編輯:Android開發實例
希望和我一樣正在學習android的新手可以通過這篇文章熟悉android線程的交互,以及使用方法。以便將來更好的在自己的程序中運用。也希望大家保持學習android的積極性,一起努力、交流、成長,因為文章比較長 大家可以分幾次閱讀。這篇文章包含了好幾個例子,我之所把它們寫在一起,是覺得它們有一定聯系。
好吧我們開始讓 我們先從android進程說起吧。
當一個程序第一次啟動的時候,Android會啟動一個LINUX進程和一個主線程。默認的情況下,所有該程序的組件都將在該進程和線程中運行。同時,Android會為每個應用程序分配一個單獨的LINUX用戶。Android會勁量保留一個正在運行進程,只在內存資源出現不足時,Android會參試停止一些進程從而釋放足夠的資源給其他新的進程使用, 也能保證用戶正在訪問的當前進程有足夠的資源去及時的響應用戶的事件。Android會 根據進程中運行的組件類別以及組件的狀態來判斷該進程的重要性,Android會 首先停止那些不重要的進程。按照重要性從高到低一共有五個級別:
l 前台進程
前台進程是用戶當前正在使用的進程。只有一些前台進程可以在任何時候都存在。他們是最後一個被結束的,當內存低到根本連他們都不能運行的時候。一般來說, 在這種情況下,設備會進行內存調度,中止一些前台進程來保持對用戶交互的響應。
l 可見進程
可見進程不包含前台的組件但是會在屏幕上顯示一個可見的進程是的重要程度很高,除非前台進程需要獲取它的資源,不然不會被中止。
l 服務進程
運行著一個通過startService() 方法啟動的service,這個service不屬於上面提到的2種更高重要性的。service所在的進程雖然對用戶不是直接可見的,但是他們執行了用戶非常關注的任務(比如播放mp3,從網絡下載數據)。只要前台進程和可見進程有足夠的內存,系統不會 回收他們。
l 後台進程
運行著一個對用戶不可見的activity(調用過 onStop() 方法).這些進程對用戶體驗沒有直接的影響,可以在服務進程、可見進程、前台進 程需要內存的時候回收。通常,系統中會有很多不可見進程在運行,他們被保存在LRU (least recently used) 列表中,以便內存不足的時候被第一時間回收。如果一個activity正 確的執行了它的生命周期,關閉這個進程對於用戶體驗沒有太大的影響。
l 空進程
未運行任何程序組件。運行這些進程的唯一原因是作為一個緩存,縮短下次程序需要重新使用的啟動時間。系統經常中止這些進程,這樣可以調節程序緩存和系統緩 存的平衡。
Android 對進程的重要性評級的時候,選取它最高的級別。另外,當被另外的一個進程依賴的時候,某個進程的級別可能會增高。一個為其他進程服務的進程永遠不會比被服 務的進程重要級低。因為服務進程比後台activity進程重 要級高,因此一個要進行耗時工作的activity最好啟動一 個service來做這個工作,而不是開啟一個子進程――特別 是這個操作需要的時間比activity存在的時間還要長的時 候。例如,在後台播放音樂,向網上上傳攝像頭拍到的圖片,使用service可 以使進程最少獲取到“服務進程”級別的重要級,而不用考慮activity目 前是什麼狀態。broadcast receivers做費時的工作的時候,也應該啟用一個服務而不是開一個線程。
2單線程模型
當一個程序第一次啟動時,Android會同時啟動一個對應的 主線程(Main Thread),主線程主要負責處理與UI相關的事件,如:用戶的按鍵事件,用戶接觸屏幕的事件以及屏幕繪圖事 件,並把相關的事件分發到對應的組件進行處理。所以主線程通常又被叫做UI線 程。在開發Android應用時必須遵守單線程模型的原則: Android UI操作並不是線程安全的並且這些操作必須在UI線程中執行。
單線程模型會在沒有考慮到它的影響的情況下引起Android應用程序性能低下,因為 所有的任務都在同一個線程中執行,如果執行一些耗時的操作,如訪問網絡或查詢數據庫,會阻塞整個用戶界面。當在執行一些耗時的操作的時候,不能及時地分發 事件,包括用戶界面重繪事件。從用戶的角度來看,應用程序看上去像掛掉了。更糟糕的是,如果阻塞應用程序的時間過長(5秒鐘)Android會向用戶提示一些信息,即打開一個“應用程序沒有相應(application not responding)”ANR 的對話框。
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/textview01" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <Button android:id="@+id/myButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/textview01" android:text="異常測試" /> <TextView android:id="@+id/myTextView" android:textSize="15pt" android:layout_toRightOf="@id/myButton" android:layout_alignTop="@id/myButton" android:textColor="#FF0000" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </RelativeLayout>
Activity01 類
package xiaohang.zhimeng; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class Activity01 extends Activity { private Button myButton; private TextView myTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); myButton = (Button) findViewById(R.id.myButton); myTextView = (TextView) findViewById(R.id.myTextView); myButton.setOnClickListener(new MyButtonListener()); } class MyButtonListener implements OnClickListener { @Override public void onClick(View v) { new Thread() { @Override public void run() { // 我們在這裡更新了UI 設置了TextView的值 myTextView.setText("張三"); } }.start(); } } }
接下來我們以看圖片的方式 看看這是怎樣的一個異常。請大家點擊圖片查看大圖
Handler的主要的方法有:
好了示例演示時間到了。示例名稱:線程交互
好了下邊我們來看布局文件 一共有2個布局文件 一個是用來定義我們的布局我這裡用的是相對布局 RelativeLayout 下邊是main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:background="@drawable/bg0" android:layout_height="fill_parent"> <TextView android:id="@+id/textview01" android:textColor="#FF0000" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <Button android:id="@+id/myButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/textview01" android:background="@drawable/newbtn" /> <TextView android:id="@+id/myTextView" android:textSize="15pt" android:layout_toRightOf="@id/myButton" android:layout_alignTop="@id/myButton" android:textColor="#FF0000" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <Button android:id="@+id/myButton01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/myButton" android:text="開始" /> <Button android:id="@+id/myButton02" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/myButton01" android:layout_marginLeft="10px" android:layout_alignTop="@id/myButton01" android:text="停止" /> <TextView android:id="@+id/textview2" android:textSize="15pt" android:layout_below="@id/myTextView" android:layout_toRightOf="@id/myButton02" android:layout_alignTop="@id/myButton02" android:textColor="#385E0F" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </RelativeLayout>
那麼另外一個xml文件就是用來定義程序的第一個按鈕的圖片轉換效果。這個怎麼實現等這個例子講解完了,會給大家做一個簡單的說明。這個文件的名字是 newbtn.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:drawable="@drawable/im1"/> <item android:state_focused="true" android:drawable="@drawable/im2"/> <item android:drawable="@drawable/im3"/> </selector>
下面就是這2個類了 先來看看我們的音樂服務類 MusicService這個類比較簡單。
package xiaohang.zhimeng; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.os.IBinder; public class MusicService extends Service{ //MediaPlayer對象 private MediaPlayer player; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } public void onStart(Intent intent, int startId){ super.onStart(intent, startId); //這裡可以理解為裝載音樂文件 player = MediaPlayer.create(this, R.raw.test); //開始播放 player.start(); } public void onDestroy(){ super.onDestroy(); //停止音樂-停止Service player.stop(); } }
在來看我們實現線程交互的這個Activity02類 看看它是怎麼完成 子線程與UI線程的交互的
package xiaohang.zhimeng; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class Activity02 extends Activity { private Button myButton;//這個按鈕就是我們的第一個按鈕就是實現了圖片變換的那個按鈕 private Button myButton01;//這個按鈕是用來開啟音樂服務的 private Button myButton02;//這個按鈕用來停止音樂服務 //myTextView 由myButton控制這個TextView用來顯示"android小子" textView由myButton01控制這個TextView用來顯示音樂名稱 private TextView myTextView, textView; // 得到主線程的Looper對象 Looper looper = Looper.myLooper(); // 這個myHandler由主線程創建所以它與主線程關聯 MyHandler myHandler = new MyHandler(looper); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //設置我們的布局文件 setContentView(R.layout.main); //得到我們的Button 按鈕對象 和 TextView對象 myButton02 = (Button) findViewById(R.id.myButton02); myButton = (Button) findViewById(R.id.myButton); myTextView = (TextView) findViewById(R.id.myTextView); myButton01 = (Button) findViewById(R.id.myButton01); textView = (TextView) findViewById(R.id.textview2); myButton.setOnClickListener(new MyButtonListener()); myButton02.setOnClickListener(new MyButton02Listener()); //給我們的myButton按鈕設置監聽器 myButton01.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { new Thread() { @Override public void run() { System.out.println("the thread id is " + Thread.currentThread().getId()); System.out.println("the thread name is" + Thread.currentThread().getName()); //獲取我們資源文件裡邊的音樂名稱 因為連路徑也獲取了 所以這裡截取了一下 String tmusicName = getResources().getString( R.raw.music_name); int b = tmusicName.lastIndexOf("/"); int e = tmusicName.lastIndexOf("."); String musicName = tmusicName.substring(b + 1, e); // String musicName = // getResources().getResourceName(R.raw.test); /** 定義消息對象 並且賦予內容 最後發送給UI線程 *這裡這個方法要說明一下 myHandler.obtainMessage()-->obtainMessage這個方法用來獲得消息對象 *但是這個消息對象會關聯調用它的Handler對象。所以就會關聯myHandler對象 而這個myHandler對象是在UI線程裡邊創建的 * 所以很顯然我們這消息會發給主線程的消息隊列 我想這對大家來說根本沒有任何難度 */ Message message = myHandler.obtainMessage(); message.obj = musicName; //這裡這個 arg1 是Message對象攜帶的參數我主要用它來區分消息對象(Message) message.arg1 = 2; //把消息發送給目標對象,目標對象就是 myHandler 就是關聯我們得到的那個消息對象的Handler message.sendToTarget(); //開啟音樂服務 startService(new Intent( "xiaohang.zhimeng.Android.MUSIC")); } //啟動線程 }.start(); } }); } // myButton02按鈕的監聽器 class MyButton02Listener implements OnClickListener { @Override public void onClick(View v) { new Thread() { @Override public void run() { System.out.println("this thread id is " + Thread.currentThread().getId()); System.out.println("this thread name is " + Thread.currentThread().getName()); // 停止Service stopService(new Intent("xiaohang.zhimeng.Android.MUSIC")); } }.start(); } } // myButton監聽器 這個按鈕用來設置 myTextView 的值 顯示 或 隱藏 有2種狀態 class MyButtonListener implements OnClickListener { @Override public void onClick(View v) { CharSequence test_View = myTextView.getText(); String str = test_View.toString(); // 當myTextView上邊顯示的文本不等於空的時候 if (!(str.trim().equals(""))) { String str1 = ""; CharSequence charsq = str1; myTextView.setText(charsq); } else { Runnable r = new Runnable() { public void run() { Message message = myHandler.obtainMessage(); message.arg1 = 1; message.obj = "android小子"; message.sendToTarget(); System.out.println("name is " + Thread.currentThread().getName()); System.out.println("id is " + Thread.currentThread().getId()); } }; Thread thread = new Thread(r); thread.start(); } } } //MyHandler繼承Handler類 用過覆寫handlerMessage方法 來處理發給附屬於UI線程的消息隊列的消息 class MyHandler extends Handler { public MyHandler() {} public MyHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { if (msg.arg1 == 1) { CharSequence xh_msg = (CharSequence) msg.obj; myTextView.setText(xh_msg); } else if (msg.arg1 == 2) { CharSequence xh2_msg = (CharSequence) msg.obj; textView.setText(xh2_msg); } } } }
例子的運行效果大家就下載源碼自行測試吧。
public abstract class AsyncTask<Params, Progress, Result> {}
在把execute方法的源碼 貼上來供大家參考 。
public final AsyncTask<Params, Progress, Result> execute(Params... params) { if (mStatus != Status.PENDING) { switch (mStatus) { case RUNNING: throw new IllegalStateException("Cannot execute task:" + " the task is already running."); case FINISHED: throw new IllegalStateException("Cannot execute task:" + " the task has already been executed " + "(a task can be executed only once)"); } } mStatus = Status.RUNNING; onPreExecute(); mWorker.mParams = params; sExecutor.execute(mFuture); return this; }
這個類判斷哪裡我也不知道它在做什麼沒有繼續往下深入的研究 內力不足。 顯然這個類返回一個AsyncTask實例。 這裡我要提醒大家的的是 onPreExecute();方法 就是告知大家這個前置方法是什麼時候執行的 當執行這個方法的時候 AsyncTask的工作流程就開始了。這裡我沒有用到這個方法就沒有重寫了。但是大家一定要知道有這麼一個方法 ,它可以用來做一些准備和初始化的工作。剛才說到它的工作流程其實就是 這幾個方法的執行順序我就以圖片的形式告知大家。 讓大家明白它們相互之間的執行順序,這裡一定一定 要搞清楚。又得點擊大圖查看圖片了。
好了我們來看例子 我們這個例子 與上一個例子實現的效果是一樣的所以這裡就不貼運行效果了。其實 是稍微有些不同的 有2點不同 上邊那個例子 我們的第一個按鈕 第一個按鈕就是最上邊的那個按鈕 剛開始是沒有顯示TextView 我們點擊第一個按鈕就會顯示TextView並且會開啟一個線程來執行 當我們再點擊的時候 TextView沒有值了 但是我們 這次點擊並不會另外開啟一個線程。 而我們這個例子會。第一個例子(線程交互) 就是顯示TextView值的時候就會開啟一個線程。當我們把TextView的值 置空的時候不會開啟另外一個線程來執行。
第二點區別就是 我們這個例子 點擊停止按鈕之後 我們的音樂名也消失。其實也是把TextView顯示的值 置空了。 下面我們就來看看這個例子 因為布局都是一樣的 我在這裡就只貼出了2個類。 大家可以下載源碼進行測試。
示例名稱 :線程交互AsyncTask版
package xiaohang.zhimeng; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.os.IBinder; public class MusicService extends Service{ //MediaPlayer對象 private MediaPlayer player; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } public void onStart(Intent intent, int startId){ super.onStart(intent, startId); //這裡可以理解為裝載音樂文件 player = MediaPlayer.create(this, R.raw.test); //開始播放 player.start(); } public void onDestroy(){ super.onDestroy(); //停止音樂-停止Service player.stop(); } }
Activity02類
package xiaohang.zhimeng; import android.app.Activity; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class Activity02 extends Activity { public static String ARGS1; private Button myButton; private Button myButton01; private Button myButton02; private TextView myTextView, textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); myTextView = (TextView) findViewById(R.id.myTextView); textView = (TextView) findViewById(R.id.textview2); myButton01 = (Button) findViewById(R.id.myButton01); myButton02 = (Button) findViewById(R.id.myButton02); myButton = (Button) findViewById(R.id.myButton); myButton.setOnClickListener(new MyButtonListener()); myButton02.setOnClickListener(new MyButton02Listener()); myButton01.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { String arg2 = Activity02.ARGS1 = "2"; new task().execute(arg2); } }); } // myButton02按鈕的監聽器 class MyButton02Listener implements OnClickListener { @Override public void onClick(View v) { String arg3 = Activity02.ARGS1 = "3"; new task().execute(arg3); } } //此類繼承AsyncTask private class task extends AsyncTask<String,String, String>{ //開啟另外一個線程執行任務 @Override protected String doInBackground(String...params) { System.out.println("the thread ID is " + Thread.currentThread().getId()); System.out.println("the thread NAME is " + Thread.currentThread().getName()); String test = params[0]; System.out.println("test value is " + test); if (params[0] == "1") { String arg1 = params[0]; return arg1; }else if(params[0] == "2"){ //開啟音樂服務 startService(new Intent( "xiaohang.zhimeng.Android.MUSIC")); //獲取參數值 String arg2 = params[0]; return arg2; }else if (params[0] == "3") { //停止音樂服務 stopService(new Intent("xiaohang.zhimeng.Android.MUSIC")); //獲取參數值 String arg3 = params[0]; return arg3; }else { System.out.println("param post error---->"); } return null; } //執行完成後傳送結果給UI線程 此方法最後執行 protected void onPostExecute(String result) { CharSequence test_View = myTextView.getText(); String str = test_View.toString(); // 當不等於空的時候 if (!(str.trim().equals(""))) { String str1 = ""; CharSequence charsq = str1; myTextView.setText(charsq); } else { if (result == "1") { //將 myTextView 賦值成 "android小子" String string = "android小子"; myTextView.setText(string); }else if(result == "2"){//result等於2說明是myButton01那個按鈕也就是開啟音樂服務的那個開始按鈕 //獲取資源文件裡邊的音樂名稱 String tmusicName = getResources().getString(R.raw.test); int b = tmusicName.lastIndexOf("/"); int e = tmusicName.lastIndexOf("."); //截取歌曲名稱 String music_Name = tmusicName.substring(b+1, e); System.out.println("music name is " + music_Name); // 在textView上顯示歌曲名稱 textView.setText(music_Name); }else if(result == "3"){ String str_none = ""; CharSequence csq = str_none; textView.setText(csq); }else { System.out.println("param post error"); } } } } // myButton監聽器 這個按鈕用來 顯示和隱藏 值為"android小子"這個TextView public class MyButtonListener implements OnClickListener { @Override public void onClick(View v) { System.out.println("wo zhen de zhixing fou???"); //給靜態變量賦值 String arg1 = Activity02.ARGS1 = "1"; new task().execute(arg1); } } }
運行效果大家就得下載源碼運行了,程序有裡邊System.out 的輸出我用來查看一些操作是在那些線程中執行的。大家可以自行過濾。我配置的System.out如下圖所示
package xiaohang.zhimeng; import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.SystemClock; import android.widget.TextView; import android.widget.Toast; /** * 一個使用異步任務的例子。一般來說一個異步任務只執行一次,這個例子有點非主流,任務結束後會觸發下一次任務執行。 * 由任務task在屏幕上打印數字,第一次任務執行由主Activity的onCreate觸發,每次任務結束後 * 設定下一次觸發的時間,共執行5次。對於任務來說doInBackground()接收任務的參數params,並執行產生數字的動作,每一個數字 * 產生後調用一次publishProgress()來更新UI,這個函數本身也是異步的只是用來發個消息調用完成後立即返回, * 而產生數字的動作在繼續進行。更新界面的操作在onProgressUpdate()中設定。 所有的on函數都由系統調用,不能用戶調用。 * 代碼中使用Handler是為了能觸發任務執行,android規定這種異步任務每次執行完就結束,若要重新執行需要new一個新的。 * 異步任務只能在UI線程裡面創建和執行 */ public class testAsync extends Activity { private final int MSG_TIMER = 10000; private TextView vText = null; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.test); vText = (TextView) findViewById(R.id.TextView01); vText.setText("Num..."); new task().execute("->"); } // 接收任務task發來的消息,觸發一個新的任務 private final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); System.out.println("Handler name -----------> " + Thread.currentThread().getName()); System.out.println("Handler id ------------> " + Thread.currentThread().getId()); switch (msg.what) { case MSG_TIMER: new task().execute("->"); break; } } }; // 任務執行次數 private static int times = 1; // AsyncTask<>的參數類型由用戶設定,這裡設為三個String // 第一個String代表輸入到任務的參數類型,也即是doInBackground()的參數類型 // 第二個String代表處理過程中的參數類型,也就是doInBackground()執行過程中的產出參數類型,通過publishProgress()發消息 // 傳遞給onProgressUpdate()一般用來更新界面 // 第三個String代表任務結束的產出類型,也就是doInBackground()的返回值類型,和onPostExecute()的參數類型 private class task extends AsyncTask<String, String, String> { // 後台執行的耗時任務,接收參數並返回結果 // 當onPostExecute()執行完,在後台線程中被系統調用 @Override protected String doInBackground(String... params) { System.out.println("doInBackground name -----> " + Thread.currentThread().getName()); System.out.println("doInBackground id -----> " + Thread.currentThread().getId()); // TODO Auto-generated method stub // 在這裡產生數據,送給onProgressUpdate以更新界面 String pre = params[0]; System.out.println("pre is ----->" + pre); for (int i = 0; i < 5; i++) { System.out.println("note i am begin sleep "); publishProgress(pre + i); // 這裡是否需要停頓下 System.out.println("hua li de bu zhuo " + pre + i); SystemClock.sleep(1000); } return "任務結束"; } // 任務執行結束後,在UI線程中被系統調用 // 一般用來顯示任務已經執行結束 @Override protected void onPostExecute(String result) { // TODO Auto-generated method stub System.out.println("onPostExecute name --------> " + Thread.currentThread().getName()); System.out.println("onPostExecute id --------> " + Thread.currentThread().getName()); super.onPostExecute(result); Toast.makeText(testAsync.this, result, Toast.LENGTH_SHORT).show(); // 任務執行5次後推出 if (times > 5) { return; } // 設定下一次任務觸發時間 Message msg = Message.obtain(); msg.what = MSG_TIMER; handler.sendMessageDelayed(msg, 10000L); } // 最先執行,在UI線程中被系統調用 // 一般用來在UI中產生一個進度條 @Override protected void onPreExecute() { // TODO Auto-generated method stub System.out.println("onPreExecute id -------> " + Thread.currentThread().getId()); System.out.println("onPreExecute name -------> " + Thread.currentThread().getName() ); super.onPreExecute(); Toast.makeText(testAsync.this, "開始執行第" + times + "次任務: " + this, Toast.LENGTH_SHORT).show(); times++; } // 更新界面操作,在收到更新消息後,在UI線程中被系統調用 @Override protected void onProgressUpdate(String... values) { // TODO Auto-generated method stub System.out.println("onProgressUpdate id ---------> " + Thread.currentThread().getId()); System.out.println("onProgressUpdate name -------> " + Thread.currentThread().getName()); super.onProgressUpdate(values); vText.append(values[0]); } } }
這個例子來自eoe大家可以好好看看 每個回調方法它都用到了不錯的。還有在這裡建議大家去看看泛型的東西 我以前不會 也看了看。不然 自己用AsyncTask類的時候 那幾個方法的參數 會有些暈。我現在還有些暈,有時間一定要好好研究一下。然後接下來的就是多多練習了。
package mars.handler; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; public class HandlerTest2 extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.main); // 打印了當前線程的ID System.out.println("Activity-->" + Thread.currentThread().getId()); // HandlerThread這個類繼承了Thread // 生成一個HandlerThread對象,實現了使用Looper來處理消息隊列的功能,這個類由Android應用程序框架提供 // 這裡這個參數指定的是線程的名字 HandlerThread handlerThread = new HandlerThread("handler_thread"); // 在使用HandlerThread的getLooper()方法之前,必須先調用該類的start(); handlerThread.start();// 啟動這個線程 MyHandler myHandler = new MyHandler(handlerThread.getLooper()); // 這裡這個obtainMessage()方法返回 Message msg = myHandler.obtainMessage(); // 將msg發送到目標對象,所謂的目標對象,就是生成該msg對象的handler對象 Bundle b = new Bundle(); b.putInt("age", 20); b.putString("name", "Jhon"); msg.setData(b); msg.sendToTarget(); } class MyHandler extends Handler { public MyHandler() { } public MyHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { // 這裡我們只做了簡單的輸出 Bundle b = msg.getData(); int age = b.getInt("age"); String name = b.getString("name"); System.out.println("age is " + age + ", name is" + name); System.out.println("Handler--->" + Thread.currentThread().getId()); System.out.println("handlerMessage"); } } }
布局文件 啥都沒有就一個TextView 為了 維持完成也貼出來吧。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
</LinearLayout>
這裡有一些我學習的時候在網上參考的文章,大家也可以看看 ,重要的就是多練習了。
淺析Android線程模型http://www.cppblog.com/fwxjj/archive/2010/05/31/116787.html
Android線程模型(Painless Threading)http://www.cppblog.com/fwxjj/archive/2010/05/31/116788.html
有關Android線程的學習 http://android.blog.51cto.com/268543/343823
Android中Message機制的靈活應用http://qaohao.iteye.com/blog/509145
http://wghjay.iteye.com/blog/427086http://wghjay.iteye.com/blog/427086
這些我認為寫的還不錯,大家 也可以看看 多多學習總是好事。
下邊羅列我們源碼的下載地址 因為線程交互的那2個例子裡邊有一些資源文件所以會比較大eye傳不上來 ,我傳到趣盤了給大家下載。
xh_Android_Test_1_2_線程交互 下載地址 趣盤下載 http://hangvip.qupan.cc/6789636.html
XH_Android_Test_1_2_SyncTask_Demo_線程交互_AsyncTask版 http://hangvip.qupan.cc/6789683.html
Android_Test_01_AsyncTask_eoe 附件下載
建議大家用IE下載直接把鏈接復制到IE下載 然後點迅雷下載 如果沒安裝迅雷 會彈出普通的下載方式,而火狐 貌似 只能用迅雷下了 還有趣盤有很多廣告很惡心,大家忍住。
所有例子的測試平台 均為 android2.0 APILEVEL 5 下載鏈接已測試可用 ,如果大家發現不可以下載可以留言給我。
可以顯示在的Android任務,通過加載進度條的進展。進度條有兩種形狀。加載欄和加載微調(spinner)。在本章中,我們將討論微調(spinner)。Spinner 用
Android應用程序可以在許多不同地區的許多設備上運行。為了使應用程序更具交互性,應用程序應該處理以適合應用程序將要使用的語言環境方面的文字,數字,文件等。在本章中,我
我們知道,在Android系統中,Activity是以堆棧的形式組織在ActivityManagerService服務中的。與Activity類似,Android
本文實例講述了Android中數據庫常見操作。分享給大家供大家參考,具體如下: android中數據庫操作是非常常見了,我們會經常用到,操作的方法也有很多種形式,