• <td id="ae6ms"><li id="ae6ms"></li></td>
  • <xmp id="ae6ms"><td id="ae6ms"></td><table id="ae6ms"></table>
  • <table id="ae6ms"></table>
  • <td id="ae6ms"></td>
    <td id="ae6ms"></td>
  • <table id="ae6ms"></table><table id="ae6ms"><td id="ae6ms"></td></table>
  • <td id="ae6ms"></td>
  • <table id="ae6ms"><li id="ae6ms"></li></table>
  • <table id="ae6ms"></table>
    西西軟件下載最安全的下載網站、值得信賴的軟件下載站!

    首頁編程開發Android → Android中UI線程與后臺線程交互設計的5種方法

    Android中UI線程與后臺線程交互設計的5種方法

    相關軟件相關文章發表評論 來源:BananaMonster時間:2013/2/2 9:51:52字體大?。?em class="fontsize">A-A+

    作者:BananaMonster點擊:1573次評論:3次標簽: UI

    • 類型:圖像瀏覽大?。?i>13.0M語言:英文 評分:4.2
    • 標簽:
    立即下載

    我想關于這個話題已經有很多前輩討論過了。今天算是一次學習總結吧。

    在android的設計思想中,為了確保用戶順滑的操作體驗。一些耗時的任務不能夠在UI線程中運行,像訪問網絡就屬于這類任務。因此我們必須要重新開啟一個后臺線程運行這些任務。然而,往往這些任務最終又會直接或者間接的需要訪問和控制UI控件。例如訪問網絡獲取數據,然后需要將這些數據處理顯示出來。就出現了上面所說的情況。原本這是在正常不過的現象了,但是android規定除了UI線程外,其他線程都不可以對那些UI控件訪問和操控。為了解決這個問題,于是就引出了我們今天的話題。Android中后臺線程如何與UI線程交互。

    據我所知android提供了以下幾種方法,用于實現后臺線程與UI線程的交互。

    1、handler

    2、Activity.runOnUIThread(Runnable)

    3、View.Post(Runnable)

    4、View.PostDelayed(Runnabe,long)

    5、AsyncTask

    方法一:handler

    handler是android中專門用來在線程之間傳遞信息類的工具。

    要講明handler的用法非常簡單,但是我在這里會少許深入的講一下handler的運行機制。

    為了能夠讓handler在線程間傳遞消息,我們還需要用到幾個類。他們是looper,messageQueue,message。

    這里說的looper可不是前段時間的好萊塢大片環形使者,他的主要功能是為特定單一線程運行一個消息環。一個線程對應一個looper。同樣一個looper對應一個線程。這就是所謂的特定單一。一般情況下,在一個線程創建時他本身是不會生產他特定單一的looper的(主線程是個特例)。因此我們需要手動的把一個looper與線程相關聯。其方法只需在需要關聯的looper的線程中調用Looper.prepare。之后我們再調用Looper.loop啟動looper。

    說了這么多looper的事情,到底這個looper有什么用哪。其實之前我們已經說到了,他是為線程運行一個消息環。具體的說,在我們將特定單一looper與線程關聯的時候,looper會同時生產一個messageQueue。他是一個消息隊列,looper會不停的從messageQuee中取出消息,也就是message。然后線程就會根據message中的內容進行相應的操作。

    那么messageQueue中的message是從哪里來的哪?那就要提到handler了。在我們創建handler的時候,我們需要與特定的looper綁定。這樣通過handler我們就可以把message傳遞給特定的looper,繼而傳遞給特定的線程。在這里,looper和handler并非一一對應的。一個looper可以對應多個handler,而一個handler只能對應一個looper(突然想起了一夫多妻制,呵呵)。這里補充一下,handler和looper的綁定,是在構建handler的時候實現的,具體查詢handler的構造函數。

    在我們創建handler并與相應looper綁定之后,我們就可以傳遞message了。我們只需要調用handler的sendMessage函數,將message作為參數傳遞給相應線程。之后這個message就會被塞進looper的messageQueue。然后再被looper取出來交給線程處理。

    這里要補充說一下message,雖然我們可以自己創建一個新的message,但是更加推薦的是調用handler的obtainMessage方法來獲取一個message。這個方法的作用是從系統的消息池中取出一個message,這樣就可以避免message創建和銷毀帶來的資源浪費了(這也就是算得上重復利用的綠色之舉了吧)。

    突然發現有一點很重要的地方沒有講到,那就是線程從looper收到message之后他是如何做出響應的嘞。其實原來線程所需要做出何種響應需要我們在我們自定義的handler類中的handleMessage重構方法中編寫。之后才是之前說的創建handler并綁定looper。

    好吧說的可能喲點亂,總結一下利用handler傳遞信息的方法。

    假設A線程要傳遞信息給B線程,我們需要做的就是

    1、在B線程中調用Looper.prepare和Looper.loop。(主線程不需要)

    2、 編寫Handler類,重寫其中的handleMessage方法。

    3、創建Handler類的實例,并綁定looper

    4、調用handler的sentMessage方法發送消息。

    到這里,我們想handler的運行機制我應該是闡述的差不多了吧,最后再附上一段代碼,供大家參考。

     1 public class MyHandlerActivity extends Activity {
     2      TextView textView;
     3      MyHandler myHandler;
     4  
     5      protected void onCreate(Bundle savedInstanceState) {
     6          super.onCreate(savedInstanceState);
     7          setContentView(R.layout.handlertest);
     8  
     9          //實現創建handler并與looper綁定。這里沒有涉及looper與
                //線程的關聯是因為主線程在創建之初就已有looper
    10          myHandler=MyHandler(MyHandlerActivitythis.getMainLooper());
    11          textView = (textView) findViewById(R.id.textView);
    12         
    13          MyThread m = new MyThread();
    14          new Thread(m).start();
    15      }
    16  
    17  
    18      class MyHandler extends Handler {
    19          public MyHandler() {
    20          }
    21  
    22          public MyHandler(Looper L) {
    23              super(L);
    24          }
    25  
    26          // 必須重寫這個方法,用于處理message
    27          @Override
    28          public void handleMessage(Message msg) {
    29              // 這里用于更新UI
    30              Bundle b = msg.getData();
    31              String color = b.getString("color");
    32              MyHandlerActivity.this.textView.setText(color);
    33          }
    34      }
    35  
    36      class MyThread implements Runnable {
    37          public void run() {
    38              //從消息池中取出一個message
    39              Message msg = myHandler.obtainMessage();
    40              //Bundle是message中的數據
    41              Bundle b = new Bundle();
    42              b.putString("color", "我的");
    43              msg.setData(b);
    44              //傳遞數據
    45              myHandler.sendMessage(msg); // 向Handler發送消息,更新UI
    46          }
    47      }

    方法二:Activity.runOnUIThread(Runnable)

     這個方法相當簡單,我們要做的只是以下幾步

    1、編寫后臺線程,這回你可以直接調用UI控件

    2、創建后臺線程的實例

    3、調用UI線程對應的Activity的runOnUIThread方法,將后臺線程實例作為參數傳入其中。

    注意:無需調用后臺線程的start方法

    方法三:View.Post(Runnable)

     該方法和方法二基本相同,只是在后臺線程中能操控的UI控件被限制了,只能是指定的UI控件View。方法如下

    1、編寫后臺線程,這回你可以直接調用UI控件,但是該UI控件只能是View

    2、創建后臺線程的實例

    3、調用UI控件View的post方法,將后臺線程實例作為參數傳入其中。

    方法四:View.PostDelayed(Runnabe,long)

    該方法是方法三的補充,long參數用于制定多少時間后運行后臺進程 

    方法五:AsyncTask

    AsyncTask是一個專門用來處理后臺進程與UI線程的工具。通過AsyncTask,我們可以非常方便的進行后臺線程和UI線程之間的交流。

    那么AsyncTask是如何工作的哪。

    AsyncTask擁有3個重要參數

    1、Params 

    2、Progress

    3、Result

    Params是后臺線程所需的參數。在后臺線程進行作業的時候,他需要外界為其提供必要的參數,就好像是一個用于下載圖片的后臺進程,他需要的參數就是圖片的下載地址。

    Progress是后臺線程處理作業的進度。依舊上面的例子說,就是下載圖片這個任務完成了多少,是20%還是60%。這個數字是由Progress提供。

    Result是后臺線程運行的結果,也就是需要提交給UI線程的信息。按照上面的例子來說,就是下載完成的圖片。

    AsyncTask還擁有4個重要的回調方法。

    1、onPreExecute

    2、doInBackground

    3、onProgressUpdate

    4、onPostExecute

    onPreExecute運行在UI線程,主要目的是為后臺線程的運行做準備。當他運行完成后,他會調用doInBackground方法。

    doInBackground運行在后臺線程,他用來負責運行任務。他擁有參數Params,并且返回Result。在后臺線程的運行當中,為了能夠更新作業完成的進度,需要在doInbackground方法中調用PublishProgress方法。該方法擁有參數Progress。通過該方法可以更新Progress的數據。然后當調用完PublishProgress方法,他會調用onProgressUpdate方法用于更新進度。

    onProgressUpdate運行在UI線程,主要目的是用來更新UI線程中顯示進度的UI控件。他擁有Progress參數。在doInBackground中調用PublishProgress之后,就會自動調onProgressUpdate方法

    onPostExecute運行在UI線程,當doInBackground方法運行完后,他會調用onPostExecute方法,并傳入Result。在onPostExecute方法中,就可以將Result更新到UI控件上。

    明白了上面的3個參數和4個方法,你要做的就是

    1、編寫一個繼承AsyncTask的類,并聲明3個參數的類型,編寫4個回調方法的內容。

    2、然后在UI線程中創建該類(必須在UI線程中創建)。

    3、最后調用AsyncTask的execute方法,傳入Parmas參數(同樣必須在UI線程中調用)。

    這樣就大功告成了。

    另外值得注意的2點就是,千萬不要直接調用那四個回調方法。還有就是一個AsyncTask實例只能執行一次,否則就出錯哦。

    以上是AsyncTask的基本用法,更加詳細的內容請參考android官方文檔。最后附上一段代碼,供大家參考。

     1 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> 
     2 //在這里聲明了Params、Progress、Result參數的類型
     3 {
     4     //因為這里不需要使用onPreExecute回調方法,所以就沒有加入該方法
     5     
     6     //后臺線程的目的是更具URL下載數據
     7      protected Long doInBackground(URL... urls) {
     8          int count = urls.length;//urls是數組,不止一個下載鏈接
     9          long totalSize = 0;//下載的數據
    10          for (int i = 0; i < count; i++) {
    11              //Download是用于下載的一個類,和AsyncTask無關,大家可以忽略他的實現
    12              totalSize += Downloader.downloadFile(urls[i]);
    13              publishProgress((int) ((i / (float) count) * 100));//更新下載的進度
    14              // Escape early if cancel() is called
    15              if (isCancelled()) break;
    16          }
    17          return totalSize;
    18      }
    19 
    20      //更新下載進度
    21      protected void onProgressUpdate(Integer... progress) {
    22          setProgressPercent(progress[0]);
    23      }
    24 
    25      //將下載的數據更新到UI線程
    26      protected void onPostExecute(Long result) {
    27          showDialog("Downloaded " + result + " bytes");
    28      }
    29  }
    30

     有了上面的這個類,接下你要做的就是在UI線程中創建實例,并調用execute方法,傳入URl參數就可以了。

    這上面的5種方法各有優點。但是究其根本,其實后面四種方法都是基于handler方法的包裝。在一般的情形下后面四種似乎更值得推薦。但是當情形比較復雜,還是推薦使用handler。

    最后補充一下,這是我的第一篇博客。存在很多問題請大家多多指教。尤其是文中涉及到內容,有嚴重的技術問題,大家一定要給我指明啊。拜托各位了。

      相關評論

      閱讀本文后您有什么感想? 已有人給出評價!

      • 8 喜歡喜歡
      • 3 頂
      • 1 難過難過
      • 5 囧
      • 3 圍觀圍觀
      • 2 無聊無聊

      熱門評論

      最新評論

      第 3 樓 本機地址CZ88.NET 網友 客人 發表于: 2016/3/10 17:02:03

      支持( 0 ) 蓋樓(回復)

      第 2 樓 浙江杭州鐵通 網友 客人 發表于: 2015/4/23 23:11:40
      写的不错哟,给你

      支持( 0 ) 蓋樓(回復)

      第 1 樓 廣東佛山順德聯通 網友 客人 發表于: 2015/2/10 11:27:22
      写的不错!!!

      支持( 0 ) 蓋樓(回復)

      發表評論 查看所有評論(3)

      昵稱:
      表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
      字數: 0/500 (您的評論需要經過審核才能顯示)
      女人让男人桶30分钟免费视频,女人张开腿让男人桶个爽,一进一出又大又粗爽视频
    • <td id="ae6ms"><li id="ae6ms"></li></td>
    • <xmp id="ae6ms"><td id="ae6ms"></td><table id="ae6ms"></table>
    • <table id="ae6ms"></table>
    • <td id="ae6ms"></td>
      <td id="ae6ms"></td>
    • <table id="ae6ms"></table><table id="ae6ms"><td id="ae6ms"></td></table>
    • <td id="ae6ms"></td>
    • <table id="ae6ms"><li id="ae6ms"></li></table>
    • <table id="ae6ms"></table>