Android UI是线程不安全的,如果在子线程中尝试进行UI操作,程序就有可能会崩溃。解决这一问题,即创建一个Message对象,然后借助Handler发送出去,之后在Handler的handleMessage()方法中获得刚才发送的Message对象,然后在这里进行UI操作就不会再出现崩溃了。这种处理方式被称为异步消息处理线程。
一.Handler的基本使用 在主线程定义Handler
public class MainActivity extends AppCompatActivity {
public static final String TAG = MainActivity.class.getSimpleName();
private TextView texttitle = null;
/**
* 在主线程中定义Handler,并实现对应的handleMessage方法
*/
public static Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//接收消息
if (msg.what == 101) {
texttitle.setText("接收到handler消息...");
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
texttitle = (TextView) findViewById(R.id.texttitle);
texttitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@Override
public void run() {
// 在子线程中发送异步消息 通知主线程更新UI
mHandler.sendEmptyMessage(101);
}
}.start();
}
});
}
}
二.在子线程中定义Handler
主要用于进程之间通讯
2.1 直接在子线程第一handler会报错误
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();//每一个线程只能调用一次
mHandler = new Handler() {
public void handleMessage(Message msg) {
Log.i(TAG, "在子线程中定义Handler,并接收到消息。。。");
super.handleMessage(msg);
System.out.println("这个消息是从-->>" + msg.obj+"过来的,在第二个子线程当中" );
}
}}
Looper.loop();//开始轮循
}).start();
在子线程中创建的Handler是会导致程序崩溃的,提示的错误信息为 Can't create handler inside thread that has not called Looper.prepare() 。说是不能在没有调用Looper.prepare() 的线程中创建Handler,那么可以理解当我们在new Handler的时候还需要有个Looper,
2.2查看Handler代码
- public Handler() {
- if (FIND_POTENTIAL_LEAKS) {
- final Class<? extends Handler> klass = getClass();
- if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
- (klass.getModifiers() & Modifier.STATIC) == 0) {
- Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
- klass.getCanonicalName());
- }
- }
- mLooper = Looper.myLooper(); //从Looper.myLooper方法中取个looper对象
- if (mLooper == null) {
- throw new RuntimeException(
- "Can't create handler inside thread that has not called Looper.prepare()"); //如果为空则报异常
- }
- mQueue = mLooper.mQueue;
- mCallback = null;
- }
查看Looper.myLooper(); 代码
- public static final Looper myLooper() {
- return (Looper)sThreadLocal.get();
- }
- //从sThreadLocal中得到looper并返回与下边Looper.perpare中sThreadLocal.set方法想吻合
查看perpare方法代码可看到,自动创建一个Looper
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
可以看到,首先判断sThreadLocal中是否已经存在Looper了,如果还没有则创建一个新的Looper设置进去。这样也就完全解释了为什么我们要先调用Looper.prepare()方法,才能创建Handler对象。同时也可以看出每个线程中最多只会有一个Looper对象。
再创建第二个子线程
new Thread(new Runnable() {
@Override
public void run() {
Looper loop = Looper.myLooper();
Message msg = childHandler.obtainMessage();
msg.obj = "第二个线程信息";
mHandler.sendMessage(msg);
}
}).start();
这样一个线程发送消息,一个线程接收消息 完成线程之间的通讯,但是在主线程中定义Handler会默认在程序启动的时候,系统已经帮我们自动调用了Looper.prepare()方法;
只有在子线程定义Handler需要prepare
三.其他异步更新UI方法
1.Activity中的runOnUiThread()方法,代码如下所示:
- if (Thread.currentThread() != mUiThread) {
- mHandler.post(action); //不为主线程时候
- } else {
- action.run();
- }
- }
2.
然后再来看一下View中的post()方法,代码如下所示:
- Handler handler;
- if (mAttachInfo != null) {
- handler = mAttachInfo.mHandler;
- } else {
- ViewRoot.getRunQueue().post(action);
- return true;
- }
- return handler.post(action); //同样会调用handler.post();
- }
查看Handler中的post()方法代码:
- return sendMessageDelayed(getPostMessage(r), 0);
- }
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
这里调用了sendMessageDelayed()方法去发送一条消息,并且还使用了getPostMessage()方法将Runnable对象转换成了一条消息,看下这个方法的源码:
private final Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
在这个方法中将消息的callback字段的值指定为传入的Runnable对象。callback在Handler的dispatchMessage()方法中原来有做一个检查,
通过追踪可以知道就是我们定义的Handler对象,然后我们查看一下Handler类的dispatchMessage方法:
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
如果Message的callback等于null才会去调用handleMessage()方法,否则就调用handleCallback()方法。那我们快来看下handleCallback()方法中的代码吧:
message.callback.run(); //调用我们run方法
}
上边说了getPostMessage(Runnable r)方法中将我们自己的Runnble给了m.callback = r;message.callback相当于我们自己的Runnble 此时调用到了run方法。
自己的一些简单理解,诸位见笑