android的looper、handler的使用

處理線程中消息隊列的方法目前我知道的分爲種兩種。一種是線程自己帶有消息隊列,如主線程和handlerThread,主線程不說了。handlerThread繼承自thread但它與通常thread不一樣的地方是它有本身的消息隊列。而通常線程(指本身建立的線程)在默認狀況下沒有和它相關的消息隊列。要想使其有在運行消息隊列的線程中調用Looper.prepare();方法。而後調用Looper.loop();去讓消息隊列中的消息挨個執行。以下所示:java

class LooperThread extends Thread {       public Handler mHandler;       public void run() {           Looper.prepare();           mHandler = new Handler() {               public void handleMessage(Message msg) {                   // process incoming messages here               }           };           Looper.loop();       }   }

        由於線程默認狀況下是沒有本身的消息隊列的,因此若是在該線程的run()方法中新建handler後調用handler.post(runnable);程序會報錯。但在run方法外調用就沒事。由於thread類只是管理子線程的,其真正的子線程是在run方法中的。android


本身寫的例子以下:app

package com.example.handlerdemo;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.R.integer;
import android.app.Activity;
import android.view.Menu;
import android.view.TextureView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
	Handler handler;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		Button start=(Button) findViewById(R.id.button1);
		TextView textView=(TextView) findViewById(R.id.textView1);
		start.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
			
				Thread thread=new Thread(){

					@Override
					public void run() {
						// TODO Auto-generated method stub
						Looper.prepare();
						handler=new Handler(){
							@Override
							public void handleMessage(Message msg) {
								// TODO Auto-generated method stub
								super.handleMessage(msg);
								switch (msg.what) {
								case 1:
									System.out.println("thread name is"+" "+Thread.currentThread().getName());
									break;
								}
							}
						};
						handler.post(runnable);
						Looper.loop();
					}
				};
				thread.start();
			}
		});
		
	}
		Runnable runnable=new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				System.out.println("這是runnable1");
				handler.sendMessage(handler.obtainMessage(1));
			}
		};
		
	
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		System.out.println("looper綁定的線程是"+Looper.myLooper().getThread().getName());
		Looper.myLooper().quit();
		super.onDestroy();
		
	}
	
	}

其中onDestroy方法中結束looper有錯誤。其獲得的是主線程的名字。會報錯。疑問:在哪裏結束Looper。有待研究。歡迎留言賜教。ide

handleMessage中打印出來的線程的名字是本身定義出來的線程的名字。而非主線程。而onDestroy方法中打印出來的是主線程的名字。且該處錯誤,不應在此處中止looper,此處疑問。oop

接近一年後再次回來看本身曾經的疑問,感受那時本身好傻啊,這麼明顯的問題都沒看出來。哎,看來本身仍是進步了。竊喜。在onDestroy方法中中止的固然必須是當初的那個looper,而上文在onDestroy中quit的,是從新得到的當前線程(main)線程的looper,固然不是原來的,因此會報錯啊。須將本身聲明的線程中的Looper mLooper=Looper.myLooper();而後在onDestroy中直接mLooper.quit();就OK了。至於具體深刻研究還需去看源碼,加油吧,路上的孩子。post

其中handler的還能夠這樣生成:ui

handler=new Handler(new Handler.Callback() {

@Override
public boolean handleMessage(Message msg) {
// TODO Auto-generated method stub
switch (msg.what) {
case 1:
System.out.println("thread name is"+" "+Thread.currentThread().getName());
break;
}
return true;
}
});
spa

Callback接口是Handler的內部接口。用來實例化handler避免本身生成handler子類的麻煩。線程

須要注意的幾點code

1.Looper.prepare();和Looper.loop();都是在run方法中執行。

2.handler.post(runnable);必須寫在Looper.loop();方法前面,不然沒有效果。

3.在runnable中能夠屢次調用handler.sendMessage(handler.obtainMessage(1));只是Message.what值不一樣就能夠發送不一樣的消息。在handleMessage中handler就能夠根據what值對不一樣的消息分別處理。

4.不要忘記了調用thread.start();方法。

下面說說handlerThread,其自己帶有消息隊列因此就不要像通常線程那樣調用Looper.prepare等方法了。下面是例子代碼:

package com.example.handlerdemo2;

import android.R.integer;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;

public class MainActivity extends Activity {

	private ProgressBar progressBar;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		Button button=(Button) findViewById(R.id.button1);
		button.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				//參數爲線程的名字可經過getName返回。
				HandlerThread handlerThread=new HandlerThread("handlerthread");
				handlerThread.start();
				Handler handler=new Handler(handlerThread.getLooper(),new Handler.Callback() {
					
					@Override
					public boolean handleMessage(Message msg) {
						// TODO Auto-generated method stub
						try {
							//經過讓線程休眠16秒沒有報錯,能夠驗證該是一個獨立於主線程的線程。能夠在此處理耗時操做。
							Thread.sleep(16000);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						switch (msg.what) {
						case 1:
							System.out.println("這是message1發來的消息");
							//此處獲得的名字就是初始化handlerThread時裏面的參數
							System.out.println("thread name is---->"+Thread.currentThread().getName());
							break;

						case 2:
							System.out.println("這是message2發來的消息");
							System.out.println("thread name is---->"+Thread.currentThread().getName());
							break;
						}
							
						
						return true;
					}
				});
				//能夠經過hanler獲得不一樣的Message從而在handleMessage方法中對消息進行分別處理。
				Message message1=handler.obtainMessage(1);
				Message message2=handler.obtainMessage(2);
				message2.sendToTarget();
				message1.sendToTarget();
				
			}
		});
		
	}

}
其就將對Looper的處理交由handlerThread處理了本身就不用管了,方便了一些。該方法中handler的聲明使該handler綁定到handlerthread的looper所在的消息隊列中去了。
相關文章
相關標籤/搜索