处理线程中消息队列的方法目前我知道的分为种两种。一种是线程本身带有消息队列,如主线程和handlerThread,主线程不说了。handlerThread继承自thread但它与一般thread不同的地方是它有自己的消息队列。而一般线程(指自己创建的线程)在默认情况下没有和它相关的消息队列。要想使其有在运行消息队列的线程中调用Looper.prepare();方法。然后调用Looper.loop();去让消息队列中的消息挨个执行。如下所示:
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }
因为线程默认情况下是没有自己的消息队列的,所以如果在该线程的run()方法中新建handler后调用handler.post(runnable);程序会报错。但在run方法外调用就没事。因为thread类只是管理子线程的,其真正的子线程是在run方法中的。
自己写的例子如下:
package com.example.handlerdemo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.R.integer;
import android.app.Activity;
import android.view.Menu;
import android.view.TextureView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button start=(Button) findViewById(R.id.button1);
TextView textView=(TextView) findViewById(R.id.textView1);
start.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Thread thread=new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
Looper.prepare();
handler=new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch (msg.what) {
case 1:
System.out.println("thread name is"+" "+Thread.currentThread().getName());
break;
}
}
};
handler.post(runnable);
Looper.loop();
}
};
thread.start();
}
});
}
Runnable runnable=new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("这是runnable1");
handler.sendMessage(handler.obtainMessage(1));
}
};
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
System.out.println("looper绑定的线程是"+Looper.myLooper().getThread().getName());
Looper.myLooper().quit();
super.onDestroy();
}
}
其中onDestroy方法中结束looper有错误。其得到的是主线程的名字。会报错。疑问:在哪里结束Looper。有待研究。欢迎留言赐教。
handleMessage中打印出来的线程的名字是自己定义出来的线程的名字。而非主线程。而onDestroy方法中打印出来的是主线程的名字。且该处错误,不该在此处停止looper,此处疑问。
接近一年后再次回来看自己曾经的疑问,感觉那时自己好傻啊,这么明显的问题都没看出来。哎,看来自己还是进步了。窃喜。在onDestroy方法中停止的当然必须是当初的那个looper,而上文在onDestroy中quit的,是重新获得的当前线程(main)线程的looper,当然不是原来的,所以会报错啊。须将自己声明的线程中的Looper mLooper=Looper.myLooper();然后在onDestroy中直接mLooper.quit();就OK了。至于具体深入研究还需去看源码,加油吧,路上的孩子。
其中handler的还可以这样生成:
handler=new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
// TODO Auto-generated method stub
switch (msg.what) {
case 1:
System.out.println("thread name is"+" "+Thread.currentThread().getName());
break;
}
return true;
}
});
Callback接口是Handler的内部接口。用来实例化handler避免自己生成handler子类的麻烦。
需要注意的几点
1.Looper.prepare();和Looper.loop();都是在run方法中执行。
2.handler.post(runnable);必须写在Looper.loop();方法前面,否则没有效果。
3.在runnable中可以多次调用handler.sendMessage(handler.obtainMessage(1));只是Message.what值不同就可以发送不同的消息。在handleMessage中handler就可以根据what值对不同的消息分别处理。
4.不要忘记了调用thread.start();方法。
下面说说handlerThread,其本身带有消息队列所以就不要像一般线程那样调用Looper.prepare等方法了。下面是例子代码:
package com.example.handlerdemo2;
import android.R.integer;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
public class MainActivity extends Activity {
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button=(Button) findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//参数为线程的名字可通过getName返回。
HandlerThread handlerThread=new HandlerThread("handlerthread");
handlerThread.start();
Handler handler=new Handler(handlerThread.getLooper(),new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
// TODO Auto-generated method stub
try {
//通过让线程休眠16秒没有报错,可以验证该是一个独立于主线程的线程。可以在此处理耗时操作。
Thread.sleep(16000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
switch (msg.what) {
case 1:
System.out.println("这是message1发来的消息");
//此处得到的名字就是初始化handlerThread时里面的参数
System.out.println("thread name is---->"+Thread.currentThread().getName());
break;
case 2:
System.out.println("这是message2发来的消息");
System.out.println("thread name is---->"+Thread.currentThread().getName());
break;
}
return true;
}
});
//可以通过hanler得到不同的Message从而在handleMessage方法中对消息进行分别处理。
Message message1=handler.obtainMessage(1);
Message message2=handler.obtainMessage(2);
message2.sendToTarget();
message1.sendToTarget();
}
});
}
}
其就将对Looper的处理交由handlerThread处理了自己就不用管了,方便了一些。该方法中handler的声明使该handler绑定到handlerthread的looper所在的消息队列中去了。