Android Handler使用详解
Handler负责发送消息,Looper负责接收Handler发送的消息,并直接把消息回传给handler自己,MessageQueue就是一个存储消息的容器。
handler是android给我们提供用来更新UI的一套机制,也是一套消息处理的机制,我们可以发送消息,也可以通过它处理消息。
它最根本的目的就是解决多线程并发问题,假设如果在一个Activity当中,有多个线程去更新UI,并且都没有加锁机制,就会产生更新界面错乱。如果对更新UI的操作都进行枷锁处理又会使应用性能下降,所以Android给我们提供了一套更新UI的机制,我们只需要遵循这样的机制就可以了,根本不用去关心多线程问题,多有的更新UI操作,都是在主线程的消息队列当中去轮询处理的。
handler的使用:
1、使用handler更新UI
定义handler
private Handler handler = new Handler();
定义Runnable
Runnable runnable = new Runnable() {
public void run() {
tetxView.setText("cx");
}
};
启动Runnable
handler.post(runnable);
2、使用handler延时更新UI
前面相同,只有启动时有差别
handler.postDelayed(runnable, 2000);//延时2s更新UI
延时发送通知
handler.sendEmptyMessageDelayed(what, 2000);
3、使用handler消息传递
创建消息,可以创建不同类型的消息(这里arg1、arg2和obj)
Message message = new Message(); //或Message message = handler.obtainMessage();这是也可以用message.sendToTarget();发送消息
message.arg1=66;
message.arg2=33;
message.obj="cx";
handler.sendMessage(message);
接收并处理消息
private Handler handler = new Handler(){
public void handleMessage(Message msg) {
tetxView.setText((String) msg.obj + msg.arg1 + msg.arg2);
};
};
4、消息延时传递sendMessageDelayed,与上面相同。
5、handler移除功能
例如:在2中的延时更新UI过程中,在延时过程中移除,则UI不再更新。
handler.removeCallbacks(runnable);
6、handler消息拦截
消息接收
private Handler handler = new Handler(new Callback() {
@Override
public boolean handleMessage(Message msg) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "1", 1).show();
return true;//返回false,执行完上面的代码在执行下面的;返回true,则不再执行下面的代码
}
}){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "2", 1).show();
}
};
发送一个空消息
handler.sendEmptyMessage(1);
7、handler原理总结:
Handler负责发送消息,Looper负责接收Handler发送的消息,并直接把消息回传给handler自己,MessageQueue就是一个存储消息的容器。
8、创建与子线程相关的Handler
主线程的Handler中不要执行耗时操作,否则界面会出现卡死现象。
创建主线程Handler
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
System.out.println("UI-----------"+Thread.currentThread());
};
};
创建子线程和子线程Handler
class MyThread extends Thread{
public Handler handler;
@Override
public void run() {
// TODO Auto-generated method stub
Looper.prepare();//要创建handler必须先创建接收handler消息的Looper
handler=new Handler(){
public void handleMessage(android.os.Message msg) {
System.out.println("-----------"+Thread.currentThread());
};
};
Looper.loop();//开始循环Looper
}
};
发送消息
MyThread thread=new MyThread();//定义子线程
thread.start();//启动子线程
thread.handler.sendEmptyMessage(1);//向子线程Handler发送消息
handler.sendEmptyMessage(1);<span style="font-family: Arial, Helvetica, sans-serif;">//向主线程Handler发送消息</span>
9、HandlerThread
在主线程的Handler中传入子线程中定义的Looper时,会出现空指针问题。
定义子线程及子线程中的Handler和Looper
class MyThread extends Thread{
public Handler handler;
public Looper looper;
@Override
public void run() {
// TODO Auto-generated method stub
Looper.prepare();
looper=Looper.myLooper();
handler=new Handler(){
public void handleMessage(android.os.Message msg) {
System.out.println("-----------"+Thread.currentThread());
};
};
Looper.loop();
}
};
启动子线程,创建一个Handler并传入子线程中的Looper
MyThread thread=new MyThread();
thread.start();
Handler handler=new Handler(thread.looper){
public void handleMessage(android.os.Message msg) {
System.out.println(msg);
};
};
运行程序会出现错误,thread.looper为空,因为在主线程中创建Handler时,子线程中的Looper还没有创建,这就是多线程并发的问题。修改上面代码:
HandlerThread thread=new HandlerThread("chenxu");//主要功能就是创建Looper,参数为线程名。
thread.start();
Handler handler=new Handler(thread.getLooper()){
public void handleMessage(android.os.Message msg) {
//可执行耗时操作
System.out.println(">>>>>>>>>>>>" + Thread.currentThread());//与上面线程名一致
};
};
handler.sendEmptyMessage(1);
这时的handler就相当于是子线程中的handler,即使执行耗时操作也不会出现界面卡顿的现象。
10、主线程与子线程信息交互
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
public class MainActivity extends Activity {
private Handler threadHandler;
//主线程handler
Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
Message message = new Message();
//向子线程发送消息
threadHandler.sendMessageDelayed(message, 1000);
System.out.println("main handler");
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
HandlerThread thread = new HandlerThread("threadHandler");//主要功能就是创建Looper,参数为线程名。
thread.start();
//子线程handler
threadHandler = new Handler(thread.getLooper()){
public void handleMessage(android.os.Message msg) {
Message message = new Message();
//向主线程发送消息
handler.sendMessageDelayed(message, 1000);
System.out.println("threadHandler handler");
};
};
handler.sendEmptyMessage(1);
}
}
11、其他消息传递方法
发送消息
handler.obtainMessage(1,true).sendToTarget();
handler.obtainMessage(2,"str").sendToTarget();
接收消息
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
boolean b = (Boolean)msg.obj;
break;
case 2:
String s = (String)msg.obj;
break;
}
}
};
12、Handler黄色警告
出现黄色警告是因为 Handler 在 Android 中用于消息的发送与异步处理,常常在 Activity 中作为一个匿名内部类来定义,此时 Handler 会隐式地持有一个外部类对象(通常是一个 Activity)的引用。当 Activity 已经被用户关闭时,由于 Handler 持有 Activity 的引用造成 Activity 无法被 GC 回收,这样容易造成内存泄露。
解决办法:将其定义成一个静态内部类(此时不会持有外部类对象的引用),在构造方法中传入 Activity 并对 Activity 对象增加一个弱引用,这样 Activity 被用户关闭之后,即便异步消息还未处理完毕,Activity 也能够被 GC 回收,从而避免了内存泄露。
private MyHandler mHandler = new MyHandler((Activity) context);
// 发送消息
Message message = new Message();
message.what = 1;
mHandler.sendMessage(message);
// 静态内部类
static class MyHandler extends Handler {
// 弱引用
WeakReference weakReference;
public MyHandler(Activity activity) {
weakReference = new WeakReference(activity);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
Toast.makeText((Context) weakReference.get(), "收到消息", Toast.LENGTH_SHORT).show();
break;
default:
// do something...
break;
}
}
}
13、消息队列使用
private ExecutorService singleThreadExecutor = null;
private LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue<Runnable>(200);
/**
* 创建队列
*/
private ExecutorService getThreadExecutor() {
if (singleThreadExecutor == null) {
singleThreadExecutor = new ThreadPoolExecutor(1, 1,
1000L, TimeUnit.MILLISECONDS,
linkedBlockingQueue);
}
return singleThreadExecutor;
}
/**
* 加入队列
*/
getThreadExecutor().execute(new Runnable() {
@Override
public void run() {
//要执行的代码
}
});
}
更多推荐
所有评论(0)