Android Handler changing WeakReference

2020-02-23 20:55发布

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,

2条回答
地球回转人心会变
2楼-- · 2020-02-23 21:35

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);
    }

}
查看更多
啃猪蹄的小仙女
3楼-- · 2020-02-23 21:44

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

查看更多
登录 后发表回答