【Android】Android中的線程(Thread+Handler)

之前po了一篇文章:【Android】Android中的線程(AsyncTask),現在說說Android中實現多線程的另一種方法Thread+Handler,博主這種方法用得不多,主要通過這篇文章學習Android異步處理一:使用Thread+Handler實現非UI線程更新UI界面,再次特別感謝這篇文章的博主。

 

Thread+Handler

要通過Thread實現多線程,通常先寫一個類繼承Runnable,實現run()方法,在裏面做子線程要執行的任務。在博主上篇文章裏寫到過“不能在UI Thread之外的線程當中操縱UI元素”,如果子線程需要更改UI,就要藉助Handler實現:寫一個類繼承Handler,實現handleMessage(Message)方法,這個方法運行在UI Thread中。在子線程的run()方法中,調用handler.sendMessage()方法將一些數據信息傳給Handler,handleMessage(Message)根據不同數據做出不同處理,更改UI。

Thread+Handler與AsyncTask的對比

在網上查了一些探討這兩種方法的文章,因爲博主目前用到多線程的地方都比較簡單,這些文章中的有些代碼沒有實驗,僅在這裏mark下來,以備不時之需。

1. Android多線程任務優化1:探討AsyncTask的缺陷:這篇文章中博主通過一個例子說明了,當新開大量線程時,AsyncTask可能存在消耗系統資源、導致應用FC的風險,因此需要我們根據自己的需求自定義不同的線程池。在Android多線程任務優化2:實現後臺預讀線程這篇文章裏給出瞭解決辦法。

2. 深入解析AsyncTask:這篇文章中博主給出了一些使用選擇Thread+Handler/AsyncTask的建議,並且給出了自己的代碼參考。

  • 改善你的設計,少用異步處理:線程的開銷是非常大的,同時異步處理也容易出錯,難調試,難維護,所以改善你的設計,儘可能的少用異步。對於一般性的數據庫查詢,少量的I/O操作是沒有必要啓動線程的。
  • 如果不與主線程通信,就用ThreadAsyncTask被設計出來的目的就是爲了滿足Android的特殊需求:非主線程不能操作(UI)組件,所以AsyncTask擴展Thread增強了與主線程的交互的能力。如果你的應用沒有與主線程交互,那麼就直接使用Thread就好了。
  • 當有需要大量線程執行任務時,一定要創建線程池:線程的開銷是非常大的,特別是創建一個新線程,否則就不必設計線程池之類的工具了。當需要大量線程執行任務時,一定要創建線程池,無論是使用AsyncTask還是Thread,因爲使用AsyncTask它內部的線程池有數量限制,可能無法滿足需求;使用Thread更是要線程池來管理,避免虛擬機創建大量的線程。比如從網絡上批量下載圖片,你不想一個一個的下,或者5個5個的下載,那麼就創建一個CorePoolSize爲10或者20的線程池,每次10個或者20個這樣的下載,即滿足了速度,又不至於耗費無用的性能開銷去無限制的創建線程。
  • 對於想要立即開始執行的異步任務,要麼直接使用Thread,要麼單獨創建線程池提供給AsyncTask:默認的AsyncTask不一定會立即執行你的任務,除非你提供給他一個單獨的線程池。如果不與主線程交互,直接創建一個Thread就可以了,雖然創建線程開銷比較大,但如果這不是批量操作就沒有問題。

下面以博主最近自己在寫的一個程序爲例,po一下使用Thread+Handler的基本代碼。

=====================================華麗麗的分割線===================================

功能描述:

與博主上一篇文章一樣,某個Activity需要解析xml文件,並將解析結果展示在界面上,解析xml的工作比較耗時,需要在Worker Thread中執行。

具體分析:

  • run():中解析出想要的xml信息,將該信息通過handler.sendMessage()方法傳給Handler。
  • handleMessage(Message):根據傳來的的信息修改UI界面。

根據以上分析,首先在Activity裏增加一個繼承Runnable的類和一個繼承Handler的類。

/**
 * 解析xml文件的線程
 */
private class PaperRunnable implements Runnable
{
	private PaperParser parser;
	private FileInputStream in;
	
	private PaperRunnable(String file)
	{//初始化一些相關變量
		......
	}
	
	@Override
	public void run()
	{
		String stringTemp="";
		for(int i=numOfPaper;i>0&&mRunning==true;i--)
		{
			stringTemp=parser.queryThePaper(i);
			//將解析出的數據傳給Handler,MSG_PAP是標誌數據種類的靜態變量
			ppHandler.obtainMessage(MSG_PAP,i+"@@"+stringTemp).sendToTarget();
		}	
		try
		{
			in.close();
		} catch (IOException e)
		{
			e.printStackTrace();
		}
	}
}

/**
 * 處理xml解析結果的Handler
 */
private class PaperHandler extends Handler
{
	@Override
	public void handleMessage (Message msg)
	{//此方法在UI線程運行
		switch(msg.what)
		{
			case MSG_PAP://對於標誌了MSG_PAP的數據進行下面的處理
				//addPaper是將字符串顯示在界面上的方法
				addPaper(((String)msg.obj).split("@@"));
				break;
		}
	}
}

要開啓子線程,先要在Activity中聲明兩個變量

private ThreadmThread;
privatePaperRunnable ppRunnable==new PaperHandler();

開啓線程時

if(mThread==null)
{
          ppRunnable=newPaperRunnable(auth+".xml");
          mThread = new Thread(ppRunnable);
          mThread.start();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章