android 再论 Handler
一、ThreadLocal的分析:
从字面上这个Threadlocal很容易让人引起误解,认真是一个本地 thread,实际上这是一个Thread的本地信息变量,也就是说用来存储线程中不安全变量的一个机制。分析如下:
ThreadLocal类接口很简单,只有4个方法,我们先来了解一下:
void set(Object value)
设置当前线程的线程局部变量的值。
· public Object get()
该方法返回当前线程所对应的线程局部变量。
· public void remove()
将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
protected Object initialValue()
返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。
对于每个线程,同名的变量,我们可以新建一个实例,并以Thread.currentThread为key保存到ThreadLocal中。当我们用到的时候,通过get()获取。
对于Handler,通常存的是 mLooper
二、Handler究竟是运行在子线程还是主线程
来看看Handler的构造函数,这里面有一个变量进行如下操作:
mLooper = Looper.myLooper();
上面的调用实际是如下操作:
public static Looper myLooper() {
return sThreadLocal.get();
}
也就是获取当前线程的Looper,这样看来,Handler运行环境不是确定的,而是在哪个线程创建这个handler,在主线程创建就运行在主线程,否则就是子线程。
三、如何正确启动一个子线程:
//在主线程先创建一个HandlerThread
HandlerThread mHandlerThread = new HandlerThread("XXX");
//第二步,是创建一个自己的Looper
mHandlerThread.start();
创建一个继承自Handler的子类,将上面创建的Looper赋给这个子类,在创建的时候,这样,我们就是创建一个不是运行在主线程的子线程了。否则,默认的是使用启动Handler的线程的Looper。
class myThread extends Handler {
public myThread (Looper looper) {
super(looper);
}
public myThread() {
super();
}
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch (msg.what) {
case 1:
try {
Thread.sleep(20* 1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
}
}
//初始化
mHandlerThread = new HandlerThread("handler");
mHandlerThread.start();
//创建子线程
mHandler = new myThread(mHandlerThread.getLooper());
四、IntentService
IntentService继承自Service,它能够在后台运行不阻塞主线程主要归于它内部开启一个工作线程,也就是创建一个继承自Handler的ServiceHandler,只是这个handler的looper是新创建的,不同于主线程的Looper,因而不会阻塞主线程。
public abstract class IntentService extends Service {
}
当我们通过Intent启动一个IntentService的时候,先进入onCreate:
public void onCreate() {
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
是不是通过HandlerThread先创建一个Looper,然后将这个Looper赋给工作线程ServiceHandler
启动好IntentService之后,我们开始
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
ServiceHandler的函数中有处理消息的机制,这里就调用onHandleIntent进行处理
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
五、如何销毁线程
1、销毁Handler:
由上面我们知道:我们开启一个子线程重要的依据在于要创建一个HandlerThread,在这里会新建一个Looper,然后通过它进行处理Message。那么在退出时如下处理:
onDestroy() {
super.onDestroy();
//将HandlerThread的looper.quit,下面应该是实例调用quit(此处不考虑语法问题)
HandlerThread.quit();
}
对于以Handler.post(Runnable)形式发送Message的方式,在上面函数中应该是:
Handler.removeCallbacks(mRunnable);
2、销毁Thread
目前是通过:设置一个全局变量,在退出时将这个变量设置为true,thread中判断到这个值为true时退出thread的循环。
作者:kakaBack
补充:移动开发 , Android ,