Android學習歷程2

上一篇的補充

在寫了上一篇博客之後,突然想到對於一個初學者而言,有很多基礎性的概念都不是很清楚,可能會讓很多人迷惑,爲什麼要使用Asynctask,至少我自己當時見到的時候就很迷茫,因此在這裏做一個補充。

Asynctask是安卓開發過程中所經常用到的兩種異步加載的方式之一。可是在開發過程中,我們爲什麼要使用異步加載的方式呢?

異步加載的原因:

在開發Android應用時必須遵守單線程模型的原則: Android UI操作並不是線程安全的並且這些操作必須在UI線程中執行。在單線程模型中始終要記住兩條法則:
1. 不要阻塞UI線程 (這裏又會衍生出一個概念UI線程,什麼是UI線程。顧名思義,ui線程就是管理着用戶界面的那個線程!)
2. 確保只在ui線程中訪問ui組件
當一個程序第一次啓動時,Android會同時啓動一個對應的主線程(Main Thread),主線程主要負責處理與UI相關的事件,如:用戶的按鍵事件,用戶接觸屏幕的事件以及屏幕繪圖事件,並把相關的事件分發到對應的組件進行處理。所以主線程通常又被叫做UI線程。
比如說從網上獲取一個網頁,在一個TextView中將其源代碼顯示出來,這種涉及到網絡操作的程序一般都是需要開一個線程完成網絡訪問,但是在獲得頁面源碼後,是不能直接在網絡操作線程中調用TextView.setText()的.因爲其他線程中是不能直接訪問主UI線程成員 。
爲了解決這種情況,android爲我們提供了很多辦法。

1)、handler和message機制:通過顯示的拋出、捕獲消息與ui進行交互;

2)、Activity.runOnUiThread(Runnable):如果當前線程爲ui線程,則立即執行;否則,將參數中的線程操作放入到ui線程的事件隊列中,等待執行。

3)、View.post(Runnable):將操作放入到message隊列中,如果放入成功,該操作將會在ui線程中執行,並返回true,否則返回false

4)、View.postDelayed(Runnable, long)跟第三條基本一樣,只不過添加了一個延遲時間。

5)、android1.5以後爲我們提供了一個工具類來搞定這個問題AsyncTask.
現在基本常用的就是第一和第五種,


介紹最本質的多線程:hanlder和message機制:

爲何需要多線程:

在日常應用中,我們通常需要處理一些“後臺,用戶不可見”的操作,例如說,我們需要下載一個音樂,要是你的應用必須等用戶下載完成之後纔可以進行別的操 作,那肯定讓用戶非常的不爽。這時候,我們通常的做法是,讓這些操作去後臺執行,然後等後臺執行完畢之後,再給用戶彈出相應的提示信息。這時候,我們就需 要使用多線程機制,然後通過創建一個新的線程來執行這些操作。

明白了,實現需求,我們就準備着手實現了。但是,經過進一步的瞭解,我們悲劇的發現,android中的線程機制是,只能在UI線程中和用戶進行交互。當 我們創建了一個新線程,執行了一些後臺操作,執行完成之後,我們想要給用戶彈出對話框以確認,但是卻悲劇的發現,我們根本無法返回UI主線程了。

(說明:何爲UI線程:UI線程就是你當前看到的這些交互界面所屬的線程)。

這時候,我們如果想要實現這些功能,我們就需要一個android爲我們提供的handler和message機制。

先講解下編程機制:

我們通常在UI線程中創建一個handler,handler相當於一個處理器,它主要負責處理和綁定到該handler的線程中的message。每一 個handler都必須關聯一個looper,並且兩者是一一對應的,注意,這點很重要哦!此外,looper負責從其內部的messageQueue中 拿出一個個的message給handler進行處理。因爲我們這裏handler是在UI線程中實現的,所以經過這麼一個handler、 message機制,我們就可以回到UI線程中了。

何爲handler:處理後臺進程返回數據的工作人員。

何爲message:後臺進程返回的數據,裏面可以存儲bundle等數據格式

何爲messageQueue:是線程對應looper的一部分,負責存儲從後臺進程中拋回的和當前handler綁定的message,是一個隊列。

何爲looper:looper相當於一個messageQueue的管理人員,它會不停的循環的遍歷隊列,然後將符合條件的message一個個的拿出來交給handler進行處理。

注意,handler是在UI線程中聲明的,如果我們直接用類似代碼執行一個線程的話,實際上並沒有創建一個新的線程,因爲handler已經跟默認的UI線程中的looper綁定了。

如果有興趣的話,可以去看下Handler的默認空構造函數便知道原因了,裏面直接綁定了當前UI線程的looper。


handler介紹

既然前面說到了Asnctask和hadler是安卓開發過程中常用的兩種異步加載的方式,前一章也簡單介紹了Asnctask的用法,現在在這裏簡單介紹一下handler的使用

Handler主要用於異步消息的處理:當發出一個消息之後,首先進入一個消息隊列,發送消息的函數即刻返回,而另外一個部分逐個的在消息隊列中將消息取出,然後對消息進行出來,就是發送消息和接收消息不是同步的處理。 這種機制通常用來處理相對耗時比較長的操作。

通常情況下,當應用程序啓動時,Android首先會開啓一個主線程 (也就是UI線程) , 主線程爲管理界面中的UI控件,進行事件分發。如果此時需要一個耗時的操作,例如:聯網讀取數據,或者讀取本地較大的一個文件的時候,你不能把這些操作放在主線程中,如果你放在主線程中的話,界面會出現假死現象,如果5秒鐘還沒有完成的話,會收到Android系統的一個錯誤提示”強制關閉”。

這個時候我們需要把這些耗時的操作,放在一個子線程中,因爲子線程涉及到UI更新,但是當子線程中有涉及到操作UI的操作時,就會對主線程產生危險,也就是說,更新UI只能在主線程中更新,在子線程中操作是危險的. 這個時候,Handler就出現了來解決這個複雜的問題,由於Handler運行在主線程中(UI線程中),它與子線程可以通過Message對象來傳遞數據,這個時候,Handler就承擔着接受子線程傳過來的(子線程用sedMessage()方法傳遞)Message對象,(裏面包含數據), 把這些消息放入主線程隊列中,配合主線程進行更新UI。

   Handler工具類在多線程中有兩方面的應用:

  1、發送消息,在不同的線程間發送消息,使用的方法爲sendXXX();。

  android.os.Handler對象通過下面的方法發送消息的:
  sendEmptyMessage(int),發送一個空的消息;
  sendMessage(Message),發送消息,消息中可以攜帶參數;
  sendMessageAtTime(Message, long),未來某一時間點發送消息;
  sendMessageDelayed(Message, long),延時Nms發送消息。

   2、計劃任務,在未來執行某任務,使用的方法爲postXXX();。

  android.os.Handler對象通過下面的方法執行計劃任務:
  post(Runnable),提交計劃任務馬上執行;
  postAtTime(Runnable, long),提交計劃任務在未來的時間點執行;
  postDelayed(Runnable, long),提交計劃任務延時Nms執行。

在使用handler的時候,首先要聲明一個handler對象,並重寫以下方法,
private Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case TryCatch:
HideLoading();
Toast.makeText(mContext, “錯誤號碼101”, Toast.LENGTH_SHORT).show();
break;
default:
break;
}
super.handleMessage(msg);
}
};

在聲明瞭對象之後,在需要執行異步加載的地方,寫下如下代碼:

mHandler.sendEmptyMessage(TryCatch1);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章