handler机制的一个引子
在android系统当中,有一个非常重要的铁律,在UI线程之外,是不能修改UI的,在后台线程,新起一个线程,得到的数据结果是不能直接反映在UI上的。
MainThread (UI线程或主线程)和 WorkrThread (除了主线程之外的其他的线程都叫workThread,对一些可能产生阻塞的操作要放在workthread中完成)
workthread从原则上来讲是不允许操作UI的,个别控件除外(ProgressBar)
在一个应用程序当中,UI线程通常用于接收用户的界面输入以及将运算结果反馈给用户
一个问题,workThread中运算,结果无法反馈到UI,又不能把运算的过程放在主线程中,就产生了workThread和mainThread通讯的问题。
handle机制就是解决这一问题的
什么是handler,handler消息处理机制:
handler就是一个消息处理器,handler,looper(循环器),messageQueue 所构成的这样的一个系统,是android系统当中最重要的消息传递,以及消息处理机制。
handler负责把消息对象加入到消息队列当中去,looper(循环器)负责把消息对象从消息队列当中取出。handler负责放,looper负责从消息队列中往外取。
如果消息队列中没有消息对象,那么负责取出消息对象的LOOP的这行代码就会产生阻塞(处于等待的状态),looper把消息对象从消息队列中取出来之后干什么呢?
looper将会调用handler的handlerMessage方法来处理message对象
主线程中 Handler A发了一个消息,Handler B在主线程中能不能接收到这个消息呢?一个handler的实例只能接受到自己发的message的信息,
很多handler共享的是一个messageQueue,通过Message 的what的属性来进行标的,只能收到自己handler相关的message
主线程有一个Looper,是一个死循环,监听消息队列,但又不是额外的线程,但是不会阻塞主线程,Looper由系统来控制的,底层的vm来控制的
并非每个线程都有Looper的实例
handler类的主要作用有两个:
在新启动的线程中发送消息,在主线程中获取、处理消息。
每个线程只拥有一个Looper,loop方法负责读取消息队列中的消息,读到信息之后就把消息交给发送该消息的handler处理
在UI线程中,系统已经初始化了一个Looper对象,因此程序直接创建handler即可,然后通过handler发送处理消息
程序员自己启动的子线程,程序员需要自己创建一个Looper对象,用prepare方法创建looper对象。
示例1(从workThread向mainThread发消息)
public class MainActivity extends Activity {
private TextView textView;
private Button button;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.textviewId);
button = (Button)findViewById(R.id.buttonId);
button.setOnClickListener(new ButtonListener());
handler = new MyHandler();
}
class ButtonListener implements OnClickListener {
@Override
public void onClick(View v) {
Thread thread = new NetWorkThread();
thread.start();
}
}
class NetWorkThread extends Thread {
@Override
public void run() {
try {
Thread.sleep( 2 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String string = "从网络测获取的数据";
Message msgMessage = handler.obtainMessage();
msgMessage.obj = string;
//sendmessage方法无论在主线程中还是workthread中都是可以发送的
handler.sendMessage(msgMessage);
}
}
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
String string = (String)msg.obj;
//在主线程中就可以随意的操作UI了
textView.setText(string);
}
}
}
示例2(从mainThread向workThread发消息,在workThread中生成handler对象)
public class MainActivity extends Activity {
private Handler handler;
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button)findViewById(R.id.buttonId);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message msg = handler.obtainMessage();
handler.sendMessage(msg);
}
});
WorkerThread wtThread = new WorkerThread();
wtThread.start();
}
class WorkerThread extends Thread {
@Override
public void run() {
//准备Looper对象
Looper.prepare();
//在workThread当中生成一个handler对象
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
System.out.println("收到了消息对象");
}
};
//调用Loop()方法之后,Looper对象不断的从消息队列当中取出消息对象,然后调用handler的handleMessage方法
//处理消息对象,如果消息队列当中没有消息对象,则线程阻塞
Looper.loop();
}
}
LOOPER是由系统控制的,底层实现的,不阻塞主线程
HandlerThread类有Looper对象,不需要prepare
}