Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android中Handler的初步認識(三)

android中Handler的初步認識(三)

編輯:關於Android編程

在上一個例子中,最終我們發現,其實用到的線程只有一個,那就是程序的主線程(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;

	//獲取主線程的looper
	Looper looper = Looper.getMainLooper();

	
	@Override
	protected 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綁定onclicklistener
		startButton.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;
				@Override
				public void run() {
					// TODO Auto-generated method stub
					i += 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 中去掉run
			handler.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中的代碼拷貝中主線程中去執行了嗎?如果有誰知道麻煩為我解答一下,不甚感激!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved