下面是一个没问题的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,这样就不会执行里面的代码。当然这只是其中一种比较好的实现方式