一、Handler与线程
Handler与使用这个Handler的Activity是处在同一个线程中的。Handler并不会调用线程的start方法,而是直接调用线程的run方法。编写线程程序的时候一般可以实现Runnable接口,或者继承Thread类,无论哪种方法都会重写run方法,但是启动线程的时候并不是调用run方法,而是调用start方法。所以,Handler直接调用run方法,则说明并没有启动新的线程,而是还在当前的线程当中。
测试实例:
HandlerActivity.java
package com.android.activity;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
public class HandlerActivity extends Activity {
private Handler handler = new Handler();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler.post(r);
setContentView(R.layout.main);
System.out.println("Activity --> "+Thread.currentThread().getId());
System.out.println("Activity --> "+Thread.currentThread().getName());
}
Runnable r = new Runnable(){
public void run() {
System.out.println("Handler --> "+Thread.currentThread().getId());
System.out.println("Handler --> "+Thread.currentThread().getName());
try{
Thread.sleep(5000);
}catch(Exception e){
e.printStackTrace();
}
}
};
}
在这个例子中,在run方法和onCreate方法中,分别打印出当前线程的id和name,同时在run方法中休眠5000ms,并且将
handler.post(r);
这句代码写在
setContentView(R.layout.main);
就是为了验证Handler和Activity是否是处在同一个线程中。
如果handler与Activity不是在同一个线程中,则handler调用的run方法执行sleep的时候,Activity的界面直接就会显示出来,如果是在同一个线程中的话,则会延迟5秒之后才显示出来。这样很容易证实Handler与使用这个Handler的Activity是处在同一个线程中的。
输出结果:
二、Bundle的用法
Bundle是一个以String类型为键,可以是其他类型为值的映射。是一个数据存储工具,类似于Map,只不过键的类型是固定的。
BundleActivity.java
String name ="test bundle";
Bundle bundle = new Bundle();
bundle.putString("name", name);
Intent intent = new Intent(BundleActivity.this,OtherActivity.class);
intent.putExtras(bundle);
startActivity(intent);
OtherActivity.java
String name=(String) getIntent().getExtras().get("name");
三、在新线程当中处理消息的方法
由于Handler与使用这个Handler的Activity是处在同一个线程中的,但是平时使用Handler都是为了新开一个线程处理那些耗时长的操作,如数据下载等。如果不另起一个线程的话,当前的Activity就会没有反应,用户就不能够同时做一些其他操作。
为了解决上面的问题,就引入了Looper的概念。Looper是一个Android框架所提供的一个类,Looper提供了一种循环着从队列中取出消息这种功能。HandlerThread类实现Looper的功能,一般就使用HandlerThread实现循环处理消息功能。
例子程序:
HandlerActivity.java
package com.android.activity;
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 BundleActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
System.out.println("Activity --> "+Thread.currentThread().getId());
//生成一个HandlerThread对象,实现类使用Looper来处理消息队列的功能
HandlerThread handlerThread = new HandlerThread("handler_thread");
handlerThread.start();
MyHandler myHandler = new MyHandler(handlerThread.getLooper());
Message msg = myHandler.obtainMessage();
//每次发送消息对象的时候,都会调用handleMessage方法,发送到目标对象,哪一个Handler得到的message就会发送到哪
msg.sendToTarget();
}
class MyHandler extends Handler{
public MyHandler() {}
public MyHandler(Looper looper){
super(looper);
}
public void handleMessage(Message msg){
System.out.println("Handler --> "+Thread.currentThread().getId());
System.out.println("handlerMessage");
}
}
}
其中:
MyHandler myHandler = new MyHandler(handlerThread.getLooper());
MyHandler类有一个带参数的构造方法,构造方法传递一个looper,意味着当前这个handler使用looper所在的这个线程,来处理消息,也就是说将handler绑定到了looper所在的线程上,而不是Activity的线程了。
在使用getLoop()方法之前必须先调用该类的start()方法,否则getLooper()方法将得到空值。
另外:
Message有args1和args2两个成员变量,可以用来传递整型参数,相对于setDate()方法来说使用这两个参数消耗比较小。
Message还有obj这样一个变量,可以用来传递对象。
如果传递大量数据的话,可以使用Message的setDate方法。
Bundle bundle = new Bundle();
bundle.putInt("number",100);
bundle.putString("name","bauble");
msg.setDate();
msg.sendToTarget();
可以在handleMessage()方法中取出:
Bundle b = msg.getDate();
int number = b.getInt("number");
String name = b.getString("name");