处理线程中消息队列的方法目前我知道的分为种两种。一种是线程本身带有消息队列,如主线程和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(); } }); } }