-
Notifications
You must be signed in to change notification settings - Fork 0
Handler
DawnSpring edited this page Jan 8, 2021
·
18 revisions
参考: https://blog.csdn.net/qq_37321098/article/details/81535449 https://blog.csdn.net/androidsj/article/details/79865091
发送消息and接收消息,具体用法
//传递的data
var bundle = Bundle()
bundle.putString("msg","我可以")
//send data
private lateinit var handler:Handler
var message = handler.obtainMessage()
message.data = bundle
message.what = 123
handler.sendMessage(message)
//receive data
**handler = @SuppressLint("HandlerLeak")**
object :Handler(){
override fun handleMessage(msg: Message){
super.handleMessage(msg)
if (msg.what == 123){
}
}
}
代码里有句提示:
handler = @SuppressLint("HandlerLeak")
表示代码不规范,有内存泄漏的风险,原因:
Handler在Android中用于消息的发送和异步处理,Handler常作为匿名内部类来定义,此时Handler会隐式的持有外部类对象的引用,当外部类关闭时,由于handler持有外部类的引用造成外部类无法被GC回收,这样容易造成内存泄漏;
解决方法:
将其定义成一个静态内部类(此时不会持有外部类对象的引用),在构造方法中传入外部类,并对外部类对象增加一个弱引用,外部类关闭后,即使异步消息未处理完毕,外部类也能被GC回收,从而避免内存泄漏。
代码应该这样写:\
//在外部类里这样写:
companion object {
private class TestHandler(view: FirstFragment) : Handler() {
private val mView = WeakReference(view)
override fun handleMessage(msg: Message?) {
super.handleMessage(msg)
when (msg?.what) {
123 -> {
var bundle = msg.data
var data = bundle.getString("msg")
}
}
}
}
}
另外改下:
private lateinit var handler:TestHandler
public final class Message implements Parcelable {
//用户定义的消息代码,以便接收者能够识别
public int what;
//arg1和arg2是使用成本较低的替代品-也可以用来存储int值
public int arg1;
public int arg2;
//存放任意类型的对象
public Object obj;
//消息触发时间
long when;
//消息携带内容
Bundle data;
//消息响应方
Handler target;
//消息管理器,会关联到一个handler
public Messanger replyTo;
//回调方法
Runnable callback;
//消息存储的链表。这样sPool就成为了一个Messages的缓存链表。
Message next;
//消息池
private static Message sPool;
//消息池的默认大小
private static final int MAX_POOL_SIZE = 50;
//从消息池中获取消息
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool; //从sPool的表头拿出Message
sPool = m.next; //将消息池的表头指向下一个Message
m.next = null; //将取出消息的链表断开
m.flags = 0; // 清除flag----flag标记判断此消息是否正被使用(下方isInUse方法)
sPoolSize--; //消息池可用大小进行减1
return m;
}
}
return new Message(); //消息池为空-直接创建Message
}
//通过标记判断消息是否正被使用
boolean isInUse() {
return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
}
//5.0后为true,之前为false.
private static boolean gCheckRecycle = true;
public void recycle() {
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it is still in use.");
}
return;
}
recycleUnchecked(); //消息没在使用,回收
}
//对于不再使用的消息,加入到消息池
void recycleUnchecked() {
//将消息标示位置为IN_USE,并清空消息所有的参数。
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this; //当消息池没有满时,将Message加入消息池
sPoolSize++; //消息池可用大小加1
}
}
}
public final class Looper {
//内部消息队列MessageQueue
final MessageQueue mQueue;
//Looper所在的线程
final Thread mThread;
//Looper的变量存储
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//主looper
private static Looper sMainLooper;
//私有构造方法,不能通过New实例化。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);//创建与其绑定的消息队列MessageQueue
mThread = Thread.currentThread(); //绑定当前线程
}
//子线程的调用----->最终通过prepare(boolean)实例化Looper
public static void prepare() {
prepare(true);
}
//主线程的调用----->最终通过prepare(boolean)实例化Looper
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();//存储区中looper作为主looper
}
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
//quitAllowed代表是否允许退出,主线程调用为不允许退出,子线程为可退出
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
//看出一个线程只能存在一个Looper-->则调用二次Looper.prepare抛出异常
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));//Looper的变量存储+实例化Looper
}
循环取出messagequeue消息队列中的消息,并分发出去。再把分发后的Message回收到消息池,以便重复利用。
public static void loop() {
final Looper me = myLooper(); //从存储区拿出looper
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; //获取Looper对象中的消息队列
......
//进入loop的主循环方法
for (;;) {
Message msg = queue.next(); //可能会阻塞
if (msg == null) { //没有消息,则退出循环
return;
}
......
//target是handler,此处用于分发Message
msg.target.dispatchMessage(msg);
......
msg.recycleUnchecked(); //将Message放入消息池
}
}