So I am running some threads with a CountDownLatch.
My problem is that when I call latch.await() the UI seems to hang and even UI commands that were called beforehand have no effect. e.g.
btnShare.setVisibility(View.INVISIBLE);
prgSharing.setVisibility(View.VISIBILE);
latch.await()
The first two lines have no effect on the UI.
Any idea why this is and possibly a solution? Thanks.
This is most likely because you are blocking the UI-Thread before it can render the Views again. I think you should look at AsyncTask and maybe put your wait logic in the doInBackground() method, or somehow re-think your implementation.
if the UI hangs it is because you call:
latch.await()
on the UI Thread. You have to avoid blocking call on the UI Thread since those are the cause of ANR
Related
I don't know is there any difference between CoroutineScope(Dispatchers.Main).launch and runOnUiThread, I think both will run on Main thread.
but still confusion is any difference there.?
Thanks.
Firstly, you can call runOnUiThread only in the context of Activity.
Secondly, you cannot call suspend functions from runOnUiThread, while you can do it in CoroutineScope(Dispatchers.Main).launch block.
Thirdly, runOnUiThread checks if the current ui thread is busy with other operations, if it is, the task is posted to an activity handler and will be executed when its turn will come.
They're different things using different technologies, and really it comes down to whether you're already using a coroutine or not. If so, just switch to the Main dispatcher when your code needs to be on the main thread. If you're not using coroutines, and you're explicitly using another thread, then you can use runOnUiThread to run some code on the main one. If you're not using coroutines or threads, then you don't need to call runOnUiThread at all!
There's nothing stopping you from using runOnUiThread from inside a coroutine - but it's not really the right tool for the job, you're stepping outside of coroutine handling unnecessarily. Plus like Steyrix says, you need access to something like an Activity to do it, which could mean holding a reference to one in a long-running coroutine when it should be garbage collected.
There are lots of other ways to get back on the main thread too, e.g. posting Runnables to a Handler (or through a View), or the postValue methods on LiveData. You don't have to switch dispatcher if there's something more concise and convenient available, it all depends on the situation
According to the documentation one of three options should be used for accessing the UI thread from a different thread.
These are the options:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
When should I use which? They all seem to add a Runnable to the message queue of the UI thread.
I assume postDelayed is only really useful if you want to schedule a Runnable for later and they only mentioned it because it also runs the Runnable on the UI thread.
And for extra confusion there is also AsyncTask. When should I use that now?
runOnUiThread and View.post are exactelly the same they both send a runnable object to the activity's Handler . so use whichever you like.
Regarding the AsynchTask it is not used to run on the UI thread. but after an Asynch task finishes working it calls a method called OnPostExcute on the UI thread.
There is a very great tutorial on this subject Here
If you need a mechanism for returning to the UI thread that is available from everywhere without needing a context, you can use this:
Handler handler = new Handler(Looper.getMainLooper());
handler.post(Runnable);
I always choose runOnUiThread, I think so is the best way to run something on the same UI Thread.
AsyncTasks are tricky, it's a good idea but if you want to use something new, use loaders or IntentService.
Forget about AsyncTask, it's not for running code in the UI thread, but running code in a background thread starting the AsyncTask from the UI thread.
Regarding the other options, feel free choosing any of them. If you are dealing with a View object, it is likely you are already on the UI thread. Therefore, you better keep a reference to the Activity context from the other thread and call runOnUiThread.
I will recommend you to use AsyncTasks, they were designed to do hard work in other thead (doInBackground()) and then syncronize with UI thead to push work results (onPostExecute()), and of course you can periodically update UI with work progress (onProgressUpdate()).
If you want to run more than one AsyncTask concurrently on Android Version greater than HONEYCOMB, you can use my small lubrary: Android-AsyncTask-Executor
I'm using an AsyncTask subclass for some background processing. The problem is that when I use the class with the .get() method, the ProgressDialog I specify in the onPreExecute() does not show.
I works fine if I use a callback withing the onPostExecute() method.
My first thought was that this was because the .get() waits for the process to complete but that can't be blocking the UI thread either so that's not the case.
Can anyone explain why this behavior is so and if there is a workaround for this ?? I'd really like to use the .get() method if I can.
I initially accepted the other answer but it seems to be wrong.
The .get() method will block the UI thread to wait for the result and any dialogs displayed will also be blocked. This is the expected behavior for this method.
The only alternative is to not use .get() if the background activity is for any noticable amount of time and instead use callback methods to the calling activity.
Calling AysncTask.get() on UI thread will block UI thread execution and make UI thread waiting for AysncTask.doInBackground() to finish. By doing this, you are actually sacrifice the benefit of AsycnTask, all code now are executed synchronously in UI thread and Background thread (still two thread, but UI thread now wait for background thread).
Also bear in mind that you will probably get ANR exception (blocked more than 5 seconds) by calling get() on UI thread.
If you really have to use it, call your showDialog() method before myAsyncTask.get():
showDialog();
myAsyncTask.execute();
myAsyncTask.get(); // <-- UI thread blocked and wait at this point.
dismissDialog();// <-- This line will be executed after doInBackground() finish.
Hope this helps.
This may have been hidden somewhere in the docs, but I don't remember seeing it:
Assuming everything is running on the same thread, would an activity callback, or any kind of callback for that matter, interrupt a runnable , or even some other callback, executing on the thread, or are they posted sequentially by time of occurance as messages similar to runnables?
It certainly doesn't interrupt execution, at least in the UI thread. For instance, say that you have a Button, and you place a Thread.sleep(10000) in its onClick callback. Well, as soon as you press the button the entire UI will freeze. This wouldn't happen if the onClick callback interrupted the UI thread's execution.
If you wanted to know all the answer of the question you need to use
http://developer.android.com/guide/developing/debugging/debugging-tracing.html
Depends on the Runnable.
All activity callbacks happen in the UI Thread. For example thread for onCreate is same as the thread which calls onTabSelected.
If you are started an AsyncTask, it runs in its own thread.
Try using following Log statement to check your scenario
Log.i("","Thread Id : "+Thread.currentThread().getId());
Can someone explain to me what exactly the UI thread is?
On developer.android.com it says about the runOnUiThread function
public final void runOnUiThread (Runnable action)
Since: API Level 1 Runs the specified action on the UI thread. If the
current thread is the UI thread, then the action is executed
immediately. If the current thread is not the UI thread, the action is
posted to the event queue of the UI thread.
Does the UI thread mean that this will be run everytime the activity is pushed the the background by some ui activity like incoming call or screen dimming etc.? If not, what exactly does the UI thread include ?
Thank you
The UIThread is the main thread of execution for your application. This is where most of your application code is run. All of your application components (Activities, Services, ContentProviders, BroadcastReceivers) are created in this thread, and any system calls to those components are performed in this thread.
For instance, let's say your application is a single Activity class. Then all of the lifecycle methods and most of your event handling code is run in this UIThread. These are methods like onCreate, onPause, onDestroy, onClick, etc. Additionally, this is where all of the updates to the UI are made. Anything that causes the UI to be updated or changed HAS to happen on the UI thread.
For more info on your application's Processes and Threads click here.
When you explicitly spawn a new thread to do work in the background, this code is not run on the UIThread. So what happens if this background thread needs to do something that changes the UI? This is what the runOnUiThread is for. Actually you're supposed to use a Handler (see the link below for more info on this). It provides these background threads the ability to execute code that can modify the UI. They do this by putting the UI-modifying code in a Runnable object and passing it to the runOnUiThread method.
For more info on spawning worker threads and updating the UI from them click here
I personally only use the runOnUiThread method in my Instrumentation Tests. Since the test code does not execute in the UIThread, you need to use this method to run code that modifies the UI. So, I use it to inject click and key events into my application. I can then check the state of the application to make sure the correct things happened.
For more info on testing and running code on the UIThread click here
If you execute blocking code (e.g. a Http-Request) in a separate Thread, consider using AsyncTask. Its doInBackground-Method runs on a separate Thread. AsyncTask provides you with methods onProgressUpdate and onPostExecute which are guaranteed to run on the UI thread.
If you need GUI-progress updates (e.g. via a progressbar) call publishProgress inside doInBackground. This leads to a subsequent call of onPublishProgress which is also guaranteed to run on the UI thread.
onPostExecute is automatically called after doInBackground returns.
All UI drawings etc. happen in a separate thread. Its called the UIThread. If you want to make any change to UI u must use make sure it happens in UIThread's context.
Easiest way of doing it is to make use of runOnUiThread