Handler大家应该都很熟悉而且平时也会经常使用到。


为什么不能在子线程创建Handler

   public Handler() {this(null, false);}public Handler(@Nullable Callback callback, boolean async) {if (FIND_POTENTIAL_LEAKS) {final Class<? extends Handler> klass = getClass();if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&(klass.getModifiers() & Modifier.STATIC) == 0) {Log.w(TAG, "The following Handler class should be static or leaks might occur: " +klass.getCanonicalName());}}mLooper = Looper.myLooper();if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread " + Thread.currentThread()+ " that has not called Looper.prepare()");}mQueue = mLooper.mQueue;mCallback = callback;mAsynchronous = async;}

 private void testMethod() {new Thread(new Runnable() {@Overridepublic void run() {Handler handler = new Handler();}}).start();}

运行发现会报错:
java.lang.RuntimeException: Can’t create handler inside thread Thread[Thread-2,5,main] that has not called Looper.prepare()

    public static @Nullable Looper myLooper() {return sThreadLocal.get();}

调用了ThreadLocal.get(),返回当前线程关联的Looper对象

如果Looper为空 就会抛出异常 :
Can’t create handler inside thread Thread[Thread-2,5,main] that has not called Looper.prepare()

为什么主线程创建 Handler()不会报错

 public static void main(String[] args) {···Looper.prepareMainLooper();Looper.loop();···}public static void prepareMainLooper() {prepare(false);synchronized (Looper.class) {if (sMainLooper != null) {throw new IllegalStateException("The main Looper has already been prepared.");}sMainLooper = myLooper();}}private static void prepare(boolean quitAllowed) {if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper(quitAllowed));}

Handler创建需要Looper对象,否则会抛出异常,默认获取当前线程的Looper
主线程也就是ActivityThread会自动创建Looper,其它线程如果需要Looper需要手动创建


为什么只能在主线程中操作UI?为什么子线程中TextView setText不报错?

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//Density.setDensity(getApplication(), this);setContentView(R.layout.activity_main);tv = findViewById(R.id.text);new Thread(new Runnable() {@Overridepublic void run() {tv.setText("我瞅瞅你~");}}).start();}

给子线程休眠2s,程序会直接闪退

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

  • 分析源码
    public final void setText(CharSequence text) {setText(text, mBufferType);}public void setText(CharSequence text, BufferType type) {setText(text, type, true, 0);if (mCharWrapper != null) {mCharWrapper.mChars = null;}}private void setText(CharSequence text, BufferType type,boolean notifyBefore, int oldlen) {//省略...if (mLayout != null) {checkForRelayout();}//省略...private void checkForRelayout() {//省略...if(){requestLayout();invalidate();} else {nullLayouts();requestLayout();invalidate();}}
public void requestLayout() {//省略...ViewRootImpl viewRoot = getViewRootImpl();if (viewRoot != null && viewRoot.isInLayout()) {if (!viewRoot.requestLayoutDuringLayout(this)) {return;}}//省略...if (mParent != null && !mParent.isLayoutRequested()) {mParent.requestLayout();}//省略...}

ViewParent mParent;
ViewRootImpl implements ViewParent

获取ViewRootImpl ,mParent是个接口
ViewRootImpl 实现mParent接口

  • 继续跟进ViewRootImpl requestLayout方法
@Overridepublic void requestLayout() {if (!mHandlingLayoutInLayoutRequest) {checkThread();mLayoutRequested = true;scheduleTraversals();}}

checkThread()方法,见名知意应该是用来检查线程

 void checkThread() {if (mThread != Thread.currentThread()) {throw new CalledFromWrongThreadException("Only the original thread that created a view hierarchy can touch its views.");}}

ViewRootImpl.checkThread()检验线程是否是View的创建线程
mThread线程为主线程,Thread.currentThread()即我们运行的子线程
如果当前更新ui不在主线程,就会导致CalledFromWrongThreadException异常


  • 在子线程中 setText 执行的速度要比主线程创建 ViewRootImpl 对象的速度要快,那么就不会执行到 ViewRootImpl 的 checkThread 的方法,就不会抛出异常
    在setText方法之前加上 sleep,让ViewRootImpl 对象先创建就会检查线程抛出异常

Handler的一些思考相关推荐

  1. Go后台项目架构思考与重构 | 深度长文

    作者 | 腾讯云后台工程师黄雷 编辑 | 唐小引 来源 | CSDN(ID:CSDNnews) 引言 本文首先介绍了架构的重要性,随后从一个实际项目的重构过程作为主线,逐步引出主流的架构设计思想以及其 ...

  2. python 记录日志到日志服务器_Python日志模块的使用与思考:服务器程序将每日日志写入每日日志文件,logging,及,把,每天,到,当天,中...

    需求: 一个Python服务器程序,可能会连续运行几个月,现在需要把每天产生的log信息写入到当天的文件中,即每天产生一个log文件. 使用logging模块编写程序,第一个版本如下: import ...

  3. java postdelayed_你真的懂Handler.postDelayed()的原理吗?

    转载自http://www.dss886.com/2016/08/17/01/ 阅读之前先问大家一个问题:Handler.postDelayed()是先delay一定的时间,然后再放入messageQ ...

  4. Handler为什么可能会造成内存泄漏以及可用的四种解决方法

    在Android系统中,Handler是一个消息发送和处理机制的核心组件之一,与之配套的其他主要组件还有Looper和Message,MessageQueue. 根据官网的描述 There are t ...

  5. 项目问题思考之策略模式

    2019独角兽企业重金招聘Python工程师标准>>> 需求: 项目中一个模块需要支持对图片,PDF,文本文件的操作,需要读取他们的内容在前台显示,显示缩略图,保存他们的内容到后台, ...

  6. React Bind Handle的思考

    文章来自我个人的Github 在平时的开发里面,总会碰到handle绑定的问题.如果你和我一样懒或者思考过,你会觉得这个过程实在是太烦了吧.这里记录一下我的思路和历程. 这里以一个按钮的点击事件来做示 ...

  7. Asp.Net 构架(Http Handler 介绍) - Part.2

    Asp.Net 构架(Http Handler 介绍) - Part.2 引言 在 Part.1 Http请求处理流程 一文中,我们了解了Http请求的处理过程以及其它一些运作原理.我们知道Http管 ...

  8. ctf php 流量分析题,GKCTF EZWEB的分析题解和思考

    GKCTF EZ三剑客-EzWeb 看到这个题前端和我自己出的一个题实在是很像,同样是输入一个url,先看题目长啥样吧. 嗯,啥也没有,输入url基本没反应,F12给的提示是?secret,输入后发现 ...

  9. 安卓开发之Handler、HandlerThread学习篇

    安卓开发之Handler.HandlerThread学习心得篇           开篇说明:本文采用的都是最基础最简单的例子,目的只有一个:希望大家将学习的焦点放在Handler的理解和使用上,我不 ...

最新文章

  1. KBEngine服务器环境搭建
  2. 一篇文章,带你了解 “机器学习工程师” 必备技能图谱
  3. linux源码安装nginx
  4. AT2705 Yes or No(组合数学)
  5. mXSS攻击的成因及常见种类
  6. 外部编辑Infopath的表单模板(xsn)
  7. 【科普】boy and girl,你是不是对算法工程师有误解
  8. ManulResetEvent与AutoResetEvent
  9. const 常量_var,let,const 的区别?
  10. typora 公式对齐_都0202年了还不会用 Typora——看Typora使用教程这篇就够了
  11. 黄聪:Destoon中循环嵌套Loop和php代码结合调用自增长数字
  12. 第 5 章 结合javabean实现CRUD
  13. uni-app uniCloud 前端操作数据库 模糊查询
  14. 计算机本地用户和组winx,计算机(Winx系统)实用操作手册.doc
  15. Android开发--MVP demo+Jsoup在线小说阅读器(一)
  16. jrtplib 编译安装配置
  17. Mac上运行matlab2019b卡顿
  18. 聪明人做生意,打折也能玩出新鲜感!让顾客觉得现在不买就是亏!
  19. JAVA要不要看源码_为什么要看源码、如何看源码,高手进阶必看
  20. 优秀的程序员——用批判性思维批判下

热门文章

  1. 【matlab】求导
  2. window下基于vscode编译下载AT32工程备忘录
  3. pubg为什么服务器一直在维护中,pubg服务器维护中
  4. ④绝一首--雨过文字舞
  5. 【Camera】相机防抖
  6. js怎么定义combobox_jQuery EasyUI -ComboBox(下拉列表框)
  7. java 判断 小数_java判断是否是小数
  8. java毕业生设计医院预约挂号系统计算机源码+系统+mysql+调试部署+lw
  9. 友情提示:破坏计算机信息系统罪
  10. margin取负值详解