What's the difference between Activity.runOnUiThread and View.post, could someone, please, explain?
There is no real difference, except that the View.post is helpful when you don't have a direct access to the activity.
In both cases, if not on UI thread, Handler#post(Runnable) will be called behind the scenes.
As CommonsWare mentioned in the comment, there is a difference between the two - when called on Ui thread, Activity#runOnUiThread will call the run method directly, while View#post will post the runnable on the queue (e.g. call the Handler#post)
The important point IMO is that both have the same goal, and for whoever use it, there should be no difference (and the implementation may change in the future).
Another difference between Activity.runOnUiThread and view.post() is that the runnable in view.post() is called after the view is attached to a window.
Either are acceptable for most situations and for the most part they are interchangeable, but they are subtly different. The biggest difference of course is that one is available from an Activity and the other from a View. There's a lot of overlap between those, but sometimes in an Activity you will not have access to a View, and sometimes in a View you will not have access to an Activity.
One of the edge cases I've encountered with View.post I mentioned in an answer to another SO question on View.post: View.post only works from another thread when the View is attached to a window. This is rarely a problem, but can occasionally cause the Runnable to never execute, especially if you call View.post in the onCreate method of your Activity. An alternative is to use Handler.post which is what Activity.runOnUiThread and View.post use under the covers anyway.
(edited for accuracy, added "from another thread")
Another difference: post is per View; runOnUiThread is per Activity.
This means it will be possible (in the future?) to do view.getQueue / activity.getQueue and get exactly what you want without your own tracking or filtering code.
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
I just want to know what is the exact difference between using sendMessage (Message msg) and post (Runnable r).
Since both these methods are going to run in Main UI Thread even if we have Seperate Runnable.
Behind the scenes they actually call the same code. SO it isn't a big concern. SendMessage may be slightly more efficient (fewer objects used because the post will create a Message object), but by so little as to not matter at all. Using sendMessage you can add a data object as well as a runnable, but you can do that with a Runnable if you aren't using an anonymous one and pass it in via constructor.
So the long and short of it is there isn't much of one. Use whichever is more convenient (which tends to be post).
Background
I'm working on making an app better by supporting its landscape mode. One thing that I use a lot is Loaders, or more specifically AsyncTaskLoaders .
Using Loaders allow you to keep doing a background task even if the activity is being re-created due to orientation changes, as opposed to AsyncTask.
The question
I'd like to ask about the lifecycle of Loaders:
When do they get GC-ed ? Do I have to keep track of them, and if one has a bitmap inside, should I abandon it as soon as possible? Do they perhaps get GC-ed only after the activity is really destroyed (and not because of configuration changes) ?
I've noticed they have states of being stopped. Does this somehow allow me to pause them?
If #2 is true, How would I implement a loader that can be paused on some points of itself?
Can fragments also have Loaders? As I've noticed, it's only for activities.
if #4 is false, what is the recommended way to use loaders in the design pattern of navigation-drawer that replaces fragments in the container?
Can AsyncTaskLoader be interrupted like AsyncTask (or threads)? I've looked at its code and at the API, but I can't find it. I've also tried to find a workaround, but I didn't succeed.
If #6 is false, is there an alternative? For example, if I know that the loader doesn't need to load something, I could just stop it right away. One way I can think of is to set a flag (maybe AtomicBoolean, just in case) that will tell it to stop, and check this value sometimes within. Problem is that I will need to add it even inside functions that it uses, while an easier way would be to call "Thread.sleep(0)" or something like that.
Is there somewhere an explanation of the lifecycle of Loaders?
Do AsyncTaskLoaders work together, at the same time, or are they like the default, current behavior of AsyncTask, which runs only on a single thread ?
1.When do they get GC-ed ? Do I have to keep track of them, and if one has a bitmap inside, should I abandon it as soon as possible? Do they perhaps get GC-ed only after the activity is really destroyed (and not because of configuration changes) ?
Since the loader lifecycle is tied to the activity/fragment lifecycle, it is safe to assume that the garbage collection pretty much takes place at the same time. Take a look at #8 for the lifecycle of loaders. Might give you some ideas.
2.I've noticed they have states of being stopped. Does this somehow allow me to pause them?
No, as far as i know loaders do not have a onPause() per say.
3.If #2 is true, How would I implement a loader that can be paused on some points of itself?
I really have no answer to this one. Would like to know a solution to this myself.
4.Can fragments also have Loaders? As I've noticed, it's only for activities.
Of course fragments can have loaders. Just initialize the loaderManager in the onActivityCreated() method
5.if #4 is false, what is the recommended way to use loaders in the design pattern of navigation-drawer that replaces fragments in the container?
4 is true. So this question is irrelevant i guess.
6.Can AsyncTaskLoader be interrupted like AsyncTask (or threads)? I've looked at its code and at the API, but I can't find it. I've also tried to find a workaround, but I didn't succeed.
I am not sure what do you mean interrupting the loaders. But if you mean having something similar to a isCancelled() method, then there is a method called cancelLoad() on the AsyncTaskLoader. The complete flow is like cancelLoad()->cancel()->onCancelled() i think.
7.If #6 is false, is there an alternative? For example, if I know that the loader doesn't need to load something, I could just stop it right away. One way I can think of is to set a flag (maybe AtomicBoolean, just in case) that will tell it to stop, and check this value sometimes within. Problem is that I will need to add it even inside functions that it uses, while an easier way would be to call "Thread.sleep(0)" or something like that.
Irrelevant again?
9.Do AsyncTaskLoaders work together, at the same time, or are they like the default, current behavior of AsyncTask, which runs only on a single thread ?
Runs on a single thread.
8.Is there somewhere an explanation of the lifecycle of Loaders?
To my best of knowledge:
When activity/fragment is created the loader starts -> onStartLoading()
When activity becomes invisible or the fragment is detached the loader stops -> onStopLoading()
No callback when either the activity or the fragment is recreated. The LoaderManager stores the results in a local cache.
When activity/fragment is destroyed -> restartLoader() or destroyLoader() is called and the loader resets.
I hope this helps. I might be a bit off on some of the answers. I am constantly learning new things myself.
Cheers.
The following code in an AsycnTask:
#Override
protected Boolean doInBackground(View... params) {
try{
Drawable drawPhoto = DataDatero.ImageDownload(taskPhotoName);
((ImageView)params[0]).setImageDrawable(drawPhoto);
((TextView)params[1]).setText(taskItemListText);
((TextView)params[2]).setTextColor(taskColore);
((TextView)params[2]).setText(taskItemStockText);
[...]
}
Throws a CalledFromWrongThreadException , describing that:
Only the original thread that created a view hierarchy can touch its
views
This has been discussed in plenty of questions: example , another example ; and all reach the same conclusion.
But what I'm not only getting the Exception..
I call that execute from a getView in a List adapter, and the images (params[0]) are updated in the view while the exception is thrown for the text. Also, if I leave only the textview updates , the text is updated and no exception is thrown.
If I update the TextView first and the ImageView after, some text and images are updated while some images are not (that imageDownload includes a 2-3 sec network operation)
Why some of them are updated and others are not?
Notes: this was tested only with sdk 4.0, v4 support, on api 16 emulation.
I fixed it and I'm not touching the views in doInBackground
The second example is something similar... is it that the operation gets validated if onCreate is not finished?
I have come across a similar issue and asked a question here (self answered after a good bit of digging).
Essentially what it boils down to is that, contrary to what everybody thinks, you can modify UI elements from an AsyncTask execute() if those views haven't gone through a layout traversal yet. This happens asynchronously to the main flow of execution (activity lifecycle methods/callbacks), so if the View in question is created shortly before execute() is called, you can access them (meaning, the exception isn't thrown, it's of course still really bad practice and not advisable). Because execute() happens on another thread, the layout traversals (which run on the UI thread) may finish while your execute() is running, which explains why only some views may be modified and others throw the exception. It also explains why "leaving only the textview updates" (and presumably removing the ImageView updates) results in those updates "magically" working too. Since this is a timing related issue, it depends on many factors, among other things how long Drawable drawPhoto = DataDatero.ImageDownload(taskPhotoName); takes to run.
PS: I realise this is a late answer, but I think this can be useful for somebody finding this answer first, there aren't many posts dealing with issues like this.
The exception is clear enough. You can not update UI element from a thread different from the UI Thread. doInBackground executes code in a different thread
Why cant you pass the information to update the UI to the onPostExecute method? This is where the UI is intended to be updated.
When you run the execute method of your task, the doInBackground method is executed in a background thread.
And you are not allowed to modify UI from a background thread.
So, don't modify the UI in the doInBackground method.
You should do this UI stuff in onPostExecute method instead, which is guaranteed to be executed in UI thread.
I am writing a custom view that animates. Would it be better for the View to get access to it's parent Activity through casting the getContext() method to the Activity and then calling Activity.runOnUiThread or would it be better to simply use a handler and post View.invalidate messages?
Easier way - call postInvalidate method of view. This can be called on non-ui thread.
Either works. IIRC runOnUiThread() will post anyway, and the runnable will get picked up by the system looper later. So whatever is easier for you. runOnUiThread sounds easier/cleaner in this case, IMO.