Difference between MainThread, UiThread, WorkerThread, BinderThread in Android Annotation - android

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.

Related

Will it be a good practice to call the getExternalFilesDir() method inside the Dispatchers.IO of coroutine?

In the production app we have seen few cases where getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.absolutePath method call is causing the ANR issue.
So to solve this issue can we utilize the Coroutine?
something like this
lifecycleScope.launch {
val envPath = withContext(Dispatchers.IO) { getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.absolutePath.orEmpty() }
// code, which will utilize the envPath
}
as the getExternalFilesDir() method is the part of ContextWrapper so will it create any problem if we will call it inside a different thread using the coroutine?
getExternalFilesDir uses android.os.storage.StorageManager which is Android system service. StorageManager is executed in a separate process, so it may block for a large of time.
Kotlin Coroutines: Deep Dive (Dispatchers chapter) recommends using Dispatchers.IO for code that may block a thread.
To sum up, it totally makes sense to use background thread for getExternalFilesDir.

Why use withContext() vs Async-await, isn't the goal of coroutines to achieve concurrency?

I am learning about threading and kotlin coroutines to load my UI and repository concurrently, but then "withContext()" as an alternative to async-await.
If I understood "withContext()" correctly and it executes one task after another waiting for the previous task to finish, why ever use it? Is there another concept I'm missing?
withContext is a suspending function that allows to execute a specific piece of code in a different coroutine context. It is in particular useful when you want to execute something in a different dispatcher.
For instance, you could have some code run in the default dispatcher with multiple threads, but then use a value produced by that code to update some UI in the UI thread. In that case, you're not looking for concurrency, the computation on the default dispatcher has to happen before updating the UI because you need the result:
val result = someComputation()
withContext(Dispatchers.Main) {
updateUI(result)
}
Of course, even if the computation and the update of the UI are not concurrent, their sequence can be concurrent with other pieces of code:
scope.launch(Dispatchers.Default) {
val result = someComputation()
withContext(Dispatchers.Main) {
updateUI(result)
}
}
If you need to execute concurrent things, you can use coroutine builders like launch and async. However, using async { ... } immediately followed by .await() defeats the purpose of concurrency, because the code between the async and await() calls is precisely what will run concurrently with the async's body:
val deferred = async { computeSomeValue() }
somethingConcurrentWithAsyncBody()
val result = deferred.await()
You can read more about how to organize your calls to achieve concurrency in the part of the doc about composing suspend functions.

Room Thread Management

Following Android Developer page says:
By default, all queries (#Query) must be executed on a thread other than the main thread. (You work on that later.) For operations such as inserting or deleting, if you use the provided convenience annotations, Room takes care of thread management for you.
Source: https://google-developer-training.gitbooks.io/android-developer-advanced-course-practicals/unit-6-working-with-architecture-components/lesson-14-room,-livedata,-viewmodel/14-1-a-room-livedata-viewmodel/14-1-a-room-livedata-viewmodel.html#task3intro
But this is not correct, right? Room does not automatically run insert and delete operations on a background thread. So what is this sentence supposed to mean?
It means that those room operations are thread-safe (so you don't have to take care of it if you e.g. run insert/delete operations on different background threads, source)
BY default you can't run room operation on the main thread.
You can use .allowMainThreadQueries() to run them in the main thread.
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "database")
.allowMainThreadQueries()
.build();
}
return INSTANCE;
Or you have to create an AsyncTask to perform room queries.
If you are running long-running operations using room you should use AsyncTask because running long-running operation on the main UI thread may cause your UI to block.

jni: calling a java method in its appartment thread

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));
}

Unity3D & Android: Difference between "UnityMain" and "main" threads?

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.

Categories

Resources