范文健康探索娱乐情感热点
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

AndroidHandler面试题总结,学会这些还怕面试官?

  作者:xiangzhihong
  在Android面试中,有关Handler的面试是一个离不开的话题,下面我们就有关Handler的面试进行一个总结。1,Handler、Looper、MessageQueue、线程的关系一个线程只会有一个Looper对象,所以线程和Looper是一一对应的。MessageQueue对象是在new Looper的时候创建的,所以Looper和MessageQueue是一一对应的。Handler的作用只是将消息加到MessageQueue中,并后续取出消息后,根据消息的target字段分发给当初的那个handler,所以Handler对于Looper是可以多对一的,也就是多个Hanlder对象都可以用同一个线程、同一个Looper、同一个MessageQueue。
  综上,Looper、MessageQueue、线程是一一对应关系,而他们与Handler是可以一对多的。2,主线程为什么不用初始化Looper
  因为应用在启动的过程中就已经初始化了一个主线程Looper。每个java应用程序都是有一个main方法入口,Android是基于Java的程序也不例外,Android程序的入口在ActivityThread的main方法中,代码如下:// 初始化主线程Looper  Looper.prepareMainLooper();  ...  // 新建一个ActivityThread对象  ActivityThread thread = new ActivityThread();  thread.attach(false, startSeq);  // 获取ActivityThread的Handler,也是他的内部类H  if (sMainThreadHandler == null) {  sMainThreadHandler = thread.getHandler();  }  ...  Looper.loop();  // 如果loop方法结束则抛出异常,程序结束  throw new RuntimeException("Main thread loop unexpectedly exited"); }
  可以看到,main方法中会先初始化主线程Looper,新建ActivityThread对象,然后再启动Looper,这样主线程的Looper在程序启动的时候就跑起来了。并且,我们通常认为 ActivityThread 就是主线程,事实上它并不是一个线程,而是主线程操作的管理者。3,为什么主线程的Looper是一个死循环,但是却不会ANR
  因为当Looper处理完所有消息的时候会进入阻塞状态,当有新的Message进来的时候会打破阻塞继续执行。
  首先,我们看一下什么是ANR,ANR,全名Application Not Responding。当我发送一个绘制UI 的消息到主线程Handler之后,经过一定的时间没有被执行,则抛出ANR异常。下面再来回答一下,主线程的Looper为什么是一个死循环,却不会ANR?Looper的死循环,是循环执行各种事务,包括UI绘制事务。Looper死循环说明线程没有死亡,如果Looper停止循环,线程则结束退出了,Looper的死循环本身就是保证UI绘制任务可以被执行的原因之一。
  关于这个问题,我们还可以得到如下的一些结论:真正会卡死的操作是在某个消息处理的时候操作时间过长,导致掉帧、ANR,而不是loop方法本身。在主线程以外,会有其他的线程来处理接受其他进程的事件,比如Binder线程(ApplicationThread),会接受AMS发送来的事件在收到跨进程消息后,会交给主线程的Hanlder再进行消息分发。所以Activity的生命周期都是依靠主线程的Looper.loop,当收到不同Message时则采用相应措施,比如收到msg=H.LAUNCH_ACTIVITY,则调用ActivityThread.handleLaunchActivity()方法,最终执行到onCreate方法。当没有消息的时候,会阻塞在loop的queue.next()中的nativePollOnce()方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,所以死循环也不会特别消耗CPU资源。4,Message是怎么找到它所属的Handler然后进行分发的
  在loop方法中,找到要处理的Message需要调用下面的一段代码来处理消息:msg.target.dispatchMessage(msg);
  所以是将消息交给了msg.target来处理,那么这个target是什么呢,通常查看target的源头可以发现:private boolean enqueueMessage(MessageQueue queue,Message msg,long uptimeMillis) {         msg.target = this;          return queue.enqueueMessage(msg, uptimeMillis);     }
  在使用Hanlder发送消息的时候,会设置msg.target = this,所以target就是当初把消息加到消息队列的那个Handler。5,Handler是如何切换线程的
  使用不同线程的Looper处理消息。我们知道,代码的执行线程,并不是代码本身决定,而是执行这段代码的逻辑是在哪个线程,或者说是哪个线程的逻辑调用的。每个Looper都运行在对应的线程,所以不同的Looper调用的dispatchMessage方法就运行在其所在的线程了。6,post(Runnable) 与 sendMessage 有什么区别
  我们知道,Hanlder中发送消息可以分为两种:post(Runnable)和sendMessage。首先,我们来看一下源码:public final boolean post(@NonNull Runnable r) {        return  sendMessageDelayed(getPostMessage(r), 0);     }   private static Message getPostMessage(Runnable r) {         Message m = Message.obtain();         m.callback = r;         return m;     }     public final boolean sendMessage(@NonNull Message msg) {      return sendMessageDelayed(msg, 0);    }
  可以看到,post和sendMessage的区别就在于,post方法给Message设置了一个callback回调。那么,那么这个callback有什么用呢?我们再转到消息处理的方法dispatchMessage中看:public void dispatchMessage(@NonNull Message msg) {         if (msg.callback != null) {             handleCallback(msg);         } else {             if (mCallback != null) {                 if (mCallback.handleMessage(msg)) {                     return;                 }             }             handleMessage(msg);         }     }      private static void handleCallback(Message message) {         message.callback.run();     }
  可以看到,如果msg.callback不为空,也就是通过post方法发送消息的时候,会把消息交给这个msg.callback进行处理;如果msg.callback为空,也就是通过sendMessage发送消息的时候,会判断Handler当前的mCallback是否为空,如果不为空就交给Handler.Callback.handleMessage处理。
  所以post(Runnable) 与 sendMessage的区别就在于后续消息的处理方式,是交给msg.callback还是 Handler.Callback或者Handler.handleMessage。7,Handler如何保证MessageQueue并发访问安全的
  循环加锁,配合阻塞唤醒机制。我们发现,MessageQueue其实是【生产者-消费者】模型,Handler不断地放入消息,Looper不断地取出,这就涉及到死锁问题。如果Looper拿到锁,但是队列中没有消息,就会一直等待,而Handler需要把消息放进去,锁却被Looper拿着无法入队,这就造成了死锁,Handler机制的解决方法是循环加锁,代码在MessageQueue的next方法中:Message next() {  ...  for (;;) {  ...  nativePollOnce(ptr, nextPollTimeoutMillis);  synchronized (this) {  ...  }  } }
  我们可以看到他的等待是在锁外的,当队列中没有消息的时候,他会先释放锁,再进行等待,直到被唤醒。这样就不会造成死锁问题了。8,Handler的阻塞唤醒机制是怎么实现的
  Handler的阻塞唤醒机制是基于Linux的阻塞唤醒机制。这个机制也是类似于handler机制的模式。在本地创建一个文件描述符,然后需要等待的一方则监听这个文件描述符,唤醒的一方只需要修改这个文件,那么等待的一方就会收到文件从而打破唤醒。
  参考:Linux的阻塞唤醒机制9,什么是Handler的同步屏障
  所谓同步屏障,其实就是一个Message,只不过它是插入在MessageQueue的链表头,且其target==null。 而Message加急消息就是使用同步屏障实现的。同步屏障用到了postSyncBarrier()方法。public int postSyncBarrier() {  return postSyncBarrier(SystemClock.uptimeMillis()); }  private int postSyncBarrier(long when) {  synchronized (this) {  final int token = mNextBarrierToken++;  final Message msg = Message.obtain();  msg.markInUse();  msg.when = when;  msg.arg1 = token;  Message prev = null;  Message p = mMessages;  // 把当前需要执行的Message全部执行  if (when != 0) {  while (p != null && p.when <= when) {  prev = p;  p = p.next;  }  }  // 插入同步屏障  if (prev != null) { // invariant: p == prev.next  msg.next = p;  prev.next = msg;  } else {  msg.next = p;  mMessages = msg;  }  return token;  } }
  可以看到,同步屏障就是一个特殊的target,即target==null,我们可以看到他并没有给target属性赋值,那这个target有什么用呢?Message next() {  ...  // 阻塞时间  int nextPollTimeoutMillis = 0;  for (;;) {  ...  // 阻塞对应时间   nativePollOnce(ptr, nextPollTimeoutMillis);  // 对MessageQueue进行加锁,保证线程安全  synchronized (this) {  final long now = SystemClock.uptimeMillis();  Message prevMsg = null;  Message msg = mMessages;  /**  *  1  */  if (msg != null && msg.target == null) {  // 同步屏障,找到下一个异步消息  do {  prevMsg = msg;  msg = msg.next;  } while (msg != null && !msg.isAsynchronous());  }  if (msg != null) {  if (now < msg.when) {  // 下一个消息还没开始,等待两者的时间差  nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);  } else {  // 获得消息且现在要执行,标记MessageQueue为非阻塞  mBlocked = false;  /**  *  2  */  // 一般只有异步消息才会从中间拿走消息,同步消息都是从链表头获取  if (prevMsg != null) {  prevMsg.next = msg.next;  } else {  mMessages = msg.next;  }  msg.next = null;  msg.markInUse();  return msg;  }  } else {  // 没有消息,进入阻塞状态  nextPollTimeoutMillis = -1;  }  // 当调用Looper.quitSafely()时候执行完所有的消息后就会退出  if (mQuitting) {  dispose();  return null;  }  ...  }  ...  } }
  我们重点看一下关于同步屏障的部分代码。if (msg != null && msg.target == null) {  // 同步屏障,找到下一个异步消息  do {  prevMsg = msg;  msg = msg.next;  } while (msg != null && !msg.isAsynchronous()); }
  如果遇到同步屏障,那么会循环遍历整个链表找到标记为异步消息的Message,即isAsynchronous返回true,其他的消息会直接忽视,那么这样异步消息,就会提前被执行了。同时,,同步屏障不会自动移除,使用完成之后需要手动进行移除,不然会造成同步消息无法被处理。10,IdleHandler的使用场景
  前面说过,当MessageQueue没有消息的时候,就会阻塞在next方法中,其实在阻塞之前,MessageQueue还会做一件事,就是检查是否存在IdleHandler,如果有,就会去执行它的queueIdle方法。
  IdleHandler看起来好像是个Handler,但他其实只是一个有单方法的接口,也称为函数型接口。public static interface IdleHandler {  boolean queueIdle(); }
  事实上,在MessageQueue中有一个List存储了IdleHandler对象,当MessageQueue没有需要被执行的Message时就会遍历回调所有的IdleHandler。所以IdleHandler主要用于在消息队列空闲的时候处理一些轻量级的工作。
  因此,IdleHandler可以用来进行启动优化,比如将一些事件(比如界面view的绘制、赋值)放到onCreate方法或者onResume方法中。但是这两个方法其实都是在界面绘制之前调用的,也就是说一定程度上这两个方法的耗时会影响到启动时间,所以我们可以把一些操作放到IdleHandler中,也就是界面绘制完成之后才去调用,这样就能减少启动时间了。11,HandlerThread使用场景
  首先,我们来看一下HandlerThread的源码:public class HandlerThread extends Thread {     @Override     public void run() {         Looper.prepare();         synchronized (this) {             mLooper = Looper.myLooper();             notifyAll();         }         Process.setThreadPriority(mPriority);         onLooperPrepared();         Looper.loop();     }
  可以看到,HandlerThread是一个封装了Looper的Thread类,就是为了让我们在子线程里面更方便的使用Handler。这里的加锁就是为了保证线程安全,获取当前线程的Looper对象,获取成功之后再通过notifyAll方法唤醒其他线程,那哪里调用了wait方法呢?答案是getLooper方法。public Looper getLooper() {         if (!isAlive()) {             return null;         }          // If the thread has been started, wait until the looper has been created.         synchronized (this) {             while (isAlive() && mLooper == null) {                 try {                     wait();                 } catch (InterruptedException e) {                 }             }         }         return mLooper;     }最后
  在这里就还分享一份由大佬亲自收录整理的学习PDF+架构视频+面试文档+源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料
  这些都是我现在闲暇时还会反复翻阅的精品资料。里面对近几年的大厂面试高频知识点都有详细的讲解。相信可以有效地帮助大家掌握知识、理解原理,帮助大家在未来取得一份不错的答卷。
  当然,你也可以拿去查漏补缺,提升自身的竞争力。
  真心希望可以帮助到大家,Android路漫漫,共勉!
  如果你有需要的话,只需私信我【进阶】即可获取

华为P40Pro再见华为P40Pro实际是上一代的顶级旗舰,是比小米11ultra更适合被称为安卓之光的手机,但现在华为P50都发布了,我们要理解华为P40Pro应该被说再见!从华为P50Pro和华为腾讯视频海外版扫黑风暴无超前点播,你怎么看待这一行为?据爆料,腾讯视频海外版播放的扫黑风暴是没有超前点播的,也就是说买一次vip就行,不用再额外花钱,也不存在会员专属广告。不过腾讯锁了中国IP,中国用户在腾讯视频海外版上根本就搜不到扫腾讯爱奇艺接连发声改!网友终于等到了近日,腾讯视频按顺序解锁观看涉嫌捆绑销售,引起了网友广泛的讨论。(此前报道扫黑风暴超前点播,被点名!)9月1日,腾讯视频发布声明,称会尽快调整解锁规则,支持用户选集解锁。以下是腾讯爱奇艺奇遇3VR一体机发布发烧级游戏大作,顶级硬件配置,内容也不拉跨伴随着元宇宙的概念爆火,不论对VRAR还是MR市场都带来了不小的震动。就在前几日,有传言称字节跳动正在收购国内VR设备公司Pico,这一消息后来也得到了字节跳动的证实。相比之下,同9月2日军工证券5g通信怎么走?昨天的军工大跌,辉哥收益率大幅回撤,辉哥只能忍了!辉哥最欣赏的一句话胜不骄,败不馁!加油!!本月的目标是做到50点!今年的目标是做到80点!这两个目标继续维持不变,欢迎大家一起共同5G还没普及,韩国LG公司6G已经试验成功,我们呢?5G是由国际组织3GPP制定批准的一个通信标准,目前该组织并未开始讨论6G采用什么技术,哪里来的6G就成功了的信息?你可以说你在实验新技术,你可以说你在为将来的6G做准备,但你没有未来世界什么样?经开区今天开幕的世界5G大会给你答案因疫情而延期的2021世界5G大会已于8月31日在北京经开区重启大幕,9月1号2号两天开始向公众开幕,随小编来大会现场先睹为快吧。2万平方米展馆打造5G新世界,34家企业带来620华为有什么魔力?为什么大家宁愿买4G的P50,也不买5G的iPhone12华为是国内顶尖的科技公司,在高通和苹果等世界先进的企业还没有打造出5G芯片的时候,华为率先推出了集成5G网络的麒麟9000芯片,取得这样的成绩值得我们骄傲。不过好景不长,华为的突出三星带你去一趟海南近期超火的小众景点山钦湾燕子洞绝美海景,礁石林立,浪花肆意,惊涛拍岸。EXIF信息2。20厂商samsung型号SMG9880光圈1。8ISO16曝光时间0。0005时间20210726110639EXIF信息华为WATCH3评测鸿蒙生态的腕上集大成,做到了有史以来最好我曾试图游说过几位事业有成的人士,为他们的手机配上一块智能手表。即便是对智能手表一无所知甚至排斥的人,只要我提到心率血氧睡眠等帮助他们养成健康生活习惯的相关功能时,他们的眼睛也还是乐视手机回归,搭载720P屏幕AppleWatch占市场一半份额乐视手机回归,搭载720P屏幕还记得那个为梦想窒息的乐视手机吗,今天它要回来了。近期乐视新机通过了入网许可,入网信息显示乐视新机搭载的是1600720分辨率的TFT材质屏幕,大小是
自己动手拆机维修佳能ip8780彩色喷墨打印机家里有台佳能ip8780打印机,闲置了两三年一直没用过,最近要打印点东西,于是让它重见天日,可意外的是,之前用得好好的机器居然无法正常开机了,插电按电源按钮,电源灯亮三下就灭了,跟你们的iPhone12有这样的问题吗,吐槽iPhone12使用吐槽1屏幕四个角缝隙真的大,可以塞A4纸,还沾灰尘每次都强迫症要去清理2用AirPods播放音乐时切歌时候会有断开的情况3充电时发烫,看视频刷抖音的时候也很烫4让我独享的桌面迷你空调最近热吗?热就对了,特别是在办公室,因为办公室不是我一个人,有很多人,有特殊情况的女生,也有体虚的女生,也有怕冷的女生,于是作为一个男生来说,自然也是只有宁愿热一点,也会同意女生们2021为什么还是有很多人坚持使用iPhone7,三个理由很真实雷军曾表示到了2021年小米6还有215万人在用,所以这款手机成为了小米的经典机型。不过,早一年诞生的iPhone7目前市场的占有率依然很高,在用率甚至是小米6的几倍,iPhone滴滴滴超越J1900近期性价比最高的软路由最低65包邮前言大家好,我是折了个腾,好久不见,有两个多月没有更新了,想不到我这样的垃圾佬也有铁粉,居然跑到我小黄鱼去催更!今天来水一篇惠普T620的折腾教程。之前出过T520改双千兆的教程,聚焦每一个小弄堂每一条小马路每一个小落脚,城市就是人工智能最佳试验场,也是人工智能价值最好实现地城市,千百年来历经多少变迁发展,是人类生存空间的代名词。人工智能,上世纪50年代中期首次提出。概念出现至今,在人类发展的历史长河里须臾一瞬。直到当今世界,科学技术的不断发展,让两者被封杀后,川粉要发动美国政变?社死恐将掐断特朗普政治生命虽然脸书(Facebook)等美国互联网巨头已经在6月彻底封禁了特朗普的账号,但这显然阻止不了特朗普在互联网上的热度。最近,阴谋论团体QAnon与特朗普粉丝们突破重重困难,自己建立华为被戏耍了?马来西亚态度反转,宣布5G建设决定阅读下面文章之前,希望您能够在上方点个免费的关注!接下来您每天都能够收到免费的国际资讯哟!您的关注是我的动力多多支持下嘛!!不知道大家有没有发现,在2G时代,我们不出几年就已经跳到5nm芯片下半场之争A15即将来袭,高通和联发科旗舰芯也已上路再过两个月,苹果一年一度的秋晚就将拉开帷幕,带来备受瞩目的新款手机iPhone13系列。虽然只是小改款,相比iPhone12系列,iPhone13系列无论是在外观还是配置上,都有着全面屏之后,手机下一个潮流是什么首先,来一波对中华酷联时代的致敬!功能机刚开始向智能机过渡的时候,还是诺基亚塞班系统的天下,中华酷联能在当时占据国内市场的一席之地,也多是靠了之前的布局,比如和网络运营商合作,充话骁龙888旗舰手机哪家强?vivoX60Pro闭眼买就行为了给使用者带来更多的选择,各大厂商的旗舰手机玩起了中杯大杯超大杯的组合。如果想要获得最顶级的使用体验,自然是要将超大杯产品纳入首要考虑范围。vivoX60Pro是vivo目前最顶