目录
前言:
文章,一为温故而知新,二若是可以帮助到别人,也是我的荣幸。
因本人能力有限,若有错误之处,麻烦指出。如果觉得有可取之处,麻烦点赞支持一下。 😊
Handler的基本使用
public class MainActivity extends AppCompatActivity {
private TextView mTextView;
private final MyHandler mHandler = new MyHandler(new WeakReference<MainActivity>(this));
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = findViewById(R.id.textView);
mHandler.sendEmptyMessage(1);
}
private static class MyHandler extends Handler {
private final WeakReference<MainActivity> mReference;
public MyHandler(WeakReference<MainActivity> reference) {
super();
mReference = reference;
}
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
MainActivity activity = mReference.get();
if (activity != null) {
TextView textView = activity.mTextView;
textView.setText("just a test");
}
}
}
}
MyHandler继承Handler,并使用静态内部类,从而不持有外部类的引用,若需要在handler中使用Activity中的成员变量,则需要通过Activity的弱引用拿到成员变量。
为什么要使用弱引用?
若直接传入Activity的引用,则会使MyHandler持有Activity的引用,从而导致静态内部类失效。
为什么软引用的Handler不会被收回?
在才接触弱引用的时候,就一直很好奇,弱引用不是gc的时候就会被回收么?那么Activity和Handler之间是弱引用,岂不是只要发生gc,handler就会被收回么? 这样的话,里面的runnable应该就都处理不了,为什么网上都还建议使用弱引用?是网上的东西都错了么?
这个问题困扰的了我很久,也询问过很多人,都没有得到一个很好的答案。于是,我开始看虚拟机是如何进行内存收回的。
Java虚拟机使用的是可达性分析算法进行内存回收。可达性分析算法解释
Handler不会被回收的话,肯定是和一个gcroot之间有强引用。
猜测图型:
如何证明Handler和一个GCRoot之间有强引用呢?
上图是一张通过profile抓取的memory的截图。官方文档对Depth进行了这样的解释,从任意GC根到选定实例的最短跳数。那么depth = 0,就代表着它为GCRoot,也就是说mlooper,mQueue都是GCRoot,而Handler又持有它们的引用,所以Handler不光是和GCRoot之间有强引用连接,而且还是多个GCRoot。
那么有那些GCRoot呢?
Java语言中,可以作为GCRoots的对象有下面四种(来自深入理解Java虚拟机第三章64页):
- 虚拟机栈中引用的对象
- 方法区中的类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中JNI引用的对象
上图中的handler使用的是主线程中的Looper,于是对应的Looper是sMainLooper是一个静态变量,匹配上面的第二个。 但是这个类静态属性让我有点慌,持怀疑态度。
而mQueue对应着方法区中常量引用的对象。