精华内容
下载资源
问答
  • 子线程中创建handler

    2016-05-13 15:07:16
    方法1、 android显示操作界面,需要在主线程中执行 不在主线程中需要在...myhandler = new Handler(new Handler.Callback() { public boolean handleMessage(Message msg) { return false; } }); Looper.loop

    方法1、

    android显示操作界面,需要在主线程中执行

    不在主线程中需要在handler中执行
    Looper.prepare();
    myhandler = new Handler(new Handler.Callback() {
    public boolean handleMessage(Message msg) {
    return false;
    }
    });
    Looper.loop();

    必须开始Looper但是开启的时刻可以自己控制

    方法2、

     public static ServiceHandler mHandler;
     // Handler that receives messages from the thread
    public final class ServiceHandler extends Handler {
         public ServiceHandler(Looper looper) {
             super(looper);
         }
         @Override
         public void handleMessage(Message msg) {
        switch (msg.what) {
    case 1:
    break;
    case 2:
    default:
    break;
    }
         }
     }

    Service的onCreate中调用

     HandlerThread handlerThread = new HandlerThread("ATMSServiceName",Process.THREAD_PRIORITY_BACKGROUND);
       handlerThread.start();
      // Get the HandlerThread's Looper and use it for our Handler
     mServiceLooper = handlerThread.getLooper();
     mHandler = new ServiceHandler(mServiceLooper);
     

    展开全文
  • 很多面试题问到“子线程中能否创建Handler?”。 之前一直使用HandlerThread框架,在主线程中创建与子线程关联的Handler实例,也没考虑过这个问题。 代码如下: ``` HandlerThread mHandlerThread = new ...
  • 二、为什么子线程不调用Looper.prepare(),创建Handler后会报错呢? 三、主线程中的Handler之前也没有调用Looper.prepare()方法,为什么就没有崩溃呢? 四、总结说 系列文章 Handler异步消息传递机制(一)...

    声明:本教程不收取任何费用,欢迎转载,尊重作者劳动成果,不得用于商业用途,侵权必究!!!

    目录

    一、前言

    二、为什么子线程不调用Looper.prepare(),创建Handler后会报错呢?

    三、主线程中的Handler之前也没有调用Looper.prepare()方法,为什么就没有崩溃呢?

    四、总结说


    系列文章

    Handler异步消息传递机制(一)Handler常用基本用法

    Handler异步消息传递机制(二)在子线程中创建Handler

    Handler异步消息传递机制(三)在主线程、子线程中创建Handler,源码(Android 9.0)解析

    Handler异步消息传递机制(四)Handler发送消息流程,源码(Android 9.0)解析

    一、前言

    上篇文章 Handler异步消息传递机制(二)Handler在主线程new还是子线程new?我们在子线程创建了Handler,程序崩溃提示报错信息为:java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare(),根据错误信息然后我们试试在线程中先调用一下Looper.prepare(),再创建Handler对象。bug解决,程序不再崩溃!

                    Looper.prepare();
                    handler = new Handler() {
                    。。。。。。
    

    二、为什么子线程不调用Looper.prepare(),创建Handler后会报错呢?

    我们来看下Handler的源码,搞清楚为什么不调用Looper.prepare()就不行呢。Handler的无参构造函数如下所示:

       public Handler() {
            this(null, false);
        }

    然后继续跟踪,可以看到如下代码:

        public Handler(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;
        }

    可以看到,在第11行调用了Looper.myLooper()方法获取了一个Looper对象,如果Looper对象为空,则会抛出一个运行时异常,提示的错误信息正是:"Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()",

    那么什么时候Looper对象mLooper才会为空呢?这就要看看Looper.myLooper()中的代码了,我们继续跟踪源码:

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

    我们发现就是从sThreadLocal对象中取出Looper,然后进行return返回。

    如果从sThreadLocal中get到有Looper存在就返回Looper,如果没有Looper存在自然就返回null了。

    而返回null就会报如上错误,然而我们通过错误提示信息在创建Handler之前执行Looper.prepare()就不报错了。

    我们自然可以推断出当执行 Looper.prepare(),Looper对象mLooper不为null,即解决了报"Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()",的异常信息。

    所以 Looper.prepare() 方法我们来看一下它的源代码:

      public static void prepare() {
            prepare(true);
        }

    然后继续跟踪我们可以看到如下代码:

      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));
        }

    通过代码我们知道,首先判断sThreadLocal通过get方法,是否能获取到 Looper对象。

    如果有的话,就会提示错误信息:“java.lang.RuntimeException: Only one Looper may be created per thread”,

    直译过来就是“每个线程只能创建一个 Looper对象”,你可以二次调用 Looper.prepare(); 来验证下。如果还没有Looper对象,则会创建一个新的Looper设置进去。

    这样也就完全解释了为什么我们要先调用Looper.prepare()方法,才能创建Handler对象。同时也可以看出每个线程中最多只会有一个Looper对象。

    三、主线程中的Handler之前也没有调用Looper.prepare()方法,为什么就没有崩溃呢?

    Android的主线程就是 ActivityThread,主线程的入口方法为main,我们来看一下 ActivityThread 类中 main 方法的源代码:

    public static void main(String[] args) {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
    
            // CloseGuard defaults to true and can be quite spammy.  We
            // disable it here, but selectively enable it later (via
            // StrictMode) on debug builds, but using DropBox, not logs.
            CloseGuard.setEnabled(false);
    
            Environment.initForCurrentUser();
    
            // Set the reporter for event logging in libcore
            EventLogger.setReporter(new EventLoggingReporter());
    
            // Make sure TrustedCertificateStore looks in the right place for CA certificates
            final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
            TrustedCertificateStore.setDefaultUserDirectory(configDir);
    
            Process.setArgV0("<pre-initialized>");
    
            Looper.prepareMainLooper();
    
            // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
            // It will be in the format "seq=114"
            long startSeq = 0;
            if (args != null) {
                for (int i = args.length - 1; i >= 0; --i) {
                    if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                        startSeq = Long.parseLong(
                                args[i].substring(PROC_START_SEQ_IDENT.length()));
                    }
                }
            }
            ActivityThread thread = new ActivityThread();
            thread.attach(false, startSeq);
    
            if (sMainThreadHandler == null) {
                sMainThreadHandler = thread.getHandler();
            }
    
            if (false) {
                Looper.myLooper().setMessageLogging(new
                        LogPrinter(Log.DEBUG, "ActivityThread"));
            }
    
            // End of event ActivityThreadMain.
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            Looper.loop();
    
            throw new RuntimeException("Main thread loop unexpectedly exited");
        }

    可以看到,它在第20行调用了 Looper.prepareMainLooper() 方法,我们继续跟踪源码,

    你会发现这个方法内部调用了 Looper.prepare() 方法,代码如下所示:

       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.prepare()方法了。

    也就是说主线程内部已经自动调用了 Looper.prepare() 方法。这样基本就将Handler的创建过程完全搞明白了。

    1、从代码操作层面上来讲:

    在主线程中可以直接创建Handler对象,而在子线程中需要先调用Looper.prepare()才能创建Handler对象。

    2、从源码解析上来说:

    创建Handler对象之前,必须拥有不为null的Looper对象。如果Looper对象为null,将会报错:"Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()"

    3、每个线程只能创建一个 Looper对象

    四、总结说

    1、为什么子线程不调用Looper.prepare(),创建Handler后会报错呢?

    (1)通过源码我们知道 Handler 构造器,做了 Looper 对象是否为空的判定。

    如果 Looper 对象为空,则报错误信息为:不能在没有调用 Looper的prepare方法的线程中创建Handler

    (2)Looper 类的prepare方法做了相关逻辑处理和说明:

    如果 Looper 对象不为空,会抛出异常提示:每个线程只能创建一个 Looper对象

    如果 Looper 对象为空,它会创建一个新的 Looper 设置进去

     

    2、主线程中的Handler之前也没有调用Looper.prepare()方法,为什么就没有崩溃呢?

    主线程中内部调用了Looper的prepareMainLooper方法,而prepareMainLooper方法里面调用了Looper的prepare() 方法

     

    3、这个时候我们必须明白一点,创建Handler对象之前,必须拥有不为null的Looper对象

     

     

     

    展开全文
  • 子线程中使用Handler

    千次阅读 2018-04-10 17:06:01
    在子线程中使用handler就意味着handler的实例是在子线程中去创建的。 Looper.prepare(); mHandler = new Handler(){ @Override public void handleMessage(Message msg) { Log.d(TAG," mHandler is co.....

    在子线程中使用Handler

    • 在子线程中使用handler就意味着handler的实例是在子线程中去创建的。
    Looper.prepare();
    mHandler = new Handler(){
        @Override
      public void handleMessage(Message msg) {
                Log.d(TAG," mHandler is coming");
      handler_main.sendEmptyMessage(1);
      }
    };
    mHandler.sendEmptyMessage(1);
    Looper.loop();
    • 如果在调用之前必须调用Looper.prepare()方法,这个是在当前线程中创建一个looper出来,如果是普通的应用场景可以直接使用HandlerThread,其中是带有Looper的。
    • 第二点值得注意的就是,Looper.loop()这个方法是无限循环的,所以在Looper.loop()后边的程序代码块是无法执行到的。loop()方法的主要作用是一直不断的通过queue.next()方法来读取来自messagequeue中的msg,这个方法是block的状态,如果queue中没有消息的话会一直阻塞在这里。
    • 关于Looper还有一个方法,当我们需要获取Looper实例时,可以直接在对应线程调用Looper looper = Looper.myLooper();来获取,默认情况下,系统只会给MainT
      hread分配一个looper。

    在子线程中更新UI

    • 这个听上去好像有点问题,其实不然,这句话是可以实现的。方法就是在子线程中获取UI线程的looper,然后再创建handler实例,在handlerMessage()方法中去更新UI。
    handler_main = new Handler(getMainLooper()){
        @Override
      public void handleMessage(Message msg) {
      helloTextView.setText("getMainLooper");
      }
    };

    今天写这篇文章主要是前几天被一个问题疑惑住了,如何在没有上下文的情况下使用子线程去更新UI,其实就是getMainLooper()获取UI线程的looper就可以了。关于Handler还有很多可以写的,下次有空再补上。

    展开全文
  • 可以创建,但是不能直接创建。 主线程中的handler是,子线程执行完后,更新主线程的数据。 子线程创建handler,主线程给子线程发消息,更新子线程的数据。

    1、可以创建,但是不能直接创建。

    需要先Looper.prepare();

    2、主线程中的handler是,子线程执行完后,更新主线程的数据。

    子线程创建handler,主线程给子线程发消息,更新子线程的数据。

    3、handler机制:

    handler:负责消息的发送,处理

    message:消息主体

    Looper:死循环,负责message的接收、分发;

    MessageQueue:消息队列

    子线程中,使用handler发给looper,放进消息队列,Looper分发给主线程中handler处理。

    展开全文
  • 本文介绍了如下内容: 1、如何创建一个handler对象并使其与子线程挂钩; 2、HandlerThread的作用以及使用方法。
  • newThread(newRunnable(){ publicvoidrun(){ Looper.prepare(); Handlerhandler=newHandler(){ @Override ...
  • 转自...在线程的run()方法里调用Looper.prepare(),实例化一个Handler对象,调用Looper.loop()使线程进入消息循环 public void run(){ Looper.prepare(); //dosome
  • 很多时候,我们需要在其他线程使用Handler,特别是在一些远程回调方法中。...因此我们可以使用主线程原有的MessageQueue,在创建Handler的时候把主线程的Looper放进去: private void initHandler...
  • 在Android子线程中初始化handler后,然后初始化looper,使得该子线程具有消息处理机制。 因为该looper是非主线程的消息循环,那为什么这个子线程也能更新Android UI 呢? 提问者采纳 子线程的hanlder...
  • 最近学习handler时,碰到一个自觉得有意思的问题, 有人说:“new Thread(run(){ //第1层子线程new Thread(run(//第2层子线程new Thread(run(){//第3层子线程}).start()) ).start()}).start()我想知道子线程...
  • Handler创建方式

    2019-06-12 15:12:49
    1. 概述 在子线程更新UI程序会崩溃,解决方案就是:创建 Message对象,然后用handler发送出去,然后调用handler的handleMessage(Message...下边分别在主线程和子线程中创建handler对象: public class MainActivi...
  • /** * 1,android为什么要在UI线程中修改UI? * 答:因为android的UI组件不是线程安全的,所以android使用UI线程(单线程)中来修改UI组件,确保UI组件... * Message:消息对象,可以携带数据,msg.what,msg.obj,创建的m
  • 如果在一个子线程中创建的类中,创建一个Handler消息对象,会报错。 解决方法是在子线程调用主线程的Handler,在执行创建操作。
  • 目录 一、前言 二、Handler对象在新启动的子线程发送消息(源码跟踪) 三、在主线程中,回调 handleMessage 方法的流程是怎样的呢?...Handler异步消息传递机制(三)在主线程、子线程中创建Handler,源码(...
  • Handler 在创建的时候必须使用当前线程的 Looper 来构造消息循环,而自己手动创建的子线程默认是没有 Looper 的, 如果在一个子线程中创建 Handler ,就必须为这个子线程创建相应的消息轮训器,否则我们就会看到一个...
  • Android 多线程之 Handler 基本使用

    千次阅读 2018-03-31 11:17:25
    Handler系列—基本使用 前言 Handler 使用 1、使用 Handler 的 post() 方法更新 UI 2、使用 Handler 的 sendMessage() 方法更新 UI ...5、子线程中创建 Handlerhandler1)发送消息,在子线程中的Handler(h...
  • Android子线程间通信

    2017-06-15 20:12:15
    Android子线程间通信 looper默认存在于主线程中,在子线程和主线程通信时,子线程通过主线程中的handler发送消息给主线程的messageQueen消息队列,通过主线程中的...一:在接受消息的子线程中创建handler前调用 Lo
  • 如果我们需要在自己的子线程中创建Handler就需要自己为子线程绑定looper了。如下: private MyHandlerTread mHandlerThread; mHandlerThread = new MyHandlerTread(); mHandlerThread.start()
  • 上篇文章,我们罗列了消息机制中常见的几个概念,如果你还未了解,请先看这篇文章, Android 源码解析...1. 创建好项目后,我们首先分别在主线程和子线程中创建Handler, private Handler mHandler1; private Handle
  • 可能很多面试时候问道,子线程中能不能new一个handler ? 答案是可以的,但是因为主线程系统默认在ActivityThread中已将帮我们创建好一个looper和MessagQueue,我们不需要手动去创建 (手动创建会出错,因为一...
  • 1、在哪个线程中创建的UI,...2、子线程中可以使用Handler吗?  可以。子线程中使用Handler必须进行Looper的prepare()。 Looper.prepare(); Handler handler = new Handler(); handler.post(new Runnable() ...
  • handler

    2018-03-03 11:23:38
     以我的看法吧, 它相当于一个主线程,我们都知道,在子线程中是不能更改UI的,比如说你想要在一个子线程中去更改UI这时候就你可以创建一个handler对象通过传达消息的方法在handler中去修改子线程当中的UI了;...
  • Handler

    2016-06-25 17:49:34
    当你创建子线程时,你可以在你的子线程中拿到父线程中创建Handler 对象,就可以通过该对象向父线程的消息队列发送消息了。由于Android要求在UI线程中更新界面,因此,可以通过该方法在其它线程中更新界面。
  • Handler机制剖析

    2020-04-28 15:25:08
    前言 说起Handler我们再熟悉不过了,Handler用来进行线程间进行通讯的,但是Handler线程间通讯的机制以及原理是什么样的?下面我们就一起来剖析一下。...但是有个前提,在子线程创建Handler,必...
  • handler机制

    2017-08-24 15:37:50
    Handler机制 一、Handler机制 Handler: Looper:循环,消息循环 MessageQuene:消息队列,采用单链表的数据结构存储消息列表 ...ThreadLocal:在不同的线程中互不干扰的...如要使用Handler子线程中必须先创建Loope
  • Handler的应用场景

    2018-10-28 11:54:16
    如果在一个activity里面有多个线程去更新UI,并且都没有加锁机制,那就会造成更新UI错乱;而如果对更新UI的操作都进行加锁处理,就会造成性能下降。...在一个子线程中创建一个Handler,然后使用这...
  • Handler课后题

    2021-02-16 15:26:45
    一定是创建Handler的线程么? 消息是如何插入到MessageQueue中的? 当MessageQueue没有消息时,它的next方法是阻塞的,会导致App ANR么? 子线程中可以使用Toast么? Looper.loop()是死循环,可以停止么? ...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 160
精华内容 64
关键字:

子线程中创建handler