下面是一個沒問題的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,這樣就不會執行里面的代碼。當然這只是其中一種比較好的實現方式
新聞熱點
疑難解答