TLDR: I'm using JNI to call into my custom JAR from Unity C#. But the android library says it's running on the "UnityMain" thread, while the actual ui thread for the activity is called "main". What is the difference between the two?
Details:
This is a problem for me since I get the error "Can't create handler inside thread that has not called Looper.prepare()". Here's the output I get when printing the two threads from Java:
/// Java Output
Current Thread: Thread[UnityMain,5,main]
MainLooper Thread: Thread[main,5,main]
To resolve this, I'm running the JNI calls using the Activity.runOnUiThread method:
/// Unity C# Code
activityObj.Call("runOnUiThread", new AndroidJavaRunnable(() => {
// JNI calls and other stuff
}
Now I get the following output when printing the two threads from Java:
/// Java Output
Current Thread: Thread[main,5,main]
MainLooper Thread: Thread[main,5,main]
Only problem now is that I can't make Unity Coroutine or Invoke calls from the "main" thread (i.e. inside the "runOnUiThread" callback). I get the following Unity error:
/// Unity C# Output
E/Unity (21048): Invoke can only be called from the main thread.
E/Unity (21048): Constructors and field initializers will be executed from the loading thread when loading a scene.
E/Unity (21048): Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
So what is the difference between the "UnityMain" and "main" threads? And why is the Java "main" thread different from that of Unity?
Unity runs its own thread to handle its processing. It doesn't usurp the Android main thread created by the Android OS when launching the app. Typically when you write a traditional Android app there is only one main thread, and everything that deals with the UI must run on the main thread. To use a second "main" thread, was a design choice made by Unity, probably so it can do whatever it wants without messing with the apps Android main thread. If you want to do anything in the Android UI outside of Unity you'll need to have your code run on the main thread. You can do this from anywhere using the below snippet:
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Log.d("MAIN", "Thread? " + Thread.currentThread());
}
});
If the Android/Java code you are calling into has access to the Application context or an Activity context you can use runOnUiThread as well.
Related
i am new on xamarin android apps.I want to build an app and i have read that connections with database or the execution of queries should happen asynchronously from the main thread otherwise the UIthread will may collapse.I have found 2 ways to do that:
First way:
WebClient client = new WebClient();
Uri uri = new Uri("http://192.168.2.8/CreateUsername.php");
NameValueCollection parameters = new NameValueCollection();
parameters.Add("Name", txtname.text);
client.UploadValuesCompleted += Client_UploadValuesCompleted;
client.UploadValuesAsync(uri,parameters); ---> is this gonna create a new thread and run asynchronously???
(here i found the first way: https://www.youtube.com/watch?v=jF3D__ibrx8 )
SecondWay:
https://developer.xamarin.com/recipes/android/web_services/consuming_services/call_a_rest_web_service/
Both ways are correct?both of ways are gonna create a new thread and run asynchronously?Thanks!!!!
Both examples are ok but I'd usually trust the official documentation by Xamarin first. What might confuse you with the first example is the lack of await keyword when calling the UploadValuesAsync method. Here's what actually happens:
Call to UploadValuesAsync is made from the UI thread.
UI thread blocks until the method returns because it's running synchronously.
However, the method returns very quickly because it launches the upload process asynchronously on another thread internally and doesn't wait for the process to complete.
When the whole upload process is finished, Client_UploadValuesCompleted will be called.
As you can see on the WebClient.UploadValuesAsync page on MSDN, it states that:
These methods do not block the calling thread.
Also, when looking at the source code for UploadValuesAsync, you'll notice the following attribute defined on top:
[HostProtection(ExternalThreading=true)]
which means the following:
Code that exposes external threading creates or manipulates threads other than its own, which might be harmful to the host.
To sum it up, the upload process is handled on another background thread but otherwise, your code will run synchronously. There's a bit more asynchronicity going on in Xamarin's sample.
I'm pretty new to jni.
I need to invoke a native method from java code, which should perform a time-consuming operation asynchronously (in another thread), and at the end it should invoke a java callback. However I need this callback to be invoked in the same java thread that originated the operation. That is, the java application should be single-threaded, and all callbacks should be invoked in the context of this thread.
I've read tutorials on callback invocations, the stuff about keeping global refs to the object, getting the appropriate methodid and invoking it.
I've also found stuff about how to call a java method from another thread (AttachCurrentThread), however this is not what I need. I need to make the java call within the originating thread, so the question is how do I switch to that thread?
For instance, in Win32 I'd use something like PostMessage/PostThreadMessage to invoke a code in the specified thread, assuming it runs the message-loop. There're also alternatives like QueueUserAPC which is applicable if the thread waits for events in an alertable state.
So, what are the options at my disposal? Is there a jni method for posting execution of a java method in the specified thread? Or perhaps a linux equivalent of PostThreadMessage? I can also think about workarounds within the java code, but prefer to solve this on the native side.
Thanks in advance.
Please see a relevant recent discussion: How do I post code to be run on the Android main thread from a separate thread in C++?. The most interesting part is this thread in android-ndk group from 2012.
TL;NR: from JNI_OnLoad() or other call that happens early enough, and comes from the UI thread, you call
pipe2(messagePipe, O_NONBLOCK | O_CLOEXEC);
ALooper_addFd(ALooper_forThread(), messagePipe[0], 0, ALOOPER_EVENT_INPUT, handler, data);
Elsewhere you define a simple handler function:
int handler(int fd, int, void* pHandler) {
int what = 0;
read(fd, &what, sizeof(what));
static_cast<MyHandler *>(pHandler)->handle(what));
return 1;
}
Now the native version of Handler.sendEmptyMessage(), and a close analog of CWinThread::PostThreadMessage() (without wParam and lParam), could then be as simple as
MyHandler::sendEmptyMessage(int what) {
write(messagePipe[1], &what, sizeof(what));
}
As i read in the android annotations for thread document
We have four types of thread,
#MainThread
#UiThread
#WorkerThread
#BinderThread
What is differences?
The differences is:
#MainThread, first Thread run when app started,
#UiThread, run from MainThread for UI works,
#WorkerThread, that run when programmer define a thread
#BinderThread,uses for something like query()/insert()/update()/delete() methods in ContentProvider.
I have one library which is linked to my Android application, I am calling some functions of that lib from my android Activity and those function calls are time taking (4-5 seconds).
I can not call this functions in separate thread (using AsyncTaks, Threads) because of the library limitations.
When i call these function and when these function are in process at the same time my UI does not respond to user activities and to avoid that i am displaying processing screen and if in-between user performs any key actions then i get ANR error.
How can i avoid this ANR or there is no way i can avoid it other that putting time taking process in separate thread?
Thanks.
better read this article and watch google IO videos (like this one and this one) .
if you don't have time for this , simply remember this simple rule:
long operations (like internet operations , DB operations , IO operations , and anything that could simply take longer than 5 seconds ) could cause ANR if they occur on the UI thread.
for updating the UI , you must use the UI thread . if you need to do it after/during the long operation , use classes such as : Handler , AsyncTask , View.post , Activity.runOnUiThread .
Who wrote the library and what is it? The only reason I can think of as to why it would throw an exception is that it is trying to update the UI from the thread that you call it on. If the library methods take 4-5 seconds to compete then they should provide you with a callback mechanism that you can update your UI on the UI thread.
new Thread("Slow native process") {
public void run() {
// call your "time taking process", passing in the callback (you could implement in the outer class and pass "this"...)
callNativeMethod( args, new YourCallbackInterface() {
public void onResult( String response ) {
activity.runOnUiThread( new Runnable() {
// update UI
});
}
});
}
}.start();
I have a client software (on Android) that listens to incoming messages. The messages are received in a while loop that waits for messages to come. When a message is found, it updates the GUI. [Since in Android, GUI can not be updated directly ] A thread is called to do this. My problem is, if there are many messages, results in many threads! And it creates a clumsy situation. My abstract code is,
My_Client()
{
send_text_function() // My question is not about it
in_a_thread_Call_receive_from_others_function() [see 1]
}
receiving_funtion() // [this function is mentioned above as (see 1), called in a thread]
{
while( waiting for new message)
{
>>A new message found >> create a thread to update the GUI. // << Here is my question. see 2
//android.os.Handler.thread type thread!
}
}
label 2: Now this thread is created each time there is a message. How can I just create one thread and keep using it again and again? Any idea?
Create a new Thread.
In the run() method of the Thread create a new Handler.
When you want to do something on the target thread, use the Handler's post() method.
You can create a Handler on the Main thread to post-back operations that update the GUI.
Also consider using AsyncTask<>.