首页 > 学院 > 开发设计 > 正文

正确使用Handler

2019-11-09 13:44:40
字体:
来源:转载
供稿:网友

下面是一个没问题的Handler

public class DActivity extends AppCompatActivity {//    @Inject//    D d;        Handler mHandler = new Handler(new Handler.Callback() {        @Override        public boolean handleMessage(Message message) {            return false;        }    });    @Override    PRotected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_d);//        Diiii component = DaggerDiiii.builder().ddasfadfa(new Ddasfadfa()).build();//        component.injectD(this);            }}1,当代码改成下面的时候就会出现问题

public class DActivity extends AppCompatActivity {//    @Inject//    D d;        Handler mHandler = new Handler(new Handler.Callback() {        @Override        public boolean handleMessage(Message message) {            return false;        }    });    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_d);//        Diiii component = DaggerDiiii.builder().ddasfadfa(new Ddasfadfa()).build();//        component.injectD(this);                mHandler.postDelayed(new Runnable() {            @Override            public void run() {                            }        },500*1000);    }}问题的原因在于:

当进入到这个界面后,反复的旋转屏幕,导致这个页面不断的重新绘制,同时,如果持有很多的资源的话就会造成OOM;

分析原因:

一开始进入这个界面,初始化Handler,开启延时任务,这时,屏幕旋转,该activity需要被销毁,却发现,自己有个孩子还在做延迟任务,那么母亲是肯定不能抛弃孩子的,所以,这个activity就销毁不了了,当不断的旋转屏幕时,就会有很多个activity无法销毁,如果持有很多的资源的话,那就更容易OOM了;

内部类new Handler(){}持有外部类Activity的引用

内部类new Runable(){}持有外部类Activity的引用

2,添加static(注意Handler和Runable都要加static)

public class DActivity extends AppCompatActivity {//    @Inject//    D d;        static Handler mHandler = new Handler(new Handler.Callback() {        @Override        public boolean handleMessage(Message message) {            return false;        }    });    static Runnable task = new Runnable() {        @Override        public void run() {                    }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_d);//        Diiii component = DaggerDiiii.builder().ddasfadfa(new Ddasfadfa()).build();//        component.injectD(this);                mHandler.postDelayed(task,500*1000);    }}分析:

这时Handler就不再是activity的孩子了,是静态成员变量(是属于类的,不属于这个实例了),这时activity就可以被销毁了,同时,Runable也用static修饰了;这样就不会造成OOM了。

3,但是,如果在Handler或者在Runable中有引用外部类的成员,那也会OOM

public class DActivity extends AppCompatActivity {//    @Inject//    D d;
	ImageView iv;
	TextView tv;        static Handler mHandler = new Handler(new Handler.Callback() {        @Override        public boolean handleMessage(Message message) {
	    //tv.setText(“你好”);
	    //iv.set。。。。。。            return false;        }    });    static Runnable task = new Runnable() {        @Override        public void run() {            tv.setText(“你好”);
	    iv.set。。。。。。
	    finish;//引用了this        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_d);//        Diiii component = DaggerDiiii.builder().ddasfadfa(new Ddasfadfa()).build();//        component.injectD(this);                mHandler.postDelayed(task,500*1000);    }}如上,当Runable中需要引用imageview和textview时,这时也会造成内部类持有外部类的引用;如果Handler中有引用的话,也会造成内部类持有外部类的引用,解决办法是:将tv、iv用静态static修饰,这样就不会持有其引用了;但是如果,Runable里面有tv、iv、bt等等,很多个引用呢?代码改起来就很麻烦了;这时想到,造成OOM的问题在于Activity想销毁时,这些成员变量tv、iv。。。却还在被内部类引用着;也就是说,只要activity被销毁了,就不让他执行那些逻辑;所以就有下面的代码:

publicclassMainActivity extends AppCompatActivity {

private Activity mActivity;

privatestaticfinal String TAG="stay4it";

@Override

protectedvoidonCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

init();

}

privatevoidinit(){

mActivity=this;

BetterHandler betterHandler = new BetterHandler(mActivity);

Message message=Message.obtain();

message.what=9527;

betterHandler.sendMessage(message);

betterHandler.postDelayed(new BetterRunnable(), 1000 * 20);

}

privatestaticclassBetterRunnable implements Runnable {

@Override

publicvoidrun() {

Log.i(TAG,"Runnable run()");

}

}

privatestaticclassBetterHandler extends Handler {

private WeakReference<Activity> activityWeakReference;

publicBetterHandler(Activity activity) {

activityWeakReference = new WeakReference<>(activity);

}

@Override

publicvoidhandleMessage(Message msg) {

super.handleMessage(msg);

if (activityWeakReference.get() != null) {

Log.i(TAG,"handle message");

}

}

}

}

就Activity需要用软引用WeakReference包一下,不然会造成activity回收不了;如上面的代码,当屏幕旋转后,activity销毁,activity为null,当handler执行任务时,activityWeakReference.get()为null,这样就不会执行里面的代码。当然这只是其中一种比较好的实现方式


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表