前面我们讲到了Looper和Handler,只是为了写这篇文章做铺垫,其实在前面的使用中,我们已经可以感觉到了一些局限性,我们怎样来自己写两个线程是它们直接进行通信呢?在看这篇文章之前,可以先看看Looper与Handler解析这篇文章。
实现通信也很简单,只是要使用Handler的另一个构造函数,在Handler中有另一个比较有用的构造函数:Handler(Looper looper),这样自己来指定Looper对象,那么Looper对象就可以在另一个线程中定义好,然后给Handler使用,就可以实现了,直接来看Handler源码:
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
我们可以为Handler指定Looper,也就是说我们可以为Handler发送的消息指定线程,我们可以单独的开一个线程A来进行消息队列的循环,在另一个线程B中或者其他的任何地方进行操作后,统一通过handler把消息发往线程A,来进行其他的一些操作,这样就可以把消息的处理统一用一个线程A来管理。而且这个线程是我们自己写的,也不影响主线程的运行。
下面直接给出一个小样例,这个小样例没有考虑内存泄漏的问题,暂且先忽略,关于内存泄漏的问题后面再单独讨论:
public class MainActivity extends Activity {
private Handler mHandler;
private MyThread mThread1;
//这个线程是专门用来处理消息队列里的消息的
//这个就是后面说的HandlerThread的精简版
class MyThread extends Thread{
Looper mLooper;
@Override
public void run() {
//它会创建一个Looper对象
Looper.prepare();
//这里可以直接得到这个Looper对象
mLooper = Looper.myLooper();
//进行消息队列循环
Looper.loop();
}
public Looper gerLooper(){
return mLooper;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mThread1 = new MyThread();
mThread1.start();
//在Handler中自己来指定前面开启的线程里的Looper
//这样就可以使用到上面那个线程里的消息队列
//如果还不明白就看我的上一篇文章:Looper与Handler解析
//这个直接定义了一个匿名类,也可以单独把它定义称一个类,后面IntentService里面就是单独定义了一个类
mHandler = new Handler(mThread1.gerLooper()){
@Override
public void handleMessage(Message msg) {
//接受消息进行处理
super.handleMessage(msg);
}
};
//在线程B执行完了,就可以发一条消息给线程A
Thread thread2 = new Thread(){
@Override
public void run() {
//执行耗时操作
//执行完后就发生消息
mHandler.sendEmptyMessage(0);
}
};
}
public void operate1(){
//执行操作
mHandler.sendEmptyMessage(0);
}
}
哈哈,说了这么多,其实只是为了说明HandlerThread的实现原理,因为早就有这样一个类来专门处理Handler消息,从名字HandlerThread也可以看出它是一个处理handler消息的线程。下面我就直接把HandlerThread的主要源码贴出来,基本跟上面MyThread一致,就是在这个基础上又加了点东西,主要原理都就这样,对照这看看,应该就明白了。
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
public int getThreadId() {
return mTid;
}
}
下面我们把上面的样例进行改动,直接使用HandlerThread替换我们写的MyYhread:
public class MainActivity extends Activity {
private Handler mHandler;
private HandlerThread mThread1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mThread1 = new HandlerThread("demo");
mThread1.start();
//在Handler中自己来指定前面开启的线程里的Looper
//这样就可以使用到上面那个线程里的消息队列
//这个直接定义了一个匿名类,也可以单独把它定义称一个类,后面IntentService里面就是单独定义了一个类
//这里先不考虑内存泄漏的问题
mHandler = new Handler(mThread1.gerLooper()){
@Override
public void handleMessage(Message msg) {
//接受消息进行处理
super.handleMessage(msg);
}
};
//在线程B执行完了,就可以发一条消息给线程A
Thread thread2 = new Thread(){
@Override
public void run() {
//执行耗时操作
//执行完后就发生消息
mHandler.sendEmptyMessage(0);
}
};
}
public void operate1(){
//执行操作
mHandler.sendEmptyMessage(0);
}
}
接下来我们要看的就是IntentService,大家都知道,虽然Service允许在后台,但是我们的耗时操作却并不能在Service中执行,因为Service和Activity一样都是运行在主线程,当然这样不考虑单独为它们指定进程。另外,当多次启动服务的时候,第一次启动会执行onCreate–onStartCommand,后面启动就会直接执行onStartCommand,这些都是基本知识。
下面有个测试代码:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("MainActivity", "activity onCreate() : " + Thread.currentThread().getId());
}
public void startMyService(View view){
Intent intent = new Intent(this,MyService.class);
startService(intent);
}
}
public class MyService extends Service {
public MyService() {
}
@Override
public void onCreate() {
Log.i("MyService","onCreate");
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("MyService", "onBind() : " + Thread.currentThread().getId());
Log.i("MyService","onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
}
废话好像说的有点多,既然Service不能执行耗时操作,那么如果我们需要在Service里面执行耗时操作怎么办,那就可以使用IntentService,它是一个异步处理Service,本身继承自Service,然后在内部加了个线程罢了。它的内部原理又离不开Looper和Handler:
当启动IntentService的时候,首先执行的当然就是onCreate操作:
@Override
public void onCreate() {
super.onCreate();
//看到没有,一上来就创建了一个HandleThread,对于HandleThread应该不陌生吧,上面刚刚讲过
//简单说就是一个线程里面定义了一个Looper对象,并且循环处理消息队列
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//得到上面HandlerThread线程中的Looper对象
mServiceLooper = thread.getLooper();
ServiceHandler就是一个handler,上面小样例我们定义的是一个匿名类,这里单独定义了一个类
mServiceHandler = new ServiceHandler(mServiceLooper);
}
这里把ServiceHandler也拿出来看看:
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
在上面的小样例中,我是这样定义的,
mHandler = new Handler(mThread1.gerLooper()){
@Override
public void handleMessage(Message msg) {
//接受消息进行处理
super.handleMessage(msg);
}
};
对照看看,它们其实是一样的,另外需要注意的是,它在handleMessaage中执行了一个onHandleIntent((Intent)msg.obj),而onHandleIntent是我们需要重载的函数,我们在创建一个MyIntentService来继承IntentService的时候,需要重载这个方法来执行我们的耗时操作,也就是说,我们的耗时操作是在HandleThread这线程中执行的。下面要解决的就是什么时候会执行这个函数,这点想必你已经清楚了,就是必须让handler发一个消息过来,从handleMessage这个函数来看,消息msg的obj对象里存放的是Intent,接着往下看,下面执行的就是onStart了。
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
看到没有,在onStart里面直接把intent放到消息里面,发送出去了,这样我们的耗时操作就放在了另一个线程中,Service做的就是通知HandlerThread线程来进行处理。
因为Service可以多次被启动,每次被启动都会执行onStart方法,这样每次startService都会往HandlerThread线程里面发一个消息,让线程了执行相应的操作,多么完美的设计。
下面我就提供一个小例子程序吧:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void startMyService1(View view){
Intent intent = new Intent(this,MyService.class);
intent.setAction("Operator_A");
startService(intent);
}
public void startMyService2(View view){
Intent intent = new Intent(this,MyService.class);
intent.setAction("Operator_B");
startService(intent);
}
}
public class MyService extends IntentService {
public MyService(){
super("MyService");
}
@Override
protected void onHandleIntent(Intent intent) {
String action = intent.getAction();
if(action.equals("Operator_A")){
Log.i("MyService","Operator_A");
}else if(action.equals("Operator_B")){
Log.i("MyService","Operator_B");
}
}
}
程序很简单,但看到这个程序之后,应该知道了它内部是怎样实现的吧,这样就可以大胆的来使用了。