異步消息處理機(jī)制
主線程又被稱(chēng)為UI線程,Android是不允許在子線程中進(jìn)行UI操作的。在主線程中進(jìn)行耗時(shí)操作,程序易發(fā)生ANR錯(cuò)誤(Application Not Response)。我們必須在子線程中執(zhí)行一些耗時(shí)操作,然后根據(jù)任務(wù)的執(zhí)行結(jié)果來(lái)更新相應(yīng)的UI控件,這就用到了異步消息處理機(jī)制。
代碼實(shí)現(xiàn):
public class MainActivity extends Activity {
private static final int IMAGE = 0;
private static final int TOAST = 1;
static ImageView iv ;
static MainActivity ma;
//Handler對(duì)象設(shè)置成static,內(nèi)部變量都需要是靜態(tài)static
static Handler handler = new Handler(){
//此方法在主線程中調(diào)用,可以用來(lái)刷新UI
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case IMAGE:
//把位圖對(duì)象顯示至ImageView
iv.setImageBitmap((Bitmap) msg.obj);
break;
case TOAST:
Toast.makeText(ma, "請(qǐng)求失敗", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv = (ImageView) findViewById(R.id.iv);
ma = this;
}
/**
* 下載圖片
*/
public void click(View v){
//創(chuàng)建一個(gè)子線程,在子線程中處理網(wǎng)絡(luò)請(qǐng)求
new Thread(){
@Override
public void run() {
//確定網(wǎng)址
String path = "http://192.168.1.100:8080/home_gradient.jpg";
try {
//將網(wǎng)址封裝成一個(gè)Url對(duì)象
URL url = new URL(path);
//獲取客戶(hù)端和服務(wù)器的連接對(duì)象,此時(shí)還沒(méi)有建立連接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//對(duì)連接對(duì)象進(jìn)行初始化
connection.setRequestMethod("GET"); //設(shè)置請(qǐng)求方法
connection.setConnectTimeout(5000); //設(shè)置連接超時(shí)
//發(fā)送請(qǐng)求,與服務(wù)器建立連接
connection.connect();
if (connection.getResponseCode() == 200) { //如果響應(yīng)嗎為200,說(shuō)明請(qǐng)求成功
//獲取服務(wù)器中響應(yīng)頭中的流,流里的數(shù)據(jù)就是客戶(hù)端請(qǐng)求的數(shù)據(jù)
InputStream is = connection.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(is);
//使用Handler對(duì)象的obtainMessage方法獲取一個(gè)消息對(duì)象Message
Message message = handler.obtainMessage();
//消息對(duì)象可以攜帶數(shù)據(jù)
message.obj = bitmap;
message.what = IMAGE;
//把消息發(fā)送至主線程的消息隊(duì)列
handler.sendMessage(message);
}
else {
//彈出吐司也是一種UI的刷新,需要在主線程中運(yùn)行
Message message = handler.obtainMessage();
message.what = TOAST;
handler.sendMessage(message);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if(connection != null){
//關(guān)閉HTTP連接
connection.disconnect();
}
}
}
}.start(); //開(kāi)啟線程任務(wù)
}
}
解析異步消息處理機(jī)制
異步消息處理主要由四部分組成:Message
、Handler
、MessageQueue
和Looper
**Message: **
Message
對(duì)象是在線程之間傳遞的消息,它可以在內(nèi)部攜帶少量的信息,用于在不同的線程之間交換數(shù)據(jù)。what
、arg1
、arg2
字段攜帶一些整型數(shù)據(jù),obj
字段攜帶一個(gè)object
對(duì)象Handler:
Handler
對(duì)象主要用于發(fā)送和處理消息。發(fā)送消息一般是使用sendMessage()
方法,消息被發(fā)送到消息隊(duì)列(MessageQueue)中,輪詢(xún)器(Looper)會(huì)把消息對(duì)象傳遞給消息處理器(Handler),消息處理器調(diào)用handleMessage()
方法,此方法運(yùn)行在主線程中,可以刷新UIMessageQueue:
MessageQueue
對(duì)象是消息隊(duì)列的意思,主要存放所有通過(guò)Handler
發(fā)送的消息。這部分消息會(huì)一直存放在消息隊(duì)列里,直至被輪詢(xún)器取出傳遞給消息處理器。每個(gè)線程中只會(huì)有一個(gè)消息隊(duì)列對(duì)象Looper:
Looper
是輪詢(xún)器的意思,是每個(gè)線程中的消息隊(duì)列MessageQueue
的管家,其會(huì)不停的檢測(cè)消息隊(duì)列中是否有消息對(duì)象,若有將從消息隊(duì)列中取出消息對(duì)象傳遞給消息處理器