最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android編程中的消息機(jī)制實(shí)例詳解

 更新時(shí)間:2016年01月05日 10:52:04   作者:liuhe688  
這篇文章主要介紹了Android編程中的消息機(jī)制,結(jié)合實(shí)例形式較為詳細(xì)的分析了Android中消息機(jī)制的原理,注意事項(xiàng)與相關(guān)使用技巧,需要的朋友可以參考下

本文實(shí)例講述了Android編程中的消息機(jī)制。分享給大家供大家參考,具體如下:

在分析Android消息機(jī)制之前,我們先來看一段代碼:

public class MainActivity extends Activity implements View.OnClickListener {
  private TextView stateText;
  private Button btn;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    stateText = (TextView) findViewById(R.id.tv);
    btn = (Button) findViewById(R.id.btn);
    btn.setOnClickListener(this);
  }
  @Override
  public void onClick(View v) {
    new WorkThread().start();
  }
  //工作線程
  private class WorkThread extends Thread {
    @Override
    public void run() {
      //......處理比較耗時(shí)的操作
      //處理完成后改變狀態(tài)
      stateText.setText("completed");
    }
  }
}

這段代碼似乎看上去很正常,但是當(dāng)你運(yùn)行時(shí)就會(huì)發(fā)現(xiàn),它會(huì)報(bào)一個(gè)致命性的異常:

ERROR/AndroidRuntime(421): FATAL EXCEPTION: Thread-8
ERROR/AndroidRuntime(421): android.view.ViewRoot$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can touch its views.

到底是怎么回事呢?原因在于,Android系統(tǒng)中的視圖組件并不是線程安全的,如果要更新視圖,必須在主線程中更新,不可以在子線程中執(zhí)行更新的操作。
既然這樣,我們就在子線程中通知主線程,讓主線程做更新操作吧。那么,我們?nèi)绾瓮ㄖ骶€程呢?我們需要使用到Handler對(duì)象。
我們稍微修改一下上面的代碼:

public class MainActivity extends Activity implements View.OnClickListener {
  private static final int COMPLETED = 0;
  private TextView stateText;
  private Button btn;
  private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      if (msg.what == COMPLETED) {
        stateText.setText("completed");
      }
    }
  };
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    stateText = (TextView) findViewById(R.id.tv);
    btn = (Button) findViewById(R.id.btn);
    btn.setOnClickListener(this);
  }
  @Override
  public void onClick(View v) {
    new WorkThread().start();
  }
  //工作線程
  private class WorkThread extends Thread {
    @Override
    public void run() {
      //......處理比較耗時(shí)的操作
      //處理完成后給handler發(fā)送消息
      Message msg = new Message();
      msg.what = COMPLETED;
      handler.sendMessage(msg);
    }
  }
}

通過上面這種方式,我們就可以解決線程安全的問題,把復(fù)雜的任務(wù)處理工作交給子線程去完成,然后子線程通過handler對(duì)象告知主線程,由主線程更新視圖,這個(gè)過程中消息機(jī)制起著重要的作用。

下面,我們就來分析一下Android中的消息機(jī)制。

熟悉Windows編程的朋友知道Windows程序是消息驅(qū)動(dòng)的,并且有全局的消息循環(huán)系統(tǒng)。Google參考了Windows的消息循環(huán)機(jī)制,也在Android系統(tǒng)中實(shí)現(xiàn)了消息循環(huán)機(jī)制。Android通過Looper、Handler來實(shí)現(xiàn)消息循環(huán)機(jī)制。Android的消息循環(huán)是針對(duì)線程的,每個(gè)線程都可以有自己的消息隊(duì)列和消息循環(huán)。

Android系統(tǒng)中的Looper負(fù)責(zé)管理線程的消息隊(duì)列和消息循環(huán)。通過Looper.myLooper()得到當(dāng)前線程的Looper對(duì)象,通過Looper.getMainLooper()得到當(dāng)前進(jìn)程的主線程的Looper對(duì)象。

前面提到,Android的消息隊(duì)列和消息循環(huán)都是針對(duì)具體線程的,一個(gè)線程可以存在一個(gè)消息隊(duì)列和消息循環(huán),特定線程的消息只能分發(fā)給本線程,不能跨線程和跨進(jìn)程通訊。但是創(chuàng)建的工作線程默認(rèn)是沒有消息隊(duì)列和消息循環(huán)的,如果想讓工作線程具有消息隊(duì)列和消息循環(huán),就需要在線程中先調(diào)用Looper.prepare()來創(chuàng)建消息隊(duì)列,然后調(diào)用Looper.loop()進(jìn)入消息循環(huán)。下面是我們創(chuàng)建的工作線程:

class WorkThread extends Thread {
   public Handler mHandler;
   public void run() {
     Looper.prepare();
     mHandler = new Handler() {
       public void handleMessage(Message msg) {
         // 處理收到的消息
       }
     };
     Looper.loop();
   }
}

這樣一來,我們創(chuàng)建的工作線程就具有了消息處理機(jī)制了。
那么,為什么前邊的示例中,我們?cè)趺礇]有看到Looper.prepare()和Looper.loop()的調(diào)用呢?原因在于,我們的Activity是一個(gè)UI線程,運(yùn)行在主線程中,Android系統(tǒng)會(huì)在Activity啟動(dòng)時(shí)為其創(chuàng)建一個(gè)消息隊(duì)列和消息循環(huán)。
前面提到最多的是消息隊(duì)列(MessageQueue)和消息循環(huán)(Looper),但是我們看到每個(gè)消息處理的地方都有Handler的存在,它是做什么的呢?Handler的作用是把消息加入特定的Looper所管理的消息隊(duì)列中,并分發(fā)和處理該消息隊(duì)列中的消息。構(gòu)造Handler的時(shí)候可以指定一個(gè)Looper對(duì)象,如果不指定則利用當(dāng)前線程的Looper對(duì)象創(chuàng)建。下面是Handler的兩個(gè)構(gòu)造方法:

/**
* Default constructor associates this handler with the queue for the
* current thread.
*
* If there isn't one, this handler won't be able to receive messages.
*/
public Handler() {
    if (FIND_POTENTIAL_LEAKS) {
      final Class<? extends Handler> klass = getClass();
      if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
          (klass.getModifiers() & Modifier.STATIC) == 0) {
        Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
          klass.getCanonicalName());
      }
    }
    mLooper = Looper.myLooper();
    if (mLooper == null) {
      throw new RuntimeException(
        "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = null;
}
/**
* Use the provided queue instead of the default one.
*/
public Handler(Looper looper) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = null;
}

下面是消息機(jī)制中幾個(gè)重要成員的關(guān)系圖:

一個(gè)Activity中可以創(chuàng)建出多個(gè)工作線程,如果這些線程把他們消息放入Activity主線程的消息隊(duì)列中,那么消息就會(huì)在主線程中處理了。因?yàn)橹骶€程一般負(fù)責(zé)視圖組件的更新操作,對(duì)于不是線程安全的視圖組件來說,這種方式能夠很好的實(shí)現(xiàn)視圖的更新。

那么,子線程如何把消息放入主線程的消息隊(duì)列中呢?只要Handler對(duì)象以主線程的Looper創(chuàng)建,那么當(dāng)調(diào)用Handler的sendMessage方法,系統(tǒng)就會(huì)把消息主線程的消息隊(duì)列,并且將會(huì)在調(diào)用handleMessage方法時(shí)處理主線程消息隊(duì)列中的消息。

對(duì)于子線程訪問主線程的Handler對(duì)象,你可能會(huì)問,多個(gè)子線程都訪問主線程的Handler對(duì)象,發(fā)送消息和處理消息的過程中會(huì)不會(huì)出現(xiàn)數(shù)據(jù)的不一致呢?答案是Handler對(duì)象不會(huì)出現(xiàn)問題,因?yàn)镠andler對(duì)象管理的Looper對(duì)象是線程安全的,不管是添加消息到消息隊(duì)列還是從消息隊(duì)列中讀取消息都是同步保護(hù)的,所以不會(huì)出現(xiàn)數(shù)據(jù)不一致現(xiàn)象。

深入理解Android消息處理機(jī)制對(duì)于應(yīng)用程序開發(fā)非常重要,也可以讓我們對(duì)線程同步有更加深刻的認(rèn)識(shí),希望這篇文章可以對(duì)朋友們有所幫助。

希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。

相關(guān)文章

最新評(píng)論

砚山县| 汕头市| 株洲县| 监利县| 溧水县| 陆川县| 陆良县| 周口市| 海盐县| 陵水| 石泉县| 昂仁县| 沈丘县| 陕西省| 韶山市| 栾川县| 资兴市| 中山市| 阿城市| 淳化县| 额尔古纳市| 无极县| 全椒县| 兴海县| 内乡县| 武隆县| 改则县| 万山特区| 泰和县| 革吉县| 益阳市| 兴城市| 舟山市| 吉水县| 平顶山市| 新泰市| 永年县| 宜兰县| 黄平县| 上犹县| 太保市|