精华内容
下载资源
问答
  • 在子线程中创建 handler,要确保子线程有 Looper,UI 线程默认包含 Looper。我们需要用到一个特殊类HandlerThread。这个类可以轻松的创建子线程 handler 创建步骤: 1.创建一个 HandlerThread,即创建一个包含 Looper...

    在子线程中创建 handler,要确保子线程有 Looper,UI 线程默认包含 Looper。我们需要用到一个特殊类HandlerThread。这个类可以轻松的创建子线程 handler

    创建步骤:
    1.创建一个 HandlerThread,即创建一个包含 Looper 的线程HandlerThread 的构造函数有两个

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
    /**
    * Constructs a HandlerThread.
    * @param name
    * @param priority The priority to run the thread at. The value supplied must be from
    * {@link android.os.Process} and not from java.lang.Thread.
    */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

    这里我们使用第一个就好:
     

    HandlerThread handlerThread=new HandlerThread("xuan");
    handlerThread.start();//创建 HandlerThread 后一定要记得 start();

    2.通过 HandlerThread 的 getLooper 方法可以获取 Looper
     

    Looper looper=handlerThread.getLooper();

    3.通过 Looper 我们就可以创建子线程的 handler 了
     

    Handlr handler=new Handler(looper);

    通过该 handler 发送消息,就会在子线程执行;
    提示:如果要 handlerThread 停止:

    handlerThread.quit();

    完整测试代码:
     

    HandlerThread hanlerThread = new HandlerThread("子线程");
    hanlerThread.start();
    final Handler handler = new Handler(hanlerThread.getLooper()) {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Log.d("----->", "线程:" + Thread.currentThread().getName());
        }
    };
    findViewById(R.id.bt).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            handler.sendEmptyMessage(100);
        }
    });

    像在 intentService(子线程)中,如果要回掉在 UI 线程怎么办呢?
     

    new Handler(getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            // person.getName() Realm objects can only be accessed on the thread they were created.
            Toast.makeText(getApplicationContext(), "Loaded Person from broadcast-receiver->intent-service: " + info, Toast.LENGTH_LONG).show();
        }
    });

     

    展开全文
  • 如何在子线程中创建Handler?

    千次阅读 2015-12-24 17:57:02
    在子线程中创建handler,要确保子线程有Looper,UI线程默认包含Looper 我们需要用到一个特殊类  HandlerThread 这个类可以轻松的创建子线程handler 创建步骤: 1: 创建一个HandlerThread,即创建一个包含Looper的...

    也许大家创建Handler都不陌生,但是如果要在子线程创建Handler,大家未必都能正确,

    在子线程中创建handler,要确保子线程有Looper,UI线程默认包含Looper

    我们需要用到一个特殊类 

    HandlerThread
    这个类可以轻松的创建子线程handler
    
    
    创建步骤:
    1: 创建一个HandlerThread,即创建一个包含Looper的线程
       HandlerThread的构造函数有两个
      public HandlerThread(String name) {
            super(name);
            mPriority = Process.THREAD_PRIORITY_DEFAULT;
        }
        
        /**
         * Constructs a HandlerThread.
         * @param name
         * @param priority The priority to run the thread at. The value supplied must be from 
         * {@link android.os.Process} and not from java.lang.Thread.
         */
        public HandlerThread(String name, int priority) {
            super(name);
            mPriority = priority;
        }


    这里我们使用第一个就好:
    HandlerThread handlerThread=new HandlerThread("xuan");
    handlerThread.start();//创建HandlerThread后一定要记得start();
    
    
    通过HandlerThread的getLooper方法可以获取Looper
    Looper looper=handlerThread.getLooper();
    
    
    通过Looper我们就可以创建子线程的handler了
    Handlr handler=new Handler(looper);
    
    
    通过该handler发送消息,就会在子线程执行;
    提示:如果要handlerThread停止:handlerThread.quit();
    
    
    完整测试代码:
      HandlerThread hanlerThread = new HandlerThread("子线程");
            hanlerThread.start();
            final Handler handler = new Handler(hanlerThread.getLooper()) {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    Log.d("----->", "线程:" + Thread.currentThread().getName());
                }
            };
            findViewById(R.id.bt).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    handler.sendEmptyMessage(100);
                }
            });

    结果:
    12-24 10:13:15.881 5024-5052/gitosctest.gitosc_studyproject D/----->: 线程:子线程
    
    
    
    像在intentService(子线程)中,如果要回掉在UI线程怎么办呢?
     new Handler(getMainLooper()).post(new Runnable() {
                        @Override
                        public void run() {
                            // person.getName() Realm objects can only be accessed on the thread they were created.
                            Toast.makeText(getApplicationContext(), "Loaded Person from broadcast-receiver->intent-service: " + info, Toast.LENGTH_LONG).show();
                        }
                    });


    
    

    展开全文
  • 四、在子线程中创建Handler 五、总结说 1、Handler的创建 系列文章 Handler异步消息传递机制(一)Handler常用基本用法 Handler异步消息传递机制(二)在子线程中创建Handler Handler异...

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

    目录

    一、前言

    二、简介

    三、在主线程中创建Handler

    四、在子线程中创建Handler

    五、总结说

    1、Handler的创建


    系列文章

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

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

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

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

    一、前言

    上一篇文章我们讲到了Handler消息传递机制的最常见用法,我们在主线程创建了Handler对象,然后在新启动的线程创建一个Message对象,然后借助Handler对象发送出去,之后在Handler的handleMessage()方法中获得刚才发送的Message对象,然后就可以进行UI更新操作了。想了解的可参考Handler异步消息传递机制(一)常用实现方式

    二、简介

    依稀记得13年的某一天一个新来的Android同事,他说我运行程序出现bug了,报的错误信息为:java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare(),你知道怎么解决吗?

    因为我有收集bug问题解决方式的习惯,于是我找了找自己的笔记给他发了一个链接。然后没过几秒,又问你知道为什么吗?当时有点懵,因为我完全没有印象。平时也不喜欢去记忆一些东西,除非是刚不久用到的东西才会有所印象吧,所以我的回答是:“ 很久了不是记得很清楚了”。

    当时感觉还是挺纳闷的,不就是new Hanlder发送消息吗?于是找了一些资料复习了一下。确实不过即使只是简单new一下,还是有不少地方需要注意的!这也使我以后对技术点的探究逐渐的深入了。

    我们先尝试在程序中创建两个Handler对象,一个在主线程中创建,一个在子线程中创建,看会有什么效果?

    三、在主线程中创建Handler

    详见上篇文章 Handler异步消息传递机制(一)常用实现方式 ,它是典型的在主线程中创建Handler的实例

    四、在子线程中创建Handler

    我们继续以文章 Handler异步消息传递机制(一)Handler常用实现方式 的demo为例,我们把主线程创建的Hanlder注释掉,然后把 Handler 的创建挪到新启动的子线程中,具体代码如下:

    package com.luminal.handler_download;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.support.v7.app.AppCompatActivity;
    import android.widget.TextView;
    
    
    public class MainActivity extends AppCompatActivity {
        private  TextView show_text;
        private String strMsg;
        private Handler handler;
    
        //在主线程中获取、处理消息
    //    private Handler handler = new Handler() {
    //        @Override
    //        public void handleMessage(Message msg) {
    //            switch (msg.what) {
    //                case 1://下载成功
    //                    strMsg = strMsg +"\n"+ "2、apk下载成功。。。开始自动安装下载好的apk!";
    //                    show_text.setText(strMsg);
    //                    break;
    //                case 2://下载失败
    //                    strMsg = strMsg +"\n"+ "apk下载失败!";
    //                    show_text.setText(strMsg);
    //                    break;
    //
    //                default:
    //                    break;
    //            }
    //        }
    //    };
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            show_text = (TextView) findViewById(R.id.show_text);
    
            downloadApkFile();
    
        }
    
    
        /**
         *  下载apk文件
         *  注:Android 6.0以上需要申请读写权限
         */
        private void downloadApkFile() {
    
            strMsg = "1、开始下载apk。。。";
            show_text.setText(strMsg);
    
            new Thread() {//在新启动的子线程,调用下载app的代码,并发送消息、反馈结果
                public void run() {
    
                    handler = new Handler() {
                        @Override
                        public void handleMessage(Message msg) {
                            switch (msg.what) {
                                case 1://下载成功
                                    strMsg = strMsg +"\n"+ "2、apk下载成功。。。开始自动安装下载好的apk!";
                                    show_text.setText(strMsg);
                                    break;
                                case 2://下载失败
                                    strMsg = strMsg +"\n"+ "apk下载失败!";
                                    show_text.setText(strMsg);
                                    break;
    
                                default:
                                    break;
                            }
                        }
                    };
    
    
                    DownLoadAppFile downLoadFile = new DownLoadAppFile();
                    downLoadFile.download(null, handler, null);
    
                };
            }.start();
        }
    }
    

    然后运行程序,你会发现,在子线程中创建的Handler是会导致程序崩溃的,提示的错误信息如下:

       java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
            at android.os.Handler.<init>(Handler.java:200)
            at android.os.Handler.<init>(Handler.java:114)
            at com.luminal.handler_download.MainActivity$1$1.<init>(MainActivity.java:60)
            at com.luminal.handler_download.MainActivity$1.run(MainActivity.java:60)

    报错信息为:java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare(),具体指向代码错误第60行,创建Handler的语句:handler = new Handler() 

    英文直译下,不能在没有调用 Looper.prepare() 的线程中创建Handler,那我们试试在线程中先调用一下Looper.prepare(),再创建Handler对象。

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

    然后再运行一下程序,果然这样就不会崩溃了,你会发现bug就这么神奇的解决了,但是这时候UI不能更新了!

    那么为什么子线程不调用 Looper.prepare() 就创建Handler会报错呢?子线程调用了Looper.prepare()、创建Handler以后,UI界面如何更新呢?欲知故事如何,请看下篇文章的整理分解吧!

    五、总结说

    1、Handler的创建

    (1)一般在主线程中创建Handler

    (2)在子线程创建Handler会报错,错误信息为:java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() ,意思是不能在没有调用 Looper的prepare方法的线程中创建Handler,所以我们先要调用Looper的prepare方法

     

     

     

     

     

     

     

    展开全文
  • 分析完上面那篇文章,基本理解了handler的实现原理,乘热打铁,这里我们利用handler原理,在子线程中创建一个handler和looper 可能很多面试时候问道,子线程中能不能new一个handler ? 答案是可以的,但是因为主线程系统...

    分析完上面那篇文章,基本理解了handler的实现原理,乘热打铁,这里我们利用handler原理,在子线程中创建一个handler和looper

    可能很多面试时候问道,子线程中能不能new一个handler ?

    答案是可以的,但是因为主线程系统默认在ActivityThread中已将帮我们创建好一个looper和MessagQueue,我们不需要手动去创建

    (手动创建会出错,因为一个线程中默认只运行一个looper和MessageQueue,具体见ThreadLocal代码原理),

    而子线程中没有looper,我们必须学习ActivityThread中的代码手动创建一个Looper(MessageQueue不用创建,因为它在looper的构造方法中已经默认创建好了)

    1. 上代码,子线程类,里面维护了一个looper
      1.   

        import android.os.Handler;
        import android.os.Looper;
        import android.os.SystemClock;
        /**
        * 子线程looper所在的子线程类
        * @author Administrator
        *
        */
        public class MyLooperThread extends Thread {
        private Looper mLooper;
        int i=5;
        /**
        * MainActivity中handler
        */
        private Handler mHandler;
        /**
        * 构造方法接受主线程的Handler 方便用主线程的handler去发送消息给主线程的looper
        * @param mHandler
        */
        public MyLooperThread(Handler mHandler) {
        super();
        this.mHandler = mHandler;
        }
        private Handler looperThreadHandler=new Handler(){
        public void handleMessage(android.os.Message msg) {
        switch (msg.what) {
        case 1:
        System.out.println("主线程的消息来了....");
        break;

        
        

        default:
        //MyThread的线程发送一个0的消息, 执行一个耗时操作
        System.out.println("开始执行耗时操作....");
        SystemClock.sleep(2000);
        SystemClock.sleep(2000);
        if(i>0){
        i-=2;
        System.out.println("耗时操作已完下执行下一个....");
        //不断轮询执行
        looperThreadHandler.sendEmptyMessage(0);
        }else{
        //操作完成 发送消息到主线程
        mHandler.sendEmptyMessage(0);
        System.out.println("所有任务已完成,等待ing....");
        }
        break;
        }

        };
        };

        @Override
        public void run() {
        super.run();
        //初始化一个looper 其构造方法中默认已经
        Looper.prepare();
        synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
        }
        Looper.loop();
        System.out.println("执行了吗");

        }

        public Looper getmLooper() {
        return mLooper;
        }
        public Handler getHandler() {
        return looperThreadHandler;
        }
        public void setHandler(Handler handler) {
        this.looperThreadHandler = handler;
        }

        }

        上面的代码有点长,主要是创建了一个子线程类,然后在其run()方法里面创建一个looper并轮询,构造方法中接受一个主线程的handler,以便于耗时操作完成之后,利用这个handler发送消息给主线程,这里我们可以发现,要想向不同的线程中发消息,必须要获取向对应线程的handler,而handler在哪个线程创建的,就已经和当前线程绑定在一起了

    2. 第二个类 线程类 主要作用是用这个线程去向上面的looper线程发一个消息,启动它的耗时任务
      1.  
        /**
         * 线程类  在子线程中获取looper并发空消息
         * @author MR.wang
         *
         */
        public class MyThread extends Thread {
        
            MyLooperThread looperThread;
        
            public MyThread(MyLooperThread looperThread) {
                super();
                this.looperThread = looperThread;
            }
        
            @Override
            public void run() {
                super.run();
                looperThread.getHandler().sendEmptyMessage(0);
                System.out.println("子线程中的执行了吗");
            }
            
        
        }

        这个代码相对好理解些,构造方法中接受looper线程中的handler,以便给他发消息,最后在run()方法发个消息,启动looper线程的耗时任务.

    3. 第三个类,主线程的hanler所在的类
      1.  
        import android.app.Activity;
        import android.os.Bundle;
        import android.os.Handler;
        import android.widget.Toast;
        /**
         * 主线程类 
         * @author MR.wang
         */
        public class MainActivity extends Activity {
            private Handler handler = new Handler() {
                public void handleMessage(android.os.Message msg) {
                    //子线程执行耗时操作完成 通知主线程
                    Toast.makeText(MainActivity.this, "所有任务已完成", Toast.LENGTH_SHORT)
                            .show();
                    //获取子线程的handler并发送一个消息给子线程的looper
                    looperThread.getHandler().sendEmptyMessage(1);
                };
            };
            private MyLooperThread looperThread;
        
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                //初始化子线程中的looper
                looperThread = new MyLooperThread(handler);
                // 开启子线程中的looper
                looperThread.start();
                //初始化一个子线程 用于给looper所在的子线程发送消息启动它
                MyThread thread = new MyThread(looperThread);
                thread.start();
            }
        
        }

        着重看看onCreate方法,初始化一个looper线程,传入当前主线程的handler,然后让另外一个子线程去给looper线程发一个消息,执行耗时任务,looper线程中耗时任务执行完毕,拿着主线程传入的handler给主线程发个消息,最后主线程的handlMessage()方法收到消息,Toast出来,完成了主线程到子线程之间的消息对接

         
    4. 最后总结一下
      1. handler创建的时候,就与当前线程绑定起来,要给一个线程发消息,获取到此线程的hanler发送消息即可.
      2. 主线程中ActivityThread默认帮我们创建好了一个looper和MessageQueue,因此我们不需要手动创建,若需要在子线程中创建一个handler,则子线程中必须也有一个looper和MessageQueue与之对应,所有,子线程中可以有handler,只需我们手动创建一个looper即可(Messagequeue在looper构造方法中自动创建)
      3. 主线程的handlMessage中尽量不要执行任何耗时操作,因为容易造成主线程阻塞(UI线程5秒,服务10秒)
      4. handler looper Messagequeue三个组合起来,和线程池特别类似,可以利用此,维护一个类似与线程池的框架,用来处理耗时多线程操作,比如网络下载多个图片等

    转载于:https://www.cnblogs.com/Android-MR-wang/p/4291391.html

    展开全文
  • 复习一下消息机制,如下代码: new Thread() { Handler handler = null; [@Override](https://my.oschina.net/u/1162528) public void run() { ...
  • 自从开始写代码以来,一直饱受取名之苦,这篇博客实在不知道该给它取个什么名字,总之,...采集用户操作的事件信息,例如某个用户何时采用了何种支付方式购买了何种产品,可以购买成功的回调中将数据信息封装为Ma
  • 如何在子线程中创建并使用Handler

    千次阅读 2019-02-20 17:45:42
    上一篇文章我们从源代码的角度分析了Handler的实现,这篇文章我们说下如何在子线程中创建Handler在子线程中创建Handler只需2步: 创建looper:Looper.prepare() 启动looper:Looper.loop() 为了创建当前...
  • 在子线程中使用Handler

    2020-03-18 16:57:36
    在子线程中创建Handler时会抛出RuntimeException异常,提示Can’t create handler inside thread …,这是由于在Handler构造时没有找到当前线程的Looper导致的 mLooper = Looper.myLooper(); if (mLooper == null) {...
  • 在子线程创建handler的写法: new Thread(new Runnable() { @Override public void run() { ... //2、在子线程中创建Handler handler = new Handler() { @Override public void ha
  • Android如何在子线程中使用Handler

    千次阅读 2019-09-16 14:59:23
    在子线程中使用Handler,需要先清楚Handler是如何工作的,这里我画一个简图描述下Handler的工作过程: 这里有提到4个概念: Handler:作为消息的发送和处理者,可以在其它线程中使用handler把消息Message存放...
  • 1. 在子线程中创建一个handler对象,让这个handler对象获取主线程的looper,这样才能把这个handler中的消息发送到ui线程的消息队列中 下面这个界面当点击updateui按钮就会创建一个对象然后调用它的更新图片和文字的...
  • Handler handler= new Handler(Looper. myLooper ()){ @Override public void handleMessage (Message msg) { textView .setText(msg. obj + "" ) ; } } ; int i= 0 ; while ( true ){ ...
  • 如果在一个子线程中创建的类创建一个Handler消息对象,会报错。 解决方法是在子线程调用主线程的Handler,在执行创建操作。
  • 1. 前言众所周知,在android中,非ui线程中是不能更新ui,如果在子线程中做ui相关操作,可能会出现程序崩溃。...初始化Handler有两个地方,一个在主线程中,一个在子线程中,具体有什么区别呢,接下来
  • 这是因为Handler对象与其调用者同一线程中,如果Handler中设置了延时操作,则调用线程也会堵塞。每个Handler对象都会绑定一个Looper对象,每个Looper对象对应一个消息队列(MessageQueue)。如果在创建Handler时...
  • 插件APP启动某个service A 的代码是在子线程中执行的。 service A 启动后有创建一个Handler。 正常APP不编译成Shadow 插件APP,运行没有问题。 编程插件之后运行,就报这个错误。 <p>07-01 20:24:46.316...
  • (1)新启动的线程中发送消息; (2)主线程中获取、处理消息。 程序员自己启动的子线程,必须自己创建一个Looper对象,并启动它。 步骤如下: (1)调用Looper.prepare()方法为当前线程创建Looper对象,创建...
  • 假设在子线程中更新UI 的话会提演示样例如以下错误:Only the original thread that created a view hierachy can touch its view((仅仅有原来的线程创建一个视图层次能够触摸它的视图)。  仅仅能...
  • Android--Handler的用法:在子线程中更新界面 本文主要介绍Android的Handler的用法。Handler能够发送Messsage和Runnable对象到与其相关联的线程的消息队列。每一个Handler对象与创建它的线程相...
  • 每个Handler对象与创建它的线程相关联,并且每个Handler对象只能与一个线程相关联。  Handler一般有两种用途:1)执行计划任务,你可以再预定的实现执行某些任务,可以模拟定时器。2)线程间通信。Android的应用...
  • Looper、Handler在子线程中的应用

    千次阅读 2016-04-28 16:45:01
    Looper类:为一个线程开启一个消息循环,里面有一个消息队列,新线程是没有开启消息循环的,所以需要用到Looper的方法创建消息循环(主线程除外,主线程会自动为其创建Looper对象,开启消息循环),MessageQueue存放...
  • 版权声明:本文为博主原创文章,未经博主允许...每个Handler对象与创建它的线程相关联,并且每个Handler对象只能与一个线程相关联。  Handler一般有两种用途:1)执行计划任务,你可以再预定的实现执行某些任务,
  • Android——线程创建以及handler

    千次阅读 2013-10-15 16:46:17
    一:创建子线程: 二:子线程访问主线程的方法: (1) Activity.runOnUiThread(Runnable) -------->UI线程里运行指定的动作,如果当前线程是UI线程,则立刻被执行 ,如果是主线程,则该动作被发送到UI线程的...
  • 相关文章: Handler的工作原理,为什么在子线程中...我们先来在子线程中创建一个Handler: public class MyActivity2 extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 935
精华内容 374
关键字:

在子线程中创建handler