正确使用Handler

下面是一个没问题的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被销毁了,就不让他执行那些逻辑;所以就有下面的代码:

public class MainActivity extends AppCompatActivity {

private Activity mActivity;

private static final String TAG="stay4it";

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

init();

}

private void init(){

mActivity=this;

BetterHandler betterHandler = new BetterHandler(mActivity);

Message message=Message.obtain();

message.what=9527;

betterHandler.sendMessage(message);

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

}

private static class BetterRunnable implements Runnable {

@Override

public void run() {

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

}

}

private static class BetterHandler extends Handler {

private WeakReference<Activity> activityWeakReference;

public BetterHandler(Activity activity) {

activityWeakReference = new WeakReference<>(activity);

}

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

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

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

}

}

}

}

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值