消息机制是什么?
android的消息机制主要是指Handler的运行机制。
handler 是什么?
我们说,handler是android给我们提供用来更新UI的一套机制,也是一套消息的处理机制,可以通过他来发消息 也可以用他来处理消息
为什么使用handler
android设计的时候就封装了一套这样的消息创建 传递 处理机制 否则就会抛出异常的。主要原因就是为了解决在子线程中无法访问UI的矛盾。
消息队列
消息队列在Android中指的是MessageQueue.其中主要包含两个操作:插入和读取。读取操作本身会伴随着删除操作(对应的方法为:enqueueMessage和N=next)。
尽管MessageQueue叫做消息队列,但是它的内部实现并不是用的队列,实际上是通过一个单链表的数据结构来维护消息列表。
扩展:
enqueueMessage主要操作就是单链表的插入操作。
next:是一个无限循环的方法,如果消息队列中没有消息,那么next方法会一直阻塞在这里。当有新消息到来时,next方法会返回这条消息并将它从单链表中移除。
Looper的工作原理
Looper在Android的消息机制中扮演者消息循环的角色,他会不停的从MessageQueue中查看是否有新的消息,如果有新的消息就会立即处理,否则一直阻塞在那里。
创建Loop的方法: Looper.prepare(); //So easy
退出Loop的方法: Looper.quit();
查阅了Looper的源码以后发现,他的工作工程比较好理解,loop方法是一个死循环,跳出死循环的方式是next方法返回null。next方法是一个阻塞操作,当没有消息时,next方法会一直阻塞在那里,导致了loop方法也一直阻塞在那里。
如果有了一条消息,Looper会处理这个消息:msg.target.dispatchMessage(msg);
这里的msg.target是发送这条消息的Handler对象,这样Hundler发送的消息最终又交给他的dispatchMessage方法来处理的。
handler的工作原理
Handler的工作主要包含消息的发送和接受过程。
Handler发送消息的过程仅仅是向消息队列中插入了一条消息,MessageQueue的next方法就会返回这条消息给Looper,Looper收到消息后就开始处理了,最终消息由Looper交给Handler处理,即Handler的dispatchMessage方法会被调用,这时Handler就进入了处理消息的阶段。
handler的用法
//第一种用法
public class MainActivity extends AppCompatActivity {
private TextView textView;
private Handler handler=new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView= (TextView) findViewById(R.id.textview);
//通过handler来更新UI
handler.post(new Runnable() {
@Override
public void run() {
textView.setText("你是我的小苹果");
}
});
}
}
//第二种用法 是一个有延时的Handler
handler.postDelayed(Runnable ,long)
handler.postDelayed(mRunnable,1000) 设置handler的延期时间
//第三种用法 handlerMessage
handlerMessage
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
// handler.sendMessage(message); 方法来发送
发送Message的时候方法
一种方法是
Message message=handler.obtainMessage();
从此获得一个message对象
第二种方法是
Message message=new Message();
message.arg1=99;
message.arg2=100;
message.obj=一个类的对象;
移除一个handler
handler.removeCallbacks(Runnable);
handler的截获
private Handler handler=new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
//当返回值为true的时候 是可以截获接受的handler的
return false;
}
});
为什么只能通过 handler更新UI
handler
封装了消息的发送 ,主要包括消息发送给谁 ,内部跟Looper进行关联
例message.arg1
looper
内部包括一个消息队列MessageQueue handler发送的消息都保留在这个对流盅
looper.Looper 方法 一个死循环 不断的从MessageQueue中取消息
messagequeue
消息队列 可以添加消息也可以处理消息
总结:
handler负责发消息
Looper负责接收Handler发送的消息 并直接把消息回传给handler自己
MessageQueue就是一个存储消息的容器
自定义线程与线程相关的Handler
class MyThread extends Thread{
public Handler handler;
@Override
public void run() {
Looper.prepare();
handler=new Handler(){
@Override
public void handleMessage(Message msg) {
Log.e("-----","我是自定义线程"+Thread.currentThread())
}
};
Looper.loop();
}
}
HandlerThread
避免空指针的问题则使用HandlerThread
private HandlerThread thread;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
//设置启动线程的名字
thread=new HandlerThread("handler thread");
thread.start();
handler=new Handler(thread.getLooper()){
@Override
public void handleMessage(Message msg) {
Log.e("-----","当前线程是"+Thread.currentThread());
}
};
handler.sendEmptyMessage(1);
}
Android中更新UI的几种方式
第一种方式 handler.post();
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
textView= (TextView) findViewById(R.id.textview1);
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
@Override
public void run() {
textView.setText("文本信息");
}
});
}
}).start();
}
第二种方式:在handlerMessa中更新UI
向handlerMessage发送一个信息
在handlerMessa中更新UI
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
textView.setText("----");
}
};
第三种:runOnUiThread
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText("----");
}
});
第四种:view.post();
textView.post(new Runnable() {
@Override
public void run() {
textView.setText("----");
}
});