原文地址:https://www.jianshu.com/p/7cdf2c2ed354
https://blog.csdn.net/qq_37321098/article/details/81535449#2.常用api
//2种创建消息方法
//1.通过handler实例获取
Handler handler = new Handler();
Message message=handler.obtainMessage();
//2.通过Message获取
Message message=Message.obtain();
//源码中第一种获取方式其实也是内部调用了第二种:
public final Message obtainMessage(){
return Message.obtain(this);
}
不建议直接new Message,Message内部保存了一个缓存的消息池,我们可以用obtain从缓存池获得一个消息,Message使用完后系统会调用recycle回收,如果自己new很多Message,每次使用完后系统放入缓存池,会占用很多内存的。
//传递的数据
Bundle bundle = new Bundle();
bundle.putString("msg", "传递我这个消息");
//发送数据
Message message = Message.obtain();
message.setData(bundle); //message.obj=bundle 传值也行
message.what = 0x11;
handler.sendMessage(message);
//数据的接收
final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 0x11) {
Bundle bundle = msg.getData();
String date = bundle.getString("msg");
}
}
};
//创建handler
final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 0x11) {
//更新ui
......
}
}
};
new Thread(new Runnable() {
@Override
public void run() {
//FIXME 这里直接更新ui是不行的
//还有其他更新ui方式,runOnUiThread()等
message.what = 0x11;
handler.sendMessage(message);
}
}).start();
//消息
Message message = Message.obtain();
//发送消息
new Handler().sendMessage(message);
//延时1s发送消息
new Handler().sendMessageDelayed(message, 1000);
//发送带标记的消息(内部创建了message,并设置msg.what = 0x1)
new Handler().sendEmptyMessage(0x1);
//延时1s发送带标记的消息
new Handler().sendEmptyMessageDelayed(0x1, 1000);
//延时1秒发送消息(第二个参数为:相对系统开机时间的绝对时间,而SystemClock.uptimeMillis()是当前开机时间)
new Handler().sendMessageAtTime(message, SystemClock.uptimeMillis() + 1000);
//避免内存泄露的方法:
//移除标记为0x1的消息
new Handler().removeMessages(0x1);
//移除回调的消息
new Handler().removeCallbacks(Runnable);
//移除回调和所有message
new Handler().removeCallbacksAndMessages(null);
public class MainActivity extends AppCompatActivity {
final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
......
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//activity被执行时,被延迟的这个消息存于主线程消息队列中1分钟,
//此消息包含handler引用,而handler由匿名内部类创建,持有activity引用,
//activity便不能正常销毁,从而泄露
handler.postDelayed(new Runnable() {
@Override
public void run() {
......
}
}, 1000 * 60);
}
页面初始化,开启了一个延时的handler事件,最后页面关闭的时候,没有及时释放Handler,会导致该handler一直持有当前Activity的引用,导致内存泄漏
public class MainActivity extends AppCompatActivity {
//创建静态内部类
private static class MyHandler extends Handler{
//持有弱引用MainActivity,GC回收时会被回收掉.
private final WeakReference<MainActivity> mAct;
public MyHandler(MainActivity mainActivity){
mAct =new WeakReference<MainActivity>(mainActivity);
}
@Override
public void handleMessage(Message msg) {
MainActivity mainAct=mAct.get();
super.handleMessage(msg);
if(mainAct!=null){
//执行业务逻辑
}
}
}
private static final Runnable myRunnable = new Runnable() {
@Override
public void run() {
//执行我们的业务逻辑
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyHandler myHandler=new MyHandler(this);
//延迟5分钟后发送
myHandler.postDelayed(myRunnable, 1000 * 60 * 5);
}
}
Handler.post(Runnable)其实就是生成一个what为0的Message,调用
myHandler.removeMessages(0);
会使runnable任务从消息队列中清除。
详细解释可以参考这:Android Handler使用Message的一个注意事项
子线程直接创建Handler,系统会抛出异常
Can't create handler inside thread that has not called Looper.prepare()
原因是非主线程没有loop对象,所以要调用Looper.prepare()方法,而且如果主线程给子线程发送消息,还要调用一个Looper.loop()的方法(此方法保证消息队列中的消息被不停的拿出,并被处理)
class MyThread extends Thread{
@Override
public void run() {
super.run();
Looper.prepare();
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//处理消息
}
};
Looper.loop();
}
}
activity如被finish,但是handler刚好还在处理消息,如果需要用的资源已被释放,则会出现空指针异常。
所以在onDestory中去remove掉我们要处理的事件,还是有必要的。不想处理就直接try catch或者判空。
有时候你会发现removeCallbacks会失效,不能从消息队列中移除。
出现这情况是activity切入后台,再回到前台,此时的runnable由于被重定义,就会和原先的runnable并非同一个对象。所以这么做,加上static即可
static Handler handler = new Handler();
static Runnable myRunnable = new Runnable() {
@Override
public void run() {
//执行我们的业务逻辑
}
};
这样,因为静态变量在内存中只有一个拷贝,保证runnable始终是同一个对象。
异步存在形式有thread,handlerThead,asyncTask,线程池,intentService,handlerThread继承thread,不过内部比普通线程多了一个Looper。
//内部Looper.prepare()
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public class MainActivity extends AppCompatActivity {
private HandlerThread thread;
static Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建一个HandlerThread并启动它
thread = new HandlerThread("MyHandlerThread");
thread.start();
//使用HandlerThread的looper对象创建Handler
mHandler = new Handler(thread.getLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
//这个方法是运行在 handler-thread 线程中的,可以执行耗时操作,因此不能更新ui,要注意
if (msg.what == 0x1) {
try {
Thread.sleep(3000);
Log.e("测试: ", "执行了3s的耗时操作");
} catch (InterruptedException e) {
e.printStackTrace();
}
//这个方法是运行在 handler-thread 线程中的,可以执行耗时操作,因此不能更新ui,要注意
// ((Button) MainActivity.this.findViewById(R.id.button)).setText("hello");
}
return false;
}
});
//停止handlerthread接收事件
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
thread.quit();
}
});
//运行
mHandler.sendEmptyMessage(0x1);
}
}
上面demo中,只要调用了
mHandler.sendEmptyMessage(0x1);
就会开始执行任务
几个地方要注意:
举例:
//耗时任务换成这个,点击按钮执行quit()方法,发现此次任务依旧执行
for (int i = 0; i < 99999999; i++) {
Log.e("测试: ", "输出" +i);
}