8 Replies Latest reply on Mar 31, 2015 5:44 AM by bcd57e93-7e23-418b-a7ed-9ddb8ed95067

    Ruby thread on Android with rhodes 5.0.30




      I saw several old discussions about the impossibility of using the ruby threads on Android with rhodes ("JNIEnv is not set for this thread" when using Threads, Lazy loading and threading etc...). Is that issue fixed in the new versions of rhodes? If not, is there a workaround? I need to launch a server socket in a separate thread which will listen for client connexion so i don't see how to do that without using thread... It works well on IOS & Windows but with Android i have the famous message "JNIEnv is not set for this thread!!!". Note that i get this error message when i'm trying to read a file in this separate thread.


      Thanks in advance!



        • Re: Ruby thread on Android with rhodes 5.0.30
          Jon Tara

          Good to know at least it works on Windows too! (Do you mean Windows desktop, though, CE, Mobile, or Windows Phone?)

          • Re: Ruby thread on Android with rhodes 5.0.30
            Jon Tara

            Are you writing your own code from scratch, and is it fairly simple? My own application was XMPP messaging and I used a large existing Gem (XMPP4R) so I don't have the option below. So, no practical work-around for me, I had to use a thread and so it can't work on Android.


            If you are writing your own code, though, Ruby IO has support for non-blocking read. You will have to periodically poll. You can easily do that with a timer callback. You will get (and should catch) an exception if there is nothing to read.


            You could poll pretty often, since it's going to do almost no work if there's nothing to receive. It will check the socket, find nothing, and schedule the next timer callback.

              • Re: Re: Ruby thread on Android with rhodes 5.0.30

                Hi Jon,


                Thank you for your answer! You're right maybe i can try to use the combination of Timer and non-blocking socket to get something which cover my needs. But it's really inconvenient compared to the facility of using threads... After a deeper analyse, it seems that the root cause of this problem is trying to open a file in a thread on android. I've tried the following code :


                def test_thread_file
                      Rho::Log.info("Start thread", "DEV")
                      Rho::Log.info("Try to open file", "DEV")
                      file = File.new(File.join(Rho::Application.publicFolder, "css/android.css"))
                      Rho::Log.info("Try to open file - OK", "DEV")
                      Rho::Log.info("Try to read file", "DEV")
                      read = file.read()
                      Rho::Log.info("Try to read file - OK", "DEV")
                      Rho::Log.info("Data file : #{read}", "DEV")
                      Rho::Log.info("The End", "DEV")


                And the error occured on line 6 (during the File.new). But if I execute the same code without using a separate thread, it works well.

                Any idea of what is going on?






                  • Re: Ruby thread on Android with rhodes 5.0.30
                    Jon Tara

                    I don't think there is any easy fix. Rhodes needs to be fixed.


                    Rhodes uses the JNI (Java Native Interface) to call C/C++ code both in Rhodes and in the underlying Linux OS. This is essential, for example, to support standard Ruby I/O and networking libraries, which use the underlying OS. (In this case Linux - for iOS, BSD.)


                    You need a JNIEnv for each thread, but Rhodes doesn't provide a new one when you create a Ruby thread. If you call any code that will use the JNI, then it will fail.


                    file.read is going to have the same problem as networking functions for this reason.


                    This might help explain:


                    JNI Tips | Android Developers


                    You might actually be able to use threads on Android in some limited ways. For example, perhaps to perform some computation. So long as you stick to Ruby code. (e.g. don't try to do it in a native extension using some C code...) (But of course, if you were writing a native extension, it would not be difficult then to just use a native thread inside the extension.).