Using a Static Handler to update the UI thread - android

When using a background thread to do work, typically you'd update the UI through a Handler.
One way to do this was defining a handler at the class level as outlined in this answer, and this answer
final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
//update UI or call class methods here
}
};
However, this construct would result in the following warning
Handler class should be static otherwise memory leaks might occur
Another way to do this was to use a static inner class as outlined in this answer, and this answer
static class MyHandler extends Handler {
private final WeakReference<Type> myWeakReference;
MyHandler(Type reference) {
myWeakReference = new WeakReference<Type>(reference);
}
#Override
public void handleMessage(Message msg)
{
//Update UI or call class methods here using weak reference
}
}
However, this form of constructor has been Deprecated according to the Android docs.
public Handler ()
This constructor is deprecated. Implicitly choosing a Looper during
Handler construction can lead to bugs where operations are silently
lost (if the Handler is not expecting new tasks and quits), crashes
(if a handler is sometimes created on a thread without a Looper
active), or race conditions, where the thread a handler is associated
with is not what the author anticipated. Instead, use an Executor or
specify the Looper explicitly, using Looper#getMainLooper, {link
android.view.View#getHandler}, or similar. If the implicit thread
local behavior is required for compatibility, use new
Handler(Looper.myLooper()) to make it clear to readers.
How should updating the UI from a Handler be done currently, and should a Handler still be used for this purpose.

As you stated the docs, it says to use Looper.getMainLooper(), just change your code to:
MyHandler(Type reference) {
super(Looper.getMainLooper());
myWeakReference = new WeakReference<Type>(reference);
}
to update the UI from the main/UI thread.

Related

Android - Define a Handler on the UI Thread

In the Training documentation on Android, Define a Handler on the UI Thread, see this code
private PhotoManager() {
...
/* Instantiates a new anonymous Handler object and defines its handleMessage() method. The Handler *must* run on the UI thread, because it moves photo Bitmaps from the PhotoTask object to the View object. To force the Handler to run on the UI thread, it's defined as part of the PhotoManager constructor. The constructor is invoked when the class is first referenced, and that happens when the View invokes startDownload. Since the View runs on the UI Thread, so does the constructor and the Handler.
*/
mHandler = new Handler(Looper.getMainLooper()) {
...
An ImageView invokes static method PhotoManager.startDownload(ImageView) passing itself. The image is downloaded on a background thread from a threadpool managed by PhotoManager.
The Handler as instantiated above sets imageView to the downloaded image bitmap.
My question is, as the constructor of PhotoManager ran on UI thread, since PhotoManager class is first referenced from the ImageView (as explained in the comment also), then why is Handler passed an instance of Main (UI thread) Looper. That is, instead of
mHandler = new Handler(Looper.getMainLooper()) {
shouldn't the following would have sufficed?
mHandler = new Handler() {
Or is it just to protect against the case where PhotoManager.startDownload() would have been called from a non-UI thread?
Yes you are correct. The Handler() default constructor uses the current thread as its main looper. In the example the Looper is specified as new Handler(Looper.getMainLooper()) which is exactly the same as calling new Handler() if and only if you are executing this code on the main thread.

What's the diference between the two ways of initializing Handler?

I am confuse about the following two ways to initialize the Handler. What's the difference ?
1. First way:
class MyFirstActivity extends Activity {
class Handler mHandler = new Handler();
...
}
2. Second way:
class MySecondActivity extends Activity {
private MyHandler mHandler;
#Oerride
protected void onCreate(Bundle bundle) {
mHandler = new MyHandler(getMainLooper());
}
private final class MyHandler extends Handler {
public MyHandler(Looper looper) {
super(looper, null, true);
}
...
}
}
Note:
I know there is the documentation:
Handler() - Default constructor associates this handler with the Looper for the current thread.
If this thread does not have a looper, this handler won't be able to receive messages so an exception is thrown.
and
Handler(Looper looper) - Use the provided Looper instead of the default one.
It means I want to know more, like
when quit, are there some special operations to do?
Which way is better (or More efficient)?
Thanks~
The Handler (Looper looper) constructor (second way) is used when creating Handler from threads, which do not have default looper, or when you want the handler to run actions on a different thread than your own.
In your "second way" example there is no need to use this type of constructor, the default one will do the same. And as the Activity constructor is invoked on the same thread as onCreate(..) method, two possible initializations ("first" and "second way") of Handler are totally equal.
UPD: make sure not to create inner Handler class.
As per documentation here
Handler() - Default constructor associates this handler with the
Looper for the current thread.
If this thread does not have a looper, this handler won't be able to receive messages so an exception is thrown.
and
Handler(Looper looper) - Use the provided Looper instead of the default one.
Here Looper is Class used to run a message loop for a thread. Check this
It's documented here. Basically second example explicitly tries to get app's main looper, while first one leaves this to the Handler's constructor:
Default constructor associates this handler with the Looper for the
current thread.
Since your both classes are Activities, there's no difference in this particular case.

Async Task OnProgressUpdate CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views

I am using an AsyncTask to download a database with a progressdialog that shows progress on the UI. Some of my users are receiving the error:
CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
As I understand it, this should only happen if you are trying to update Views off of the UI thread. Here is the error:
com...updateops.DbCreate.onProgressUpdate(DbCreate.java:70)
at com...updateops.DbCreate.onProgressUpdate(DbCreate.java:1)
and here is my code:
public class DbCreate extends AsyncTask<String, String, String>{
private static Context mCtx;
private static ProgressDialog mDialog;
public static AmazonSimpleDBClient mSDbClient;
public static AmazonS3Client mS3Client;
private static int mAppVersion;
private static boolean mCreate;
public DbCreate(Context ctx, int versionCode, boolean create) {
mCtx = ctx.getApplicationContext();
mAppVersion = versionCode;
mDialog = new ProgressDialog(ctx);
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.setMessage("Checking for server access. Please wait...");
mDialog.setCancelable(false);
mDialog.setMax(1);
mDialog.show();
mCreate = create;
}
protected void onProgressUpdate(String... name) {
if (name[0].equals("item")) {
mDialog.incrementProgressBy(1);
} else if (name[0].equals("setMax")) {
mDialog.setProgress(0);
mDialog.setMax(Integer.parseInt(name[1])); <-- This is line 70
}}
#Override
protected String doInBackground(String... arg0) {
**do stuff**
publishProgress("setMax", ""+ 3);
}
It looks to me like I am following exactly what I am supposed to do in order to avoid this error. Anyone know why it's happening?
Edit: I should also mention that this code works most of the time. I am receiving crash reports on the Developer Console.
According to the onProgressUpdate(Progress...) is invoked on the UI thread after a call to publishProgress(Progress...).
You should analyze the whole log report to check if there is any chance that your async task was created on other thread.
And if you really cannot find the root cause you can use a handler created on UI thread to workaround.
You code looks fine and in most of the cases it should work. I would suggest you to use handler. You can write a handler in UI thread and call it from onProgressUpdate(). This will completely ensure that the UI work is done in UI thread.
This will fix your issue for sure, but I dont know why you are gettin error at first hand. I have seen this kind of issue before and never got a concrete reason for it.
I had the same problem that you are describing and I fixed it by using a runOnUiThread() call against the context owned by the AsyncTask (as you also have in your example).
The following solution should absolve your issues;
#Override
protected void onProgressUpdate(final String... messages){
myActivityReference.runOnUiThread(new Runnable() {
#Override
public void run() {
// Your UI changes here.
}
});
}
It's worth noting that my AsyncTask was originally called from within a AlertDialog, which is what I believe is causing the issue to begin with.
I found the same issue on Android 2.3.x devices and here's the crash log:
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRoot.checkThread(ViewRoot.java:2934)
...
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.os.HandlerThread.run(HandlerThread.java:60)
The log indicates that onProgressUpdate and onPostExecute are executed on HandlerThread which is essentially a worker thread with a custom Looper. So that's why the crash occurs.
Therefore, in your case it is likely the internal handler of AsyncTask is bound to non main looper associated with a worker thread like HandlerThread and onUpdateProgress is processed on worker thread instead.
I found this bug appear pervasively on Android 2.3 devices. Therefore I checked the source code of AsyncTask in 2.3 and found this:
private static final InternalHandler sHandler = new InternalHandler();
private static class InternalHandler extends Handler {
#SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
#Override
public void handleMessage(Message msg) {
...
}
}
The chance is that the internal handler might be bound to a non main looper.
I also checked the latest source code of AsyncTask and saw the change:
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
...
}
The InternalHandler constructor eliminate the chance that it might be bound to a non main looper therefore onUpdateProgress behaves normal on post Android 2.3 devices.

Android's Activity.runOnUiThread is not static, so how can i use it?

For example, if I have a thread doing expensive stuff, and from that thread I want to fire runOnUiThread in the Main (activity) class. Obviously I shouldn't make an instance of my activity class (Main). So if I try
Main.runOnUiThread(mRunnable);
from my thread it gives me an error saying it's not a static method, and therefor it can't be accessed in my way. Now my understanding would be that the activity class is nearly almost accessed in a static way.
How would I do this?
(Btw: I'm doing this because I was getting CalledFromWrongThreadException, Only the original thread that created a view hierarchy can touch it's views)
Raunak has the right idea. I'll just add that you can also specify an integer in the method sendEmptyMessage as an identifier to the handler. This will allow you to create one handler that can handle all of your UI updates, e.g.
public static final int EXAMPLE = 0;
public static final int ANOTHER_EXAMPLE = 1;
private final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
switch( msg.what ){
case EXAMPLE:
//Perform action
break;
case ANOTHER_EXAMPLE;
//Perform action
break;
}
}
}
//Call to submit handler requesting the first action be called
handler.sendEmptyMessage(EXAMPLE);
Hope this helps!
You should use the Handler class. The handler class runs on the UI thread. When you finish work in your thread, call handler.sendEmptyMessage(), from where you can make the changes to your ui.
private final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
// make changes to ui
}
}
Your question doesn't really provide enough details, but from the sound of things, you're in a private inner class (Runnable?) in your activity (Main). If that is the case, you can either write:
Main.this.runOnUiThread(mRunnable);
or
runOnUiThread(mRunnable); //will see that there is no runOnUiThread in the current class and begin looking "upwards"
Also, you may want to look at AsyncTask, specifically at the onPostExecute, onPreExecute and onProgressUpdate callbacks, which run on the UI thread.
first create a runnable outside onCreate. Like this:
private Runnable myRunnable = new Runnable() {
#Override
public void run() {
//work to be done
}
};
and then call the runnable using:
runOnUiThread(myRunnable);
all of the above answers are not very correct.
1)if you want a piece of code to run on UI thread from any thread code base. you can do:
Looper.getMainLooper().post(new Runnable(...))
because Looper.getMainLooper() is a static variable and initialized in ActivityThread.
2) if your runnable code snippet is inside an activity
then you can use:
MainActivity.this.runOnUiThread(...)
For those who are looking for an easy instant solution follow the simple steps
Make a reference of your class before your onCreate() method
MyClass obj;
Initialize it in you onCreate() method
obj = MyClass.this;
Call runOnUiThread()
obj.runOnUiThread(new Runnable() {
public void run() {
//perform your UI tasks here
}
});
Hope it helps.

How/when is a Handler garbage collected?

Inside a class of mine I have the following code:
mHandler = createHandler();
private Handler createHandler() {
return new Handler() {
public void handleMessage (Message msg) {
update();
if (!paused) {
sendEmptyMessageDelayed(0, 300);
}
}
};
}
The documentation says:
http://developer.android.com/reference/android/os/Handler.html
Each Handler instance is associated with a single thread and that thread's message queue
So if I understood correctly the Handler is not garbage collected as long as the application thread is running, is that correct?
In my specific example since the Handler is an anonymous inner class it has an implicit reference to the enclosing Object and the whole hierarchy of objects that is pointed by it. This looks to me like a recipe for memory leaking.
Btw, I can make the Handler stop sending messages(that's why I have the if (!paused)) but this won't make it be GCed, right?
So is there a way to remove the Handler from the message queue and get it to be GCed?
An examination of the Handler source reveals more details.
Here is some debug code from the Handler() constructor that was added by Romain Guy:
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
The warning is clear: Don't declare your Handler subclass as an inner class.
The Handler's looper is obtained from a static ThreadLocal instance:
mLooper = Looper.myLooper();
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
Anatomy of the leak:
The main app thread retains the Looper and its MessageQueue, the Messages in the queue retain a link to their target Handler, and the Handler -- unless it is a static nested class with a WeakReference to your Activity -- will retain your Activity and its views.
You could instead try to plug this leak by cleaning up your messages:
handler.removeMessages(what);
but this is easier said than done.
Also see On Memory Leaks in Java and in Android
In my specific example since the Handler is an anonymous inner class it has an implicit reference to the enclosing Object and the whole hierarchy of objects that is pointed by it.
You could reduce the impact of the potential leak to almost nothing by using a static nested class instead of an anonymous inner class.
No, stop sending message doesn't make GC work. As the doc points out, it bounds to the thread which creating it. If thread is running, the handler won't be recycled by GC.
Why do you think this could cause memory leaking? What do you mean by "implicit reference to the enclosing Object"?

Categories

Resources