android中Handler的初步認識(三)

來源:互聯網
上載者:User

在上一個例子中,最終我們發現,其實用到的線程只有一個,那就是程式的主線程(UI線程)。那麼怎麼把那個例子改成用建立的線程來實現呢,今天我嘗試了一下,寫了下面這個小程式。

當然,首先要聲明一下,今天的這個例子並不是推薦的寫法,而是我為了學習多線程而寫的例子(貌似更常用的是AsyncTask,而不是Thread和Handler去更新UI)。


在今天的這個例子中,我用到了Looper,先說說Looper是什麼


在API中是這麼解釋Lopper的:Class used to run a message loop for a thread。我的理解是Looper是用來控制message queue的類


Looper常用的幾個用法有:

Looper.prepare() 安卓的主線程中會預設調用這個方法來建立訊息佇列。但是,如果我們自己建立的線程,如果需要訊息佇列,則需要手動調用這個方法。

Looper.loop() 這個方法用在prepare()方法之後,調用該方法之後,進入訊息迴圈。

Looper.getMainLooper() 我在代碼中用到了這個方法,這個方法的作用是獲得主線程的Looper執行個體

Looper.myLooper() 這個方法用到擷取當前線程的Looper執行個體


今天這個例子和第二篇中實現的功能一下,我只不過改了一個寫法而已,下面是代碼:

package com.example.handler2;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Looper;import android.os.Message;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.ProgressBar;public class MainActivity extends Activity {Button startButton = null;Button stopButton = null;ProgressBar progressbar = null;Thread counter = null;//擷取主線程的looperLooper looper = Looper.getMainLooper();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);startButton = (Button) findViewById(R.id.startButton);stopButton = (Button) findViewById(R.id.stopButton);progressbar = (ProgressBar) findViewById(R.id.progressBar);//為button綁定onclicklistenerstartButton.setOnClickListener(new ButtonOnclickListener());stopButton.setOnClickListener(new stopOnclickListener());}class ButtonOnclickListener implements OnClickListener{public void onClick(View v) {progressbar.setVisibility(View.VISIBLE);counter = new Thread(){int i = 1;@Overridepublic void run() {// TODO Auto-generated method stubi += 10;Message msg = handler.obtainMessage();msg.arg1 = i;//讓線程延遲一秒try {Thread.sleep(1000);} catch (Exception e) {e.printStackTrace();}Log.i("run", "run "+i+"%");Log.i("run", Thread.currentThread().getName());msg.sendToTarget();  }};counter.start();}}class stopOnclickListener implements OnClickListener{public void onClick(View v) {//從message queue 中去掉runhandler.removeCallbacks(counter);//讓progressbar置成隱藏progressbar.setVisibility(View.GONE);}}//將handler與主線程關聯Handler handler = new Handler(looper){public void handleMessage(android.os.Message msg) {int i =msg.arg1;//根據message中傳來的參數控制進度條progressbar.setProgress(i);Log.i("run", Thread.currentThread().getName());if(i<100){handler.post(counter);}else{handler.removeCallbacks(counter);progressbar.setVisibility(View.GONE);}};};}


這段代碼,和第二篇中最大的差別就是,當我點擊啟動按鈕後,調用的不是主線程的run,而是我建立的線程。

但是因為安卓不允許我們在主線程之外的線程中對UI進行修改,所以我在建立的線程中只是進行計數,然後將計數的結果通過message傳遞到主線程中,在主線程中更新進度條。


遺留問題:

本來這個例子到這裡就結束了,但是,我為了深入瞭解一下就在我建立的線程的run中和主線程Handler的handlerMessage方法中列印了當前線程的名稱:

結果如下:



按照我最初的理解,在日誌中應該是主線程和我的線程交替寫入日誌,但是實際的情況是在第一次是counter線程,後面列印的都是主線程

請問各位,有誰知道這是為什麼嗎?


我看到在API中Handler的post方法是這麼說明的:Causes the Runnable r to be added to the message queue. The runnable will be run on the thread to which this handler is attached.

難道是,我使用了post方法,就相當於把counter線程的run中的代碼拷貝中主線程中去執行了嗎?如果有誰知道麻煩為我解答一下,不甚感激!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.