Android开发Handler中为什么会使用到弱引用:
主要是解决Handler内存泄漏问题。什么是Handler内存泄漏?
当使用内部类(包括匿名类)来创建Handler的时候,Handler对象会隐式地持有一个外部类对象(通常是一个Activity)的引用,不然你怎么可能通过Handler来操作Activity中的View。而Handler通常会伴随着一个耗时的后台线程(例如从网络拉取图片)一起出现,这个后台线程在任务执行完毕(例如图片下载完毕)之后,通过消息机制通知Handler,然后Handler把图片更新到界面。
然而,如果用户在网络请求过程中关闭了Activity,正常情况下,Activity不再被使用,它就有可能在GC检查时被回收掉,但由于这时线程尚未执行完,而该线程持有Handler的引用(不然它怎么发消息给Handler?),这个Handler又持有Activity的引用,就导致该Activity无法被回收(即内存泄露),直到网络请求结束(例如图片下载完毕)。
如果一个内存中的对象没有任何引用的话,就说明这个对象已经不再被使用了,从而可以成为被垃圾回收的候选。不过由于垃圾回收器的运行时间不确定,可被垃圾回收的对象的实际被回收时间是不确定的。对于一个对象来说,只要有引用的存在,它就会一直存在于内存中。如果这样的对象越来越多,超出了JVM中的内存总数,JVM就会抛出OutOfMemory错误。虽然垃圾回收的具体运行是由JVM来控制的,但是开发人员仍然可以在一定程度上与垃圾回收器进行交互,其目的在于更好的帮助垃圾回收器管理好应用的内存。
以上先介绍弱引用的概念,下面讲解Handler在实际开发中的几种使用情况:
先理解概念:在Android开发中,为了UI操作是线程安全的,规定只允许UI线程更新Activity中的UI组件(如果不这样规定的话,试想一下,一个Activity中可以开启好多线程,如果这些线程都可以有权利更新UI组件,而不遵守调度机制等规则,那么界面该是有多混乱,可能前一秒TextView的内容是这样,而后一秒则变成那样)。但是在实际开发过程中,总是存在着这样的问题:有许多子线程需要对UI主线程中的组件进行操作,那么问题就出现了:怎么才能保证多个线程能够并发操作UI组件,并且能够保证线程安全呢?这就需要使用到Handler消息机制了,即工作线程需要更新UI组件的时候,通过Handler通知主线程,从而在主线程中执行UI操作。
总结起来使用Handler的原因就是:将工作线程需操作UI
的消息 传递 到主线程,使得主线程可根据工作线程的需求 更新UI
,从而避免线程操作不安全的问题。
1,下面使用post()方法来执行Handler操作:
public class MainActivity extends AppCompatActivity {
private Button button;
private TextView textView;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=findViewById(R.id.button_1);
textView=findViewById(R.id.text_view);
handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handler.post(new Runnable() {
@Override
public void run() {
textView.setText("这是使用post方式改变组件");
}
});
}
});
}
}
2,使用runOnUiThread:(在主线程)
public class MainActivity extends AppCompatActivity {
private Button button;
private TextView textView;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=findViewById(R.id.button_1);
textView=findViewById(R.id.text_view);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText("这是使用runOnUiThread来改变");
}
});
}
});
}
}
在子线程
public class MainActivity extends AppCompatActivity {
private Button button;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=findViewById(R.id.button_1);
textView=findViewById(R.id.text_view);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText("这是使用runOnUiThread来改变");
}
});
}
}).start();
}
});
}
}
3,发送延迟消息,下面这个例子就是在2秒后发送消息:
public class MainActivity extends AppCompatActivity {
private Button button;
private TextView textView;
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:
textView.setText("这是使用延迟");
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=findViewById(R.id.button_1);
textView=findViewById(R.id.text_view);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
handler.sendEmptyMessageDelayed(1,2000);
}
}).start();
}
});
}
}
1,使用静态内部类来解决内存泄漏
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import java.lang.ref.WeakReference;
public class SampleActivity extends AppCompatActivity {
private final MyHandler mHandler = new MyHandler(this);
private static final Runnable sRunnable = new Runnable() {
@Override
public void run() {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler.postDelayed(sRunnable, 1000 * 60 * 10);
finish();
}
static class MyHandler extends Handler {
private final WeakReference<SampleActivity> mActivity;
public MyHandler(SampleActivity activity) {
mActivity = new WeakReference<SampleActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
SampleActivity activity = mActivity.get();
if (activity != null) {
}
}
}
}
关于android Handler为什么要使用弱引用请看下面一篇博客:https://blog.csdn.net/qq_38684229/article/details/80931865
虽然觉得自己handler掌握的差不多了,但是读完这两位大神的文章,对是觉得受益匪浅,推荐给大家。
Android Handler消息机制原理最全解读(持续补充中)https://blog.csdn.net/wsq_tomato/article/details/80301851
手把手带你分析Handler机制源码https://www.jianshu.com/p/b4d745c7ff7a
在学习Handler之前需要了解一下java弱引用,这里也有一篇博客,大家可以参考一下:
java四种引用 https://www.cnblogs.com/fengbs/p/7019687.html