Handle温习笔记

Handler笔记


1.handler是啥

handler是android给我们提供用来更新ui的一套机制,也是一套消息处理的机制,我们可以发送消息,也可以通过它处理消息

大部分东西都是handler发送消息的,android的fragmwork也是通过handler处理的actitivy中各种生命周期的


2.为啥使用handler,不用行不行

创建一个handler的时候,它会和一个默认的线程绑定

不能不用,android在设计的时候,就封装了一套消息创建,传递,处理机制,如果不遵循这样的机制就没办法更新ui信息,会抛出异常信息


3.handler如何使用呢

第一可以更新ui
private Handler handler = new Handler();
new Thread() {
@Override
public void run() {
super.run();
try {
Thread.sleep(1000);
handler.post(new Runnable() {
@Override
public void run() {
// 直接在这里更新ui就完事了,这里已经回到ui线程了
handlerBtn.setText(“sfsfdfsd”);
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
还比如说延迟发送的操作
handler.postDelayed(myRunnable, 1000);

第二可以发送消息
比如现有一个线程
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
// Message message = new Message();
Message message = handler.obtainMessage();
message.arg1 = 88;
message.arg2 = 100;
message.obj = new PersonClass(33, “小明”);
// handler发消息
// messageHandler.sendMessage(message);
// message它自己其实也可以发送消息,内部实现其实也是handler。sendmessage
message.sendToTarget();

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).start();

这里可以接收到消息并更新ui
private Handler messageHandler = new Handler() {
public void handleMessage(Message msg) {
handlerBtn.setText(" " + msg.arg1);
}
};

当然发消息的时候我们没必要用new Message,直接复用系统的即可
Message message = handler.obtainMessage();
看一下这个方法
@NonNull
public final Message obtainMessage()
{
// 这个this其实就是handler它自己
return Message.obtain(this);
}
进到obtain方法
public static Message obtain(Handler h) {
// 相当于new一个message对象
Message m = obtain();
m.target = h;

return m;

}
在看一下封的这个obtain()方法,先从系统拿message 如果拿不到就自己创建一个
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize–;
return m;
}
}
return new Message();
}

handler不仅可发送消息,也可以移除消息
messageHandler.removeCallbacks(myRunnable);

消息拦截Handler.Callback通过return返回true和false,决定是否拦截
private Handler handlerCall = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
Toast.makeText(MainActivity.this, “1”, Toast.LENGTH_SHORT).show();
return false;
}

}){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Toast.makeText(MainActivity.this, “2”, Toast.LENGTH_SHORT).show();

}

};


4.为么要设计只能通过handler机制更新ui呢

最根本的目的是为了解决多线程并发的问题,假设如果在一个activity里,有多个线程要更新ui,并且没有锁,将会导致页面错乱,但是如果把所有更新ui操作都加上锁,又会导致性能下降
基于这种情况,android提供了一套ui更新机制,让其在消息队列中轮询处理,不必关心多线程问题


5.handler的原理

handler封装了消息的发送(主要包括消息发送给谁) 默认情况下都是发送给target的它自己

looper,消息的载体
它的内部包含一个消息队列MessageQueue,所有的handler发送的消息都走这个消息队列

looper.looper方法,是一个死循环,不断的轮询MessageQUeue,如果有消息就处理,没有消息就阻塞

messageQueue就是一个消息队列,可添加和处理消息
handler也很简单,会在初始化的时候,内部和looper关联,也就是在handler的内部会找到looper(looper.prepare方法创建的looper对象),找到了looper就等于找到了messagequeue,所以在handler中发送消息就是相当于向mesagequeue发送消息

总结
handler负责发送消息,looper扶着接受handler发送的消息,并把消息回传给handler自己,messagequeue就是一个存储消息的容器

源码分析理解

最开始有个activityThread,创建的时候main方法中初始化了一个looper对象,创建的同时也创建了messagequeue,通过threadloacl类的set方法放进去,然后在handler初始化的时候,会把looper对象从threadloacl拿出来,再取出messagequeue,对里面的消息做处理,处理的时候有个dispactch的方法, 这个发送的方法中间有个callback,如果callback不是空,就用callback处理消息,并看callback的bool值是否需要拦截,如果是空就直接用handler,sendmessage发送即可


6.如何自定义一个和线程相关的handler

handleMessage方法一定会回到主线程

在一个子线程里创建handler
class MyThread extends Thread {
public Handler handlerMy;

@Override
public void run() {
    super.run();
    Looper.prepare(); // set Looper
    handlerMy = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
	// 经打印这里是主线程,不能做耗时任务
            Log.d("currentThread : ", "" + Thread.currentThread());
        }
    };
    // 启动循环处理
    Looper.loop();
}

}
// 发送消息
new MyThread().handlerMy.sendEmptyMessage(1);


7.handlerThread是什么

有一个场景,如果自己创建一个和线程相关的handler
handlerTest= new Handler(thread.getLooper) {}
可能会需要一个looper,如果用new 出来的looper,因为looper初始化在子线程里,可能用的时候还是空,所以HandlerThread handlerThread = new HandlerThread(‘handlerThread’);
用handlerThread.getLooper得到的就不会是空了,为什么不是空呢,因为这个方法里面有锁和判断,如果是looper是空会让其等待,直到looper不是空了才返回,这事google帮我们想到的做好的东西


8.如何在主线程给子线程发消息(和平时常见情况相反)

准备两个handler,一个是在主线程创建,一个是在new的子线程创建,两个都是实现handleMessage方法,注意的是子线程的handler要借助HandlerThread.getLooper创建, 然后在两个handleMessage中互相用handler.sendDelayedMessage方法发送消息,互相接受


9.andoroid中更新UI的4种方式

// 内部做了线程判断,如果是主线程就执行,不是直接用handler.post
runOnUIThread new Runnable(){
// 内部封装了sendMessageDelepy,然后又封装了message其实和第三个方法一样
handler.post(new Runnable(){
// 这个就是最基本的
handler.sendMessage(1);
// 这个判断attachInfo,取出handler,然后用viewRootImpl发送message
textView.post(new Runnable{


10.非UI线程就不能更新UI了?

并非如此,在某些情况是可以直接更新ui的
textview子线程直接更新ui可以,但是sleep2s之后就不行了

有个ViewParent里面有个invalidate方法,里面有个checkThread方法检测当前线程和UI线程是否相等,如果是子线程当然不相等,抛出异常,但是为什么直接更新就行?
因为有个viewRootImpl主要做ui更新处理逻辑,而它也是需要时间初始化的


11.handler经常会遇到的问题
一个是子线程更新ui的问题,在checkThread方法判断当前线程是否和主线程相等,否者抛出
还有个问题就是在子线程直接new 一个handler,而并没有先looper.parpaer方法,因为这个方法是set一个looper对象的,如果不加后面的初始化handler就取不出looper对象,就抛出异常

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值