这个是接着Handler的二三事写的。
基本用法
我们已经知道,Handler主要做两件事情:更新ui;发送消息
- 首先说说更新ui:
public class MainActivity extends AppCompatActivity {
Handler mHandler = new Handler();
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.textView);
mHandler.post(new Runnable() {
@Override
public void run() {
System.out.println("" + Thread.currentThread());
mTextView.setText("用handler更新了ui");
}
});
}
}
然后看到后台打印了
09-01 15:55:28.716 11152-11152/com.example.myactionbardemo I/System.out: Thread[main,5,main]
这说明post这个方法是运行在主线程中的,我们知道谷歌规定只有在ui线程也就是主线程中才能执行更新ui的操作,所以handler.post()这个方法就能完成这个行为。那么既然是这样我们是不是可以把它放在工作线程中更新ui呢?当然是可以的,这就为我们工作线程和主线程之间的通信提供了一个思考问题的方向。最后基本上可同理postDelay()--延时执行。这个也是运行在主线程当中。
- 然后是发送消息
在线程中发送消息,代码如下
new Thread(){
@Override
public void run() {
Message message = mHandler.obtainMessage();
mHandler.sendEmptyMessage(1);
//message.sendToTarget();
}
}.start();
首先是创建了一个是Message对象,我们一般不用new Message()来创建,而是使用Handler的obtainMessage()方法来创建,可以去看一下源码,源码中是这样return Message.obtain(this);
,返回一个这样的Message对象,然后我们进入obtain()方法中,原来传入的this就是Handler本身,m.target = h;
这个的意思就是把这个消息和handler绑定了。然后里面还有一个没有参数的obtain()方法,点进去看了一眼,好像是用链表处理的啊啊,我在这方面实在是有点欠缺,不过上面的英语的意思就是生成一个了新的Meesage。说了这么多废话其实就是这个方法可以生成一个和Handler有关系的Message。
然后是处理消息,依然是运行在主线程中,可以修改Ui。
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
mTextView.setText("99");
}
};
最后说一点Handler里面还有一个参数Callback。代码如下:
Handler mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
System.out.println("1");
return false;
}
}){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println("2");
}
};
当返回false的时候处理执行第一条语句后,也会继续执行第二个语句:
09-01 20:23:45.333 25527-25527/com.example.myactionbardemo I/System.out: 1
09-01 20:23:45.333 25527-25527/com.example.myactionbardemo I/System.out: 2
返回true,就只会执行第一个handleMessage()里面的语句
09-01 20:32:40.169 2336-2336/com.example.myactionbardemo I/System.out: 1
这样我们就可以拦截消息(这是慕课网上的老师说的),感觉很厉害的样子。
与线程相关的handler
其实我很早以前以为在线程中的handler就是属于线程当中的,后来发现不是,handler在哪不重要,我觉得是看它的Looper在哪创建的,或者使用的是哪个Looper。
虽然前一篇贴过代码,那我就不贴了。现在说一下多线程并发的一个小问题。看代码。
public class MainActivity extends AppCompatActivity {
private TextView mTextView;
private Handler mHandler;
class myThread extends Thread{
public Handler mHandler;
public Looper mLooper;
@Override
public void run() {
super.run();
Looper.prepare();
mLooper = Looper.myLooper();
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println("" + Thread.currentThread());
}
};
Looper.loop();
}
}
private myThread mThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.textView);
mThread = new myThread();
mThread.start();
mHandler = new Handler(mThread.mLooper){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println("" + Thread.currentThread());
}
};
mHandler.sendEmptyMessage(1);
}
}
当运行上面程序的时候就会出错闪退,原因就是当工作线程mThread执行的时候,主线程当中与之关联的handler可能已经执行到获取工作线程的looper了,然而这个时候looper是空的就是没有执行到mLooper = Looper.myLooper();所以会报错。自定义Handler可能就会遇到这种问题。
然后就介绍HeadlerThread可以避免这种问题。
private HandlerThread mHandlerThread;
private Handler mHadler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.textView);
mHandlerThread = new HandlerThread("handler thread");
mHandlerThread.start();
mHadler = new Handler(mHandlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println("" + Thread.currentThread());
}
};
mHadler.sendEmptyMessage(1);
}
创建HandlerThread中传入的对象是线程的名字,当该线程创建并star()之后,再关联handler,就可以得到了该线程的Looper对象,并且打印出来handlerMessage是运行在工作线程当中的。这样就可以在主线程发一个消息,然后在工作线程中执行一些比较耗时的操作,哎呀好方便啊啊啊。这是不是线程间通信啦。
这个就写到这了。
线程一定要start()阿门。
昨天看了一篇文章,就是说在写这类文章的时候,只有自己懂是远远不够,还要让别人也看的懂,当时就觉得特别的惭愧,自己写的自己不一定完全理解,别人就更不一定了。后来我想想,也许是自己的知识水平还没有提升到一个层次,所以对有一些东西还是停留在前人的一些思考上面,很少有自己的想法,写起来奇奇怪怪。如果是自己初次接触到这个东西还看不看得懂呢,这大概是我需要想想的一个问题。
推荐一个博客帅气的stormzhang的博客,理由就是最近他好像做父亲,沾沾喜气喽。