基本的原理就是,内部类 ( 包括匿名内部类 ) 不管有无调用,实际上会持有外部类对象的引用。比如下面的代码 C 类可以取得外部类的变量值。
public class InnerTest {
private String mContent = "hi";
class B {
private String mContent = "hi, B";
class C {
public void test() {
System.out.println(InnerTest.this.mContent);
System.out.println(B.this.mContent);
}
}
}
public static void main(String[] args) {
new InnerTest().new B().new C().test();
}
}
我们来看看会造成 Handler leak 的代码,如下:
public class MemLeakActivity extends Activity {
...
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
...
}
}
}
所以当我们的内部类 IncomingHandler 发出 Message 后, 根据
Android 异步消息処理机制,Message 会持有 Handler 对象引用,而上面的代码,会持有外部类对象,也就是 MemLeakActivity 对象的引用,导致即使在此 Activity 在调用完 onDestroy( )后,只要 Looper 还没有処理完这个 Message( 比如说这个 Message 是设定为延迟十分钟后再処理),MemLeakActivity 的对象便无法被回收,占用了内存实际上却没有作用,便造成了 Handler Leak 内存泄漏。
解决方法:
使用静态(内部)类 + 弱引用( WeakReference )避免 Activity 被 Message 强引用而无法回收。
public class BaseHandler extends Handler {
WeakReference<Callback> mTarget = null;
public BaseHandler(Callback cb) {
mTarget = new WeakReference<>(cb);
}
public interface Callback {
boolean handleMessage(Message msg);
}
@Override
public void handleMessage(Message msg) {
Callback handler = mTarget.get();
if (handler != null) {
handler.handleMessage(msg);
}
}
}
使用方式
public class HandlerDemoActivity extends Activity implements BaseHandler.Callback, View.OnClickListener{
private BaseHandler mHandler;
private final static int MSG_TEST = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_handler_demo);
mHandler = new BaseHandler(this);
TextView tv = (TextView) findViewById(R.id.tv);
tv.setOnClickListener(this);
}
@Override
public boolean handleMessage(Message msg) {
final int what = msg.what;
if(what == MSG_TEST) {
Toast.makeText(this, "TEST", Toast.LENGTH_LONG).show();
}
return true;
}
@Override
public void onClick(View v) {
mHandler.sendEmptyMessage(MSG_TEST);
}
}
Github 范例相关参考文章
refs: http://stackoverflow.com/questions/11407943/this-handler-class-should-be-static-or-leaks-might-occur-incominghandler