Android-執行緒通訊設計模式-Handler訊息模型
思考問題:
1) Android中的工作執行緒獲取資料以後如何傳遞給主執行緒?
例如:
例如工作執行緒通過網路下載一張圖片,通過主執行緒將圖片更新到頁面上。
所有的耗時操作在工作執行緒,工作執行緒不能操作UI
2) Android 中主執行緒的資料如何傳遞給工作執行緒?
例如:
主執行緒將要下載的檔案的名字傳遞給工作執行緒。
記住:工作執行緒是不能更新UI的
目的:儘量不要去阻塞主執行緒,安卓中的UI執行在主執行緒。
3)SendMessage與PostMessage的區別:
前者同步,後者非同步。
SendMessage傳送訊息後會等對方處理完這個訊息後才會繼續!
PostMessage則將訊息傳送出去後就會繼續!
所以注意,不要通過PostMessage傳遞臨時變數指標,應該很可能訊息被處理時該變數已經銷燬,這時訪問就會出錯
4)handleMessage與dispatchMessage處理訊息的區別?
handleMessage處理訊息在主執行緒中
dispatchMessage處理訊息相當新開了一個執行緒中
用SendMessage替換DispatchMessage不會有問題,但是效率沒有DispatchMessage高
但是用DispatchMessage替換SendMessage卻不行!
dispatchMessage是新開了一個執行緒,而sendMessage是在主執行緒,所以更新UI的時候報錯了,這也應證了安卓只能在主執行緒更新UI這一情況了。
Android中執行緒通訊底層訊息模型
Handler給哪個執行緒發訊息,就關聯哪個執行緒的looper(雙向關聯!)
注:此章是為了個人能更好的理解Android底層機制
Android中執行緒之間進行資料傳遞通常要藉助訊息模型,在這個訊息模型中會設計到如下幾個物件:
Message(訊息物件):資料的載體
MessageQueue(訊息佇列):儲存多個訊息物件
Looper(迭代器物件):迭代訊息佇列
Handler(訊息處理物件):傳送,處理訊息
簡單案例不涉及主執行緒與工作執行緒!
class Message{
Object obj;
@Override
public String toString() {
return "Message [obj=" + obj + "]";
}
}
class MessageQueue{
private BlockingQueue<Message> queue=
new ArrayBlockingQueue<>(10);
public void put(Message msg){//放訊息
try{
queue.put(msg);
}catch(Exception e){}
}
public Message take(){//取訊息
try {
return queue.take();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
class Looper{
private MessageQueue mq;
//Looper關聯MessageQueue(MessageQueue的生命週期隨looper變化而變化,這是強聚合)
//Looper關聯Handler(通過set等方法的是低聚合)
//注:能從Looper中關聯Handler,也能從Handler中關聯looper,這是雙向關聯!
private Handler handler;
public void setHandler(Handler handler) {
this.handler = handler;
}
public MessageQueue getMq() {
return mq;
}
boolean flag=true;
public Looper(){
mq=new MessageQueue();//強聚合(組合)
}
public void loop(){
while(flag){
//迭代訊息佇列
Message msg=mq.take();
//呼叫handler方法處理訊息
handler.handleMessage(msg);
}
}
}
class Handler{
//Hanlder關聯looper(has a),獲取訊息佇列
private Looper looper;
public Handler(Looper looper){
this.looper=looper;
looper.setHandler(this);
}
//Handler與Message的關係是use a
public void sendMessage(Message msg){
//將訊息儲存到訊息佇列
looper.getMq().put(msg);
}
public void handleMessage(Message msg){
//處理訊息佇列中的訊息
System.out.println(msg);
}
}
public class TestMsg {
public static void main(String[] args) {
//訊息物件
Message msg1=new Message();
msg1.obj="helloworld";
//迭代器物件(此物件建立時會建立訊息佇列)
Looper looper=new Looper();
Handler h=new Handler(looper);
h.sendMessage(msg1);
Message msg2=new Message();
msg2.obj="gsd1504";
h.sendMessage(msg2);
looper.loop();
}
}
主執行緒與工作執行緒配合案例
class Message{
Object obj;
@Override
public String toString() {
return "Message [obj=" + obj + "]";
}
}
class MessageQueue{
private BlockingQueue<Message> queue=
new ArrayBlockingQueue<>(10);
public void put(Message msg){//放訊息
try{
queue.put(msg);
}catch(Exception e){}
}
public Message take(){//取訊息
try {
return queue.take();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
class Looper{
private MessageQueue mq;
private Handler handler;
public void setHandler(Handler handler) {
this.handler = handler;
}
public MessageQueue getMq() {
return mq;
}
boolean flag=true;
public Looper(){
mq=new MessageQueue();//強聚合(組合)
}
public void loop(){
while(flag){
//迭代訊息佇列
Message msg=mq.take();
//呼叫handler方法處理訊息
handler.handleMessage(msg);
}
}
}
class Handler{
private Looper looper;
public Handler(Looper looper){
this.looper=looper;
looper.setHandler(this);
}
public void sendMessage(Message msg){
//將訊息儲存到訊息佇列
looper.getMq().put(msg);
}
public void handleMessage(Message msg){
//處理訊息佇列中的訊息
System.out.println(msg);
}
}
public class TestMsg {
static Looper looper;
/**主執行緒給工作執行緒發訊息*/
public static void main(String[] args) {
//訊息物件
Message msg1=new Message();
msg1.obj="helloworld";
//迭代器物件(此物件建立時會建立訊息佇列)
new Thread(){
public void run() {
//looper共享資料集加鎖
synchronized (TestMsg.class) {
looper=new Looper();
TestMsg.class.notify();//類物件
}
looper.loop();
};
}.start();
synchronized (TestMsg.class) {
//Hanlder關聯那個執行緒的looper,就給哪個執行緒發訊息
//也就是主執行緒給工作執行緒發訊息
if(looper==null)try{TestMsg.class.wait();}catch(Exception e){}
Handler h=new Handler(looper);
h.sendMessage(msg1);
}
}
}
//給哪個執行緒發訊息就讓handler關聯哪個執行緒的looper
提取類封裝拿到looper案例
HandlerThread類:
public class HandlerThread extends Thread{
Looper looper;
@Override
public void run() {
synchronized (this) {
looper=new Looper();
this.notify();
}
looper.loop();
}
public Looper getLooper(){
synchronized (this) {
if(looper==null)
try{this.wait();}catch(Exception e){e.printStackTrace();}
return looper;
}
}
//一個方法執行在哪個執行緒取決於此方法在哪個執行緒被呼叫的
}
TestMsg類
class Message{
Object obj;
@Override
public String toString() {
return "Message [obj=" + obj + "]";
}
}
class MessageQueue{
private BlockingQueue<Message> queue=
new ArrayBlockingQueue<>(10);
public void put(Message msg){//放訊息
try{
queue.put(msg);
}catch(Exception e){}
}
public Message take(){//取訊息
try {
return queue.take();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
class Looper{
private MessageQueue mq;
private Handler handler;
public void setHandler(Handler handler) {
this.handler = handler;
}
public MessageQueue getMq() {
return mq;
}
boolean flag=true;
public Looper(){
mq=new MessageQueue();//強聚合(組合)
}
public void loop(){
while(flag){
//迭代訊息佇列
Message msg=mq.take();
//呼叫handler方法處理訊息
handler.handleMessage(msg);
}
}
}
class Handler{
private Looper looper;
public Handler(Looper looper){
this.looper=looper;
looper.setHandler(this);
}
public void sendMessage(Message msg){
//將訊息儲存到訊息佇列
looper.getMq().put(msg);
}
public void handleMessage(Message msg){
//處理訊息佇列中的訊息
System.out.println(msg);
}
}
public class TestMsg {
/**主執行緒給工作執行緒發訊息*/
public static void main(String[] args) {
//訊息物件
Message msg1=new Message();
msg1.obj="helloworld";
//迭代器物件(此物件建立時會建立訊息佇列)
HandlerThread ht=new HandlerThread();
ht.start();
System.out.println("start");
Handler h=new Handler(ht.getLooper());
System.out.println("h="+h);
h.sendMessage(msg1);
}
}
//給哪個執行緒發訊息就讓handler關聯哪個執行緒的looper