1,子线程通过sendMessage发消息。mHandler相当于成员变量。
mHandler.sendMessage(message);
2,主线程通过handleMessage接收到消息,然后更改ui。
其内部实现逻辑如下:
子线程使用handler发消息,主线程在有messQueue消息队列来接收消息,然后循环器Looper不停循环(通过源码我们可以知道looper是一个死循环),将消息传递给主线程handler,进而主线程更改ui。
具体事例代码如下:
package com.example.administrator.myhandler;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity {
private ImageView mImag;
private Handler mHandler = new Handler(){
@Override public void handleMessage(Message msg) {
//取出消息 Bitmap bitmap = (Bitmap) msg.obj;
mImag.setImageBitmap(bitmap);
}
};
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImag = (ImageView) findViewById(R.id.iv); initData();
}
private void initData() {
new Thread(new Runnable() {
@Override public void run() {
Message message = new Message();
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.b);
message.obj = bitmap; //使用handler从子线程发消息
mHandler.sendMessage(message);
} }).start();
}
}
为什么不可以子线程更改ui呢?实际上,Android是这样考虑的:
Android 中主线程也叫 UI 线程,那么从名字上我们也知道主线程主要是用来创建、更新 UI 的,而其他耗时操作,比如网络访问,或者文件处理,多媒体处理等都需要在子线程中操作,之所以在子线程中操作是为了保证 UI 的流畅程度,手机显示的刷新频率是 60Hz,也就是一秒钟刷新 60 次,每 16.67 毫秒刷新一次,为了不丢帧,那么主线程处理代码最好不要超过 16 毫秒。当子线程处理完数据后,为了防止 UI 处理逻辑的混乱,Android 只允许主线程修改 UI,那么这时候就需要 Handler 来充当子线程和主线程之间的桥梁了。
在 Android 中主线程如何给子线程发 Message?
其实可以把上面的过程逆过来就可以了:在主线程发消息,子线程中new出Handler,接收消息。道理是一样的。
总结
应用启动是从 ActivityThread 的 main 开始的,先是执行了 Looper.prepare(),该方法先是 new 了一个 Looper 对象,在私有的构造方法中又创建了 MessageQueue 作为此 Looper 对象的成员变量,Looper 对象通过 ThreadLocal 绑定 MainThread 中;
当我们创建 Handler 子类对象时,在构造方法中通过 ThreadLocal 获取绑定的 Looper 对象,并获取此 Looper 对象的成员变量 MessageQueue 作为该 Handler 对象的成员变量;
在子线程中调用上一步创建的 Handler 子类对象的 sendMesage(msg) 方法时,在该方法中将 msg 的 target 属性设置为自己本身,同时调用成员变量 MessageQueue 对象的 enqueueMessag() 方法将 msg 放入 MessageQueue 中;
主线程创建好之后,会执行 Looper.loop() 方法,该方法中获取与线程绑定的 Looper 对象,继而获取该 Looper 对象的成员变量 MessageQueue 对象,并开启一个会阻塞(不占用资源)的死循环,只要 MessageQueue 中有 msg,就会获取该 msg,并执行 msg.target.dispatchMessage(msg) 方法(msg.target 即上一步引用的 handler 对象),此方法中调用了我们第二步创建 handler 子类对象时覆写的 handleMessage() 方法。
Handler 的 软引用,避免内存泄漏:
public class MainActivity extends AppCompatActivity {
private static MyHandler myHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myHandler = new MyHandler(this);
}
private class MyHandler extends Handler{
private final WeakReference<MainActivity> mActivity;
private MyHandler(MainActivity activity){
mActivity = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(@NonNull Message msg) {
MainActivity mainActivity = mActivity.get();
if (mainActivity != null){
}
}
}
}