问题
My static handler has a WeakReference
to my Activity
(this is to prevent the well documented memory leak issue).
I post a long delayed message and I want this message delivered to my activity (which should be in the foreground).
My concern is that on orientation change, my activity is destroyed and the handler has a reference to the old activity which should have been destroyed.
In order to get around this in my onCreate
for the activity I do this.
if(mHandler == null)
mHandler = new LoginHandler(this);
else {
mHandler.setTarget(this);
}
And my handler is declared as a static global variable:
private static LoginHandler mHandler = null;
and the implementing class is also static as below:
private static class LoginHandler extends Handler {
private WeakReference<LoginActivity> mTarget;
LoginHandler(LoginActivity target) {
mTarget = new WeakReference<LoginActivity>(target);
}
public void setTarget(LoginActivity target) {
mTarget = new WeakReference<LoginActivity>(target);
}
@Override
public void handleMessage(Message msg) {
// process incoming messages here
LoginActivity activity = mTarget.get();
switch (msg.what) {
case Constants.SUCCESS:
activity.doSomething();
break;
default:
activity.setStatusMessage("failed " + msg.obj, STATUS_TYPE_DONE);
}
}
}
What I want to know is if there is something wrong with changing the WeakReference on onCreate
or is there anything else wrong with this approach?
Thanks,
回答1:
So I wrote the following test to figure out whether I had the right idea or not and it seems that m approach is correct. In onCreate
we change the WeakReference
and the posted message will always get delivered to the activity that is in the foreground. If you change this code to always create a new Handler in onCreate
you'll notice the update messages do not get delivered.
public class MainActivity extends Activity {
private static int COUNT = 0;
static LoginHandler mHandler;
private static class LoginHandler extends Handler {
private WeakReference<MainActivity> mTarget;
LoginHandler(MainActivity target) {
mTarget = new WeakReference<MainActivity>(target);
}
public void setTarget(MainActivity target) {
mTarget.clear();
mTarget = new WeakReference<MainActivity>(target);
}
@Override
public void handleMessage(Message msg) {
// int duration = Toast.LENGTH_LONG;
// process incoming messages here
MainActivity activity = mTarget.get();
activity.update(msg.arg1);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(mHandler == null)
mHandler = new LoginHandler(this);
else
mHandler.setTarget(this);
((Button)findViewById(R.id.button)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message msg = new Message();
msg.arg1 = COUNT++;
mHandler.sendMessageDelayed(msg, 3000);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private void update(int count) {
((TextView) findViewById(R.id.hello_world)).setText("Hello World @ "+ count);
}
}
回答2:
A solution in getting away with activity's destroy-and-create life cycle, if you want to retain the active objects is to make use of the "Retent Fragments".
The idea is simple, you are telling the Android system to " retain" your fragment, when it's associated activity is being destroyed and re created. And make sure you grab the current activity's context in the fragment's onAttach() callable, so you are always updating the correct activity.
Below link has more details: http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html
来源:https://stackoverflow.com/questions/18221593/android-handler-changing-weakreference