Android基礎之六:多線程開發

  • 多線程開發爲複雜的耗時處理功能提升了效率,同時也不影響UI界面的顯示效果,是在Android開發或者Java開發中常常用到的一種開發機制
  • 首先理解多線程的概念:
    • 多線程並非真正的多個任務在同一時間點上併發執行,而是分時間片來執行,即同一個時間點上執行的任務只有一個,可是從一小段時間來看,倒是許多任務併發執行
    • 多線程須要注重資源的分配
    • 須要注意Java中多線程機制
    • 主線程:即應用的UI線程
    • 輔線程:即工做線程,不能直接操做UI
  • Android中的多線程
    • Handler類
      • post方法
        • post方法並無新起線程,仍然運行在UI線程中,其本質上仍是UI線程,只是是UI現成的子線程,能夠優化UI操做性能
        • 與View自帶的post方法原理相同,都是在UI子線程中操做UI變化
        • Handler handler=new Handler();
          handler.post(new Runnable() {
                @Override
                 public void run() {
                        //ToDo
                 }
          });
        • 注意:進行UI操做,例如修改UI控件屬性等,雖然直接修改通常不會出現問題,可是若是在UI執行耗時操做時會形成卡頓,一般使用post來經過UI子線程來操做
      • sendMessage方法
        • post方法只適合在單獨操做UI的狀況下使用,若是其中涉及到耗時操做以及UI操做,例如:UI與Service通訊,根據Service返回的結果修改UI,Service一般是一個比較耗時的操做,在這種狀況下就不能直接使用post將耗時操做放到UI線程中,而是須要開啓輔線程
        • 輔線程是獨立於UI線程以外的工做線程,在工做線程中可以處理複雜的業務邏輯計算等耗時操做,可是不能直接操做UI
        • 輔線程(工做線程)與UI線程之間的交互
          • UI線程中建立Handler
          • Handler handler=new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    //UI 操做
                }
            };
          • 輔線程中建立Message消息,並向主線程的handler傳遞消息
          • Message message=new Message();
            message.setData(new Bundle());
            handler.sendMessage(message);
          • 這樣就能夠實現工做線程執行耗時操做,UI線程負責界面處理
    • HandlerThread類
      • HandlerThread能夠另起新線程,但不能操做UI,屬於工做線程
      • 經過HandlerThread的Looper建立的Handler使用post方法也不能操做UI,只有經過主線程的Looper建立的Handler才能操做UI,即Handler的構造方法中不傳參時表示的是使用主線程的Looper建立實例
      • HandlerThread使用
        • 建立實例
        • HandlerThread ht = new HandlerThread("handler thread");
          ht.start();
        • 實例化後必須使用start啓動
        • 經過HandlerThread實例的Looper建立Handler實例
        • Handler handler=new Handler(ht.getLooper());
        • 經過Handler實例進行post方法調用
        • handler.post(new Runnable(){//這裏run()方法其實仍是在等ht.start()調用
              public void run(){
                  Log.e("當前線程:",Thread.currentThread().getName());//這裏打印的會是handler thread
                  setTitle("哈哈");//這樣一定報錯
              }
          });
        • 在run中若是操做UI會直接報錯,由於這個縣城是工做線程,不能執行UI操做,而若是想要執行UI操做,須要經過sendMessage來實現,在UI線程中再實例化一個Handler實例,重寫handlerMessage方法,而後在run中向該實例發送消息
        • 這樣實現會發現比較繁瑣並且低效,不建議使用這種方法,即HandlerThread不建議使用
        • 而且一個HandlerThread中建立的多個Handler,在post的時候並非並打的,而是順序執行的
    • Java中建立線程方法
      • Java提供了通用的多線程類與接口,可以簡單而直接建立工做線程,不須要使用HandlerThread建立一個handler
      • 經過new Thread(){run}.start();
      • new Thread(){
            @Override
            public void run() {
                super.run();
                //ToDo
            }
        }.start();
        • 該方法是經過匿名類來實例化Thread的子類實例的,在run中處理複雜操做,併發送消息到UI線程中,完成與UI線程通訊
      • 經過new Thread(Runnable).start();
      • new Thread(new Runnable() {
            @Override
            public void run() {
                
            }
        }).start();
        • 經過Runnable接口實例化Thread實例,與匿名類同樣,只是兩種不一樣的實例化方法
    • AsyncTask異步任務
      • Android中提供一種異步任務類,可以實現簡單的工做線程與主線程操做,是Handler、Message的結合,使用更加簡單
      • 建立異步任務
        • 注意AsyncTask中的5個可重寫方法
          • onPreExcute:是在異步任務執行前執行的操做,能夠操做UI線程
          • doInBackground(params):在工做線程中執行的操做
          • onProgressUpdate(values):在工做線程執行過程當中若是須要操做UI,就能夠在doInBackground中使用publicProgress();來廣播進度,在onProgressUpdate中就會收到進度值
          • onPostExcute(retult):任務執行結束後調用,即將doInBackground中返回的結果傳到該方法中
          • 在實例化AsyncTask的時候能夠直接指定不一樣方法中參數的類型,即AsyncTask是泛型類
          • 在整個過程當中只有一個方法doInBackground是在工做線層中運行的,其餘三個方法都是在主線程中運行的
        • 實例化
        • AsyncTask<String,String,String> asyncTask=new AsyncTask<String, String, String>() {
              @Override
              protected void onPreExecute() {
                  super.onPreExecute();
              }
              @Override
              protected String doInBackground(String... params) {
                  return null;
              }
              @Override
              protected void onProgressUpdate(String... values) {
                  super.onProgressUpdate(values);
              }
              @Override
              protected void onPostExecute(String s) {
                  super.onPostExecute(s);
              }
          };
        • 與Thread+Handler+Message實現多線程比較
          • AsyncTask本質上就是Thread+Handler+Message的封裝
          • 在Activity被從新建立(設備狀態改變,例如屏幕方向變化引發的Activity重啓)時,任務會被取消
          • 在線程池中只能容納5個後臺運行程序,再多會形成阻塞,這裏表示的是經過AsyncTask建立的線程,用Thread建立的不算
          • 執行方式不一樣,AsyncTask經過excute來執行,Thread經過start來執行
    • ExecutorService線程池
      • 線程池適合處理大量線程的操做,例如多線程加載1000張圖片,多線程批量下載
      • 實例化線程池
        • 單線程
        • ExecutorService service=Executors.newSingleThreadExecutor();
        • 固定數量線程
        • ExecutorService service=Executors.newFixedThreadPool(10);
        • 動態線程
        • ExecutorService service=Executors.newCachedThreadPool();
      • 執行線程操做:
        • submit(Runnable):建立並執行一個工做線程
相關文章
相關標籤/搜索