Quick question: I have been using frameworks that spawn worker threads to perform asynchronous tasks, a good example is Retrofit. Within the success/failure sections, I may pop up a Dialog box which would need to be on the UI thread. I have been accessing the underlying
Activity/UI thread in this fashion within the success/failure sections of Retrofit:
Dialog dialog = new Dialog(LoginActivity.this, R.style.ThemeDialogCustom);
This works well 99.9% of the time but every once in a while, I receive the following error when creating a Dialog box:
android.view.WindowManager$BadTokenException
LoginActivity.java line 343 in LoginActivity$6.success()
Unable to add window -- token android.os.BinderProxy#41662138 is not valid;
is your activity running?
So, is my approach the most stable way to access the Activity context/UI thread from a worker thread or do I need a different approach?
If you work with threads and not using Asynctasks, always run everything that changes UI in runOnUIThread like this
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
//change UI
}
});
The more generic way to do it is this, which is pretty much the same
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
//change UI
}
})
See here the minimal difference between runOnUIThread and MainLooper
If you want to check if you are on the main/ui thread
if(Thread.currentThread() == Looper.getMainLooper().getThread()) {
//you are on the main thread
}
AFAIK, there is nothing wrong with the approach you are using. The problem is occurring because the by the time the worker thread finishes and you are trying to show the dialog, the instance of the Activity has finished. So, the crash is totally dependent on the amount of time it takes for the thread to finish. And it seems that in your case, the thread mostly finishes when the Activity is still active; hence you don't get the error is most cases.
What you need to do is to check if the Activity is still running before trying to show the Dialog. One of the simplest ways would be to
if(!((Activity) LoginActivity.this).isFinishing())
{
//safe to show your dialog
}
Related
This is not the problem about being able to call a method in the main/UI thread but being able to do so instantaneously.
It is my knowledge that you are not normally allowed to interact with the UI thread directly because of the UI responsive requirements. It would make sense then to have a system in place to queue the requests you have for the main thread and we do have that system with the looper, handler, etc.
Here is what I did:
I did some task in the background thread and I want to intimate the main thread as soon as a condition gets satisfied(I created a listener for it) and I use the response handler to post it..something like this:
if(mNoOfPendingRequests >= mNoOfRequestsConsideredEnough){
mShouldFlagEnoughRequestsAtATime = true;
Log.i("ThumbnailDownloader: ","Enough Requests Queued");
//Now inform about this to PhotoGallery right now
mResponseHandler.postAtFrontOfQueue(new Runnable() {
public void run() {
mEnoughRequestsListener.onEnoughRequestsQueued(mShouldFlagEnoughRequestsAtATime);
}
});
}
else{
mShouldFlagEnoughRequestsAtATime = false;
mEnoughRequestsListener.onEnoughRequestsQueued(mShouldFlagEnoughRequestsAtATime);
}
If I don't inform the PhotoGallery about the enough requests sent already, it would continue to send more and more requests and app becomes unresponsive.
Also, the requests are queued and are executed later resulting in too many requests.
My question is therefore:
Is there a way to call a method/inform in UI thread from a background thread almost instantaneously?
You can run things on UI thread doing this:
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// put your code here :)
}
});
Is there a way to call a method/inform in UI thread from a background thread almost instantaneously?
Not really. Your postAtFrontOfQueue() is about as close as you can get, and as the boldface note mentions in the docs, "This method is only for use in very special circumstances -- it can easily starve the message queue, cause ordering problems, or have other unexpected side-effects."
If I don't inform the PhotoGallery about the enough requests sent already, it would continue to send more and more requests and app becomes unresponsive. Also, the requests are queued and are executed later resulting in too many requests.
Have more smarts in your queue, to know when to throttle back request processing based upon whatever your "enough" algorithm is.
This method works like a charm unless you already have lots of events in your events queue.
activity.runOnUiThread(new Runnable() {
public void run() {
// call your method here
}
});
Yes, you can call using activity context
runOnUiThread() and pass runnable object and write code inside run() method.
It is not clear from your code, what onEnoughRequestsQueued does. If all it is doing is telling the posting thread that it should stop sending requests, then you can probably accomplish the same thing with a simple volatile boolean
If the thread enqueuing requests stops doing so, when the variable is true, and the background thread sets it true, and the variable is volatile you should be good.
I've got this piece of code:
public void updateOptionLists() {
Log.d("UI", "Called update");
if (updating){
return;
}
updating = true;
runOnUiThread(
new Runnable() {
#Override
public void run() {
updating = false;
updateOptionList();
scrollToLastTapped();
Log.d("UI","Updating");
}
});
Log.d("UI", "Posted update");
}
What I'd expect from logcat would be something like this:
Called update
Posted update
Updating
As far as I know runOnUi should be asynchronous, right? And considering that the functions called alter the views, which takes a while, this should be running asynchronous. Right?
So I look at my logcat:
Called update
Updating
Posted update
Why does this happen? And how do I make sure this runs asynchronous?
runOnUiThread will execute your code on the main thread, which (in this example) also appears to be where it's called from. This explains the ordering of the log statements you see - all code is executing on a single thread, so is synchronous per the documentation (my emphasis):
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.
runOnUiThread is typically used to execute code on the main thread from a different (i.e. background thread). The use of this separate background thread is what will make a task asynchronous. Calling back to the UI thread at the end of that task is required if you want to modify UI with the results of your background thread calculations.
Android provides several mechanisms for doing work on a background thread and then posting back to the main thread (not all use runOnUiThread explicitly for the latter operation). Good things to read up on include Thread, Handler, AsyncTask, Service, etc.
As far as I know runOnUi should be asynchronous, right?
runOnUiThread, as the name states, runs on UI thread, which is a main thread of an application. It runs synchronously with other code running within that thread and asynchronously with code in other threads.
The word 'asynchronous' has no meaning without a context: some code can run asynchronously with other parts of the code, which means these parts of the code run in different threads. Saying that something 'should be asynchronous' makes no sense without this kind of context.
is updateOptionLists running on the UI Thread?
If this is the case, i would expect this behavior to be ok.
In a normal case you use runOnUiThread from a background thread to come again to the Ui Thread..
Because you call upadetOptionLists() on ui prosess, upadetOptionLists() and runUiThread() both run in the same thread.
To separte theam you need run content in other new thread as following
public void updateOptionLists() {
new Thread(new Runnable() {
#Override
public void run() {
Log.d("UI", "Called update");
if (updating){
return;
}
updating = true;
runOnUiThread(
new Runnable() {
#Override
public void run() {
updating = false;
updateOptionList();
scrollToLastTapped();
Log.d("UI","Updating");
}
});
Log.d("UI", "Posted update");
}
}).start();
}
For accessing the view, you must be in the UI Thread (the main one). So, runOnUiThread will be executed on it.
You must do the long work in an other thread and only call runOnUiThread for little thing like changing a color or a text but not to calculating it.
From the documentation:
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.
http://developer.android.com/reference/android/app/Activity.html#runOnUiThread(java.lang.Runnable)
Multi Threaded Programming: Theory vs Actual
Puppy Photos Explain is the Best pic.twitter.com/adFy17MTTI— Cian Ó Maidín (#Cianomaidin) 6. april 2015
But joke aside.
If you want to test how the threads work in correlation, try:
runOnUiThread(
new Runnable() {
#Override
public void run() {
updating = false;
updateOptionList();
scrollToLastTapped();
Thread.sleep(100);
Log.d("UI","Updating");
}
});
I have two JNI native methods that callback Java methods in my UI.
1) Display progress..
2) Dismiss progress
Both of the above calls are definitely in sequence. They both call Java methods that create new runnables as follows:
m_Activity.runOnUiThread( new Runnable()
{
#Override
public void run()
{
DisplayProgressUpdate( m_ProgressPercent );
}
} );
--
m_Activity.runOnUiThread( new Runnable()
{
#Override
public void run()
{
m_Progress.dismiss();
}
} );
What I am seeing is that the dismiss runnable is happening before the progress update runnable completes. I would have thought that because they were called in sequence and because they are both being requested on the same (UI) thread that they would occur in sequence as well. Is this not the case?
Is this why I should be using something such as a Handler to synchronise/sequence these calls?
EDIT: OK, I implemented a Handler and still observed the same behaviour. It was actually my debug that confused me. It looked as though the Dismiss Java code was happening before the progress update had completed, but what it was in fact was the Java debug printing as soon as JNI called the Java method which did the posting to the handler - not the actual runnable thread itself. So.. tajonn07 was right in a way - the dialog box was closing before I had a chance to see it and my debug lead me astray. Thanks for helping guys.
I suspect that what you're seeing isn't the dismiss being executed first, but instead it's being executed so quickly after the display that it doesn't even show.
I would suggest using a handler. But even with a handler, if it's in your UI thread, it will freeze your screen.
It's a bit messy, but you could drop both those blocks of code inside another thread with a handler. It's not the cleanest solution but it should do the trick!
runOnUiThread is not added on queue in android , this is called immediately when it invoke.
If you want queue / sequence(ie one after another), you have to use Handler.
I have a Thread with open socket connection in a activity, I like to use the thread globaly so that I can get data from thread in other Activities. Somethink like running on the background...
Does anyone have a solution or examples for me?
Thank u.
You are looking for Service
or try this code
void runInBackground() {
new Thread(new Runnable() {
#Override
public void run() {
// DO your work here
// get the data
if (activity_is_not_in_background) {
runOnUiThread(new Runnable() {
#Override
public void run() {
//uddate UI
}
});
}
runInBackground();
}
});
}
And the third method using Async Task-- Understanding AsyncTask
If you want multiple activities to have access to this thread then I would combine Vaibs_cool's sample of running a thread (it's just a normal Thread, nothing Android specific about it) and then...
extend Application (make an entry for it in the Manifest) and put that Thread in there.
That way all your activities can talk to it.
You have two options:
Service
AsyncTask
If you want to open socket and make it opened even after Activity close use Service
On other hand if you want to open socket during Activity is running and close on Activity close then use AsyncTask
You can find example how to use AsyncTask here
From Docs:
Network operations can involve unpredictable delays. To prevent this from causing a poor user experience, always perform network operations on a separate thread from the UI. The AsyncTask class provides one of the simplest ways to fire off a new task from the UI thread.
I've got a few activities. In the main activity I have a login screen, when the user presses the login button, a thread is started to show a progress dialog until the user has been authenticated. At this point i load the next activity which has several fields for the user to input data.
Here the user inputs some data and presses a button to process it. The data is passed to a new activity where the data is actually processed and displayed. This is where i create the new thread and where it's crashing when i call thread.start(); and I have no idea why this is happening.
Both activities are implementing Runnable.
I'm using the same code below to create and call thread.start() in the button press of the first activity and the onCreate method of the last one:
pd = ProgressDialog.show(search_results.this, "", "Searching...", true, false);
Thread thread = new Thread(this);
thread.start();
I'm using the same code below as well to handle the threads for both as well.
public void run() {
handler.sendEmptyMessage(0);
}
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
pd.dismiss();
}
};
Am I missing something? I don't really understand why it's crashing.
While I encourage people to use AsyncTask, it's not really needed, especially for simple things like progress/loading dialogs. That's not the problem here.
Your question and your code is confusing. I'm not sure which code goes where, on which activity, and I hope you're not leaving dialogs open between activities, trying to access them across them (it won't work, of course). Also, providing a Context to a Thread does not even compile (it's marked with errors at design time). To sum it all up, you didn't provide the Log entry. Sorry, I can't make sense of what you're doing or where the error is. We can only guess.
Below are one of the possible ways to do it with a Handler, a Runnable and a Thread. This was taken from the Developer Resource when I first learn how to use it:
1- You declare a Handler. Most people do this on the onCreate section to reuse it often:
Handler mHandler = new Handler();
2- When you need, you start a Thread:
new Thread() { public void run() {
mHandler.post(mLoadingData);
// ... do work
mHandler.post(mLoadingDataStop);
}}.start()
3- These are the Runnables that are posted to the Handler:
private final Runnable mLoadingData = new Runnable() {public void run() {
showDialog(LOADING_DIALOG); // In your case, show your custom dialog
}};
private final Runnable mLoadingDataStop = new Runnable() {public void run() {
dismissDialog(LOADING_DIALOG); // In your case, dismiss the dialog
}};
For a progress dialog, things need a bit more work (update the progress etc.), but for a loading dialog, you don't need to really mess with messages.
I had this same issue when developing for the tablet. After a certain API, I'm thinking 3.0 (sdk 11), Android enforces applications to run long running processes on a separate thread, otherwise it kills it. Logcat will confirm this.
I know you are using another thread, but that didn't work for me either. Try using AsyncTask. You can create a quick inner class that, in my opinion, is way easier than handling your own threads. AsyncTask has several functions that run on the UI thread and a couple that run on their own thread. This allows you to start a "Loading" user interface object on the user interface thread, process on the back end thread, and then when its done, it'll notify a user interface thread function.
You'll want to specifically look at override
onPreExecute()
doInBackground()
onPostExecute()