對于Handler來說,它和與它調用它的Activity是出于同一線程的,上一篇并沒有調用線程
的start方法,而是直接執行的run方法。而啟動一個線程是調用的start方法
上一篇博客里的對Handler的調用時通過Runnable接口來實現的,并且是通過run()方法來啟動那個線程的,而且是Activity和 Handler是兩個線程獨立運行的,互補干擾,但是實際情況確實,Activity所在的線程和Handler的線程是同一個線程,下面進行一下實驗
Java代碼

- package org.hualang.handlertest3;
-
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.util.Log;
-
- public class HandlerTest3 extends Activity {
- private Handler handler = new Handler();
- private String TAG = "System.out";
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- handler.post(r);
- setContentView(R.layout.main);
- //Thread t = new Thread(r);
- //t.start();
-
- Log.d(TAG,"Activity id:"+Thread.currentThread().getId());
- Log.d(TAG,"Activity name:"+Thread.currentThread().getName());
-
- }
- Runnable r = new Runnable()
- {
- public void run()
- {
- Log.d(TAG,"Handler id:"+Thread.currentThread().getId());
- Log.d(TAG,"Handler name:"+Thread.currentThread().getName());
- try {
- Thread.sleep(5000);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- };
- }
運行結果:
證明是同一個線程的兩個依據:
①Activity的id或name和Handler的id或name是同樣的
②我設置了
handler.post(r);
setContentView(R.layout.main);
也就是,如果執行后馬上顯示文本信息,那么可以證明它們不在同一個線程,但是實際情況是要先執行了handler后5秒,才顯示文本信息,說明它們在同一線程


如果將代碼改為
Java代碼

- //handler.post(r);
- setContentView(R.layout.main);
- Thread t = new Thread(r);
- t.start();
再次執行,運行結果如下,通過start啟動線程,它們不在同一個線程中

----------------------------------------------------------------------------------------------------------------
Looper即循環的從隊列當中取得消息的功能,如果在線程中使用Looper
那么,就會循環的從線程隊列當中取得消息并處理,如果隊列當中沒有消息的話
,線程就進入了休眠狀態
Looper很少自己創建,在Android中給出了HandlerThread類,并且具有循環取得并處理消息的功能
下面來實現這種Activity和Handler分別在兩個線程中執行,實現真正的異步處理
Java代碼

- package org.hualang.handlertest;
-
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.HandlerThread;
- import android.os.Looper;
- import android.os.Message;
- import android.util.Log;
-
- public class HandlerTest4 extends Activity {
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- Log.d("System.out","Activity所在線程的id:"+Thread.currentThread().getId());
- /**
- * 生成一個HandlerThread對象,實現了使用Looper來處理消息隊列的功能
- * 這個類由Android應用程序框架提供
- */
- HandlerThread handlerThread = new HandlerThread("handlerThread");
- handlerThread.start();
- MyHandler handler = new MyHandler(handlerThread.getLooper());
- Message msg = handler.obtainMessage();
- /**
- * 將Message對象發送到目標對象
- * 所謂的目標對象,就是生成該msg對象的handler對象
- */
- msg.sendToTarget();
- }
- class MyHandler extends Handler
- {
- public MyHandler()
- {
- }
- public MyHandler(Looper looper)
- {
- super(looper);
- }
- public void handleMessage(Message msg)
- {
- Log.d("System.out", "handler所在線程的id:"+Thread.currentThread().getId());
- }
- }
- }
運行結果:

可以看到,Activity和Handler是在兩個不同的線程中執行的,這樣就是實現了真正的異步處理
1、首先創建一個HandlerThread對象,這個HandlerThread類實現了循環的取得消息并處理
2、用start方法啟動一個新線程
3、創建MyHandler類,里面傳遞的參數即Looper方法所獲得的可以循環在隊列中取得的消息
4、MyHandler類調用的是帶參數Looper的構造方法,并且實現了handlerMessage方法
5、獲取一個Message對象
6、將這個對象發送到生成該msg對象的handler對象,從而執行了handleMessage方法
-----------------------------------------------------------------------------------------------------
最后,將說一下Message里傳送的數據的使用,這里的msg對象可以使用arg1,arg2或者obj
arg1 and arg2 are lower-cost alternatives to using setData()
if you only need to store a few integer values. 也就是相對于setData()方法,如果你僅僅保存一些簡單的整形數的話,arg1,arg2對資源的要求較低,而setData()方法一般用于傳遞 大量數據的時候會用到
如果是msg.obj,那么可以這樣用
msg.obj = "Welcome to china";
然后在handleMessage()方法中用
String str = (String)msg.obj;來獲得傳遞的值
如果使用getData()方法的話,需要用到Bundle對象來傳遞,下面用個例子來說明
Java代碼

- Bundle b = new Bundle();
- b.putInt("age", 22);
- b.putString("name", "loulijun");
- msg.setData(b);
- msg.sendToTarget();
上面的代碼用來設置要傳遞的數據
下面的代碼用來獲取Bundle傳遞過來的數據并且用Toast來顯示
Java代碼

- Bundle b = msg.getData();
- int age = b.getInt("age");
- String name = b.getString("name");
- Toast toast = Toast.makeText(getApplicationContext(), "age="+age+"name="+name, Toast.LENGTH_LONG);
- toast.show();
package org.hualang.handlertest;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;
public class HandlerTest4 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d("System.out","Activity所在線程的id:"+Thread.currentThread().getId());
/**
* 生成一個HandlerThread對象,實現了使用Looper來處理消息隊列的功能
* 這個類由Android應用程序框架提供
*/
HandlerThread handlerThread = new HandlerThread("handlerThread");
/**
* 使用HandlerThread的getLooper()方法之前,必須先調用該類的start()方法,否則是個null,會報錯
*/
handlerThread.start();
MyHandler handler = new MyHandler(handlerThread.getLooper());
Message msg = handler.obtainMessage();
/**
* 將Message對象發送到目標對象
* 所謂的目標對象,就是生成該msg對象的handler對象
*/
//msg.obj = "Hello world";
Bundle b = new Bundle();
b.putInt("age", 22);
b.putString("name", "loulijun");
msg.setData(b);
msg.sendToTarget();
}
class MyHandler extends Handler
{
public MyHandler()
{
}
public MyHandler(Looper looper)
{
super(looper);
}
public void handleMessage(Message msg)
{
//String str = (String)msg.obj
Bundle b = msg.getData();
int age = b.getInt("age");
String name = b.getString("name");
Toast toast = Toast.makeText(getApplicationContext(), "age="+age+"name="+name, Toast.LENGTH_LONG);
toast.show();
Log.d("System.out", "handler所在線程的id:"+Thread.currentThread().getId());
}
}
}
運行結果:
