Handler、Thread、HandlerThread
Handler:在android中负责发送和处理消息,通过它可以实现其他支线线程与主线程之间的消息通讯。
Thread:Java进程中执行运算的最小单位,亦即执行处理机调度的基本单位。某一进程中一路单独运行的程序。
HandlerThread:一个继承自Thread的类HandlerThread,Android中没有对Java中的Thread进行任何封装,而是提供了一个继承自Thread的类HandlerThread类,这个类对Java的Thread做了很多便利的封装。
HandlerThread对象start后可以获得其Looper对象,并且使用这个Looper对象实例Handler,之后Handler就可以运行在其他线程中了。
图例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BQSWlzpJ-1637650819397)(C:\Users\wangshuo\AppData\Roaming\Typora\typora-user-images\image-20210816132407598.png)]
Andriod提供了 Handler 和 Looper 来满足线程间的通信。 Handler 先进先出原则。 Looper 类用来管理特定线程内对象之间的消息交换
Looper: 一个线程可以产生一个 Looper 对象,由它来管理此线程里的 MessageQueue( 消息队列 ) 和对消息进行循环。
Handler: 你可以构造 Handler 对象来与 Looper 沟通,以便 push 新消息到 MessageQueue 里 ; 或者接收 Looper 从 Message Queue 取出 所送来的消息。
Message Queue( 消息队列 ): 用来存放线程放入的消息。
Message:是线程间通讯的消息载体
如果一个线程要处理消息,那么它必须拥有自己的Looper
HandlerThread的使用
public class MainActivity extends AppCompatActivity {
Handler mainHandler,workHandler;
HandlerThread mHandlerThread;
TextView text;
Button button1,button2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.text1);
// 创建与主线程关联的Handler
mainHandler = new Handler();
/**
* 步骤①:创建HandlerThread实例对象
* 传入参数 = 线程名字,作用 = 标记该线程
*/
mHandlerThread = new HandlerThread("handlerThread");
/**
* 步骤②:启动线程
*/
mHandlerThread.start();
/**
* 步骤③:创建工作线程Handler & 复写handleMessage()
* 作用:关联HandlerThread的Looper对象、实现消息处理操作 & 与其他线程进行通信
* 注:消息处理操作(HandlerMessage())的执行线程 = mHandlerThread所创建的工作线程中执行
*/
workHandler = new Handler(mHandlerThread.getLooper()){
@Override
public void handleMessage(Message msg)
{
//设置了两种消息处理操作,通过msg来进行识别
switch(msg.what){
case 1:
try {
//延时操作
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 通过主线程Handler.post方法进行在主线程的UI更新操作
mainHandler.post(new Runnable() {
@Override
public void run () {
text.setText("第一次执行");
}
});
break;
case 2:
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mainHandler.post(new Runnable() {
@Override
public void run () {
text.setText("第二次执行");
}
});
break;
default:
break;
}
}
};
/**
* 步骤④:使用工作线程Handler向工作线程的消息队列发送消息
* 在工作线程中,当消息循环时取出对应消息 & 在工作线程执行相关操作
*/
button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message msg = Message.obtain();
msg.what = 1; //消息的标识
msg.obj = "A"; // 消息的存放
// 通过Handler发送消息到其绑定的消息队列
workHandler.sendMessage(msg);
}
});
button2 = (Button) findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message msg = Message.obtain();
msg.what = 2;
msg.obj = "B";
workHandler.sendMessage(msg);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandlerThread.quit(); // 退出消息循环
workHandler.removeCallbacks(null); // 防止Handler内存泄露 清空消息队列
}
}
handler过时的方法问题
为了防止内存泄露,官方要求将handler声明为静态类,静态就意味着全局,也就是说当app全部被销毁的时候内核不会忘记销毁你这个handler,可内存泄露问题解决了,却引来了另一个很棘手的问题,静态类是无法访问外部类成员的,
访问外部类的成员变量是消息处理代码非常迫切的需求,那怎么办呢?就把外部类的对象引用通过构造函数的参数传递过来不就可以访问了吗,的确是这样,但参数又被WeakReference包装了一下又是什么意思呢?
还是为了解决最初的那个问题,怕的是消息没处理完呢activity被销毁了。在我看来WeakReference就是个具有感知内部对象是否已经被销毁能力的东东。怎么感知?当然是.get()函数啦。最后还要提醒一下,要在handler消息处理中访问的activity成员要声明成public才行
handler的隐式传递Looper的构造函数不建议再使用了,上面的代码显然没有解决这个问题。google认为隐式传递的构造函数不合理,所以不建议再使用了。总之,新的代码中应该做的就是handler创建时需要手动指明往哪个Looper注册自己,也就是说创建handler对象时要给构造函数传递当前线程的Looper
public class MainActivity extends Activity {
public int m_var; //需要在消息处理中访问的成员变量,一定要声明成public
MyHandler handler = new MyHandler(Looper.myLooper(),this);//获取Looper并传递
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_auto);
}
//新的handler类要声明成静态类
static class MyHandler extends Handler{
WeakReference<MainActivity> mactivity;
//构造函数,传来的是外部类的this
public MyHandler(@NonNull Looper looper,MainActivity activity){
super(looper);//调用父类的显式指明的构造函数
mactivity = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
MainActivity nactivity=mactivity.get();
if(nactivity == null)
return ;//avtivity都没了还处理个XXX
switch (msg.what) {
case 0:
//在这里通过nactivity引用外部类
nactivity.m_var=0;
break;
default:
break;
}
}
}
Handler handler = new Handler(Looper.myLooper()) {
@Override
public void dispatchMessage(@NonNull Message msg) {
super.dispatchMessage(msg);
String message = msg.getData().getString("msg");
Log.i("test", "msg:" + message);
}
};
id dispatchMessage(@NonNull Message msg) {
super.dispatchMessage(msg);
String message = msg.getData().getString(“msg”);
Log.i(“test”, “msg:” + message);
}
};