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

    2017-07-12 15:20:18
    朋友跳槽,面试时被问到子线程可以创建Handler吗?对于这个问题,其实我也是有点疑惑,暂且不论子线程创建Handler的应用场景,对于能不能创建这个事情我还是比较好奇的,作为一名爱较真的程序猿,马上打开Android...

    朋友跳槽,面试时被问到子线程可以创建Handler吗?对于这个问题,其实我也是有点疑惑,暂且不论子线程创建Handler的应用场景,对于能不能创建这个事情我还是比较好奇的,作为一名爱较真的程序猿,马上打开AndroidStudio写个demo测试。

         new Thread(){
                @Override
                public void run() {
                    Handler handler=new Handler();
                }
            }.start();

    经过验证直接采用new的方式在子线程中创建Handler会出现错误:”Can’t create handler inside thread that has not called Looper.prepare()。按照提示,应该在new handler()之前,调用Looper.prepare();但是为什么要调用这个方法呢?这个方法又是什么作用呢?看下源码:

        public static void prepare() {
            prepare(true);
        }
    
        private static void prepare(boolean quitAllowed) {
        //此处保证一个线程只有一个looper
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            sThreadLocal.set(new Looper(quitAllowed));
        }

    原来prepare方法为当前的Handler创建了一个新的looper,但是经过尝试,子线程中handler发的消息不能被取到,这是为什么呢?为什么activity中创建的handler就可以被取到?通过查看源码,发现,在主线程中创建的Handler,也拥有looper,而且调用了looper.loop(),开启消息消息处理。于是,我们采用如下方法在子线程中创建Handler

           new Thread(){
                @Override
                public void run() {
                    Looper.prepare();
                    Handler handler=new Handler(Looper.myLooper());
                    Looper.loop();
                }
            }.start();

    大功告成。
    经过一番思考,恍然大悟,原来子线程创建Handler有着这样的应用场景:子线程中去创建一个Handler,使用这个handler实例在任何其他线程中发送消息,最终处理消息的代码都会在创建Handler实例的线程中运行。
    朋友们,喜欢就支持下,如有错误,敬请指正!

    展开全文
  • 309_子线程创建Handler

    2016-10-12 21:15:24
    子线程创建Handler 这篇是看郭霖大神博客写的 相当于读书笔记而已 博客地址是:http://blog.csdn.net/guolin_blog/article/details/9991569 一.子线程中不能创建Handler  new Thread(new ...




    子线程创建Handler


    这篇是看郭霖大神博客写的


    相当于读书笔记而已


    博客地址是:http://blog.csdn.net/guolin_blog/article/details/9991569




    一.子线程中不能创建Handler
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Handler handler = new Handler();
                }
            }).start();


    这样会报错:
    Can't create handler inside thread that has not called Looper.prepare()








    二.创建之前增加Looper.prepare(); 
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Looper.prepare();
                    Handler handler = new Handler();
                }
            }).start();








    三.为什么要增加Looper.prepare();
    看看源码
    看看Handler的构造函数
        public Handler() {  
            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 that has not called Looper.prepare()");  
            }  
            mQueue = mLooper.mQueue;  
            mCallback = null;  
        }  


    我们看到先是mLooper = Looper.myLooper();
    然后判断如果mLooper为空,就报这个错误








    四.为什么会出现mLooper的情况
    看看myLooper()这个方法


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


    这个方法的意思就是:从sThreadLocal中取出一个Looper
    mLooper为空,就说明sThreadLocal里面没有Looper










    五.为什么sThreadLocal里面没有Looper
    我们来看看Looper的prepare()方法就完全明白了
        public static final void prepare() {  
            if (sThreadLocal.get() != null) {  
                throw new RuntimeException("Only one Looper may be created per thread");  
            }  
            sThreadLocal.set(new Looper());  
        }  


    调用prepare方法的时候也是先调用sThreadLocal的get方法
    检查一下现在sThreadLocal里面有没有Looper
    如果sThreadLocal不为空,那么就报错:一个线程只能有一个Looper
    如果sThreadLocal里面还没有Looper,那么就给sThreadLocal设置一个new Looper()








    六.为什么主线程不需要prepare
    因为程序启动的时候,系统已经自动调用了主线程的Looper.prepare()方法
        public static void main(String[] args) {  
            SamplingProfilerIntegration.start();  
            CloseGuard.setEnabled(false);  
            Environment.initForCurrentUser();  
            EventLogger.setReporter(new EventLoggingReporter());  
            Process.setArgV0("<pre-initialized>");  
            Looper.prepareMainLooper();  
            ActivityThread thread = new ActivityThread();  
            thread.attach(false);  
            if (sMainThreadHandler == null) {  
                sMainThreadHandler = thread.getHandler();  
            }  
            AsyncTask.init();  
            if (false) {  
                Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));  
            }  
            Looper.loop();  
            throw new RuntimeException("Main thread loop unexpectedly exited");  
        }  


    里面Looper.prepareMainLooper()就是








    七.总结:
    主线程已经自动prepare过了,子线程中创建Handler需要prepare.





    展开全文
  • Android 子线程创建handler

    千次阅读 2017-12-24 22:55:05
    据上篇我转载的 Handler,Looper, Message 三者关系深入消化,理解后。...但是有人会疑问,那子线程中是否可以创建一个Handler,仅仅通知线程呢? 答案是肯定的。 直接上代码。 new Thread(new Runnable() {

    据上篇我转载的 Handler,Looper, Message 三者关系深入消化,理解后。我们会很清楚地使用了子线程和Ui线程通信的问题。

    即解决了一个网络请求成功或者失败后,通知ui线程更新界面的case。

    但是有人会疑问,那子线程中是否可以创建一个Handler,仅仅通知线程呢? 答案是肯定的。

    直接上代码。

    1. new Thread(new Runnable() {  
    2.             public void run() {  
    3.                 Handler handler = new Handler(){  
    4.                     @Override  
    5.                     public void handleMessage(Message msg) {  
    6.                         Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();  
    7.                     }  
    8.                 };  
    9.                 handler.sendEmptyMessage(1);  
    10.                   
    11.             };  
    12.         }).start();  
    很遗憾,会报错:

    01-12 02:49:31.814: E/AndroidRuntime(2226): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare(),需要looper.prepare().

    1. new Thread(new Runnable() {  
    2.             public void run() {  
    3.                 Looper.prepare();  // 此处获取到当前线程的Looper,并且prepare()  
    4.                 Handler handler = new Handler(){  
    5.                     @Override  
    6.                     public void handleMessage(Message msg) {  
    7.                         Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();  
    8.                     }  
    9.                 };  
    10.                 handler.sendEmptyMessage(1);  
    11.                   
    12.             };  
    13.         }).start();  
    运行后发现还是报错,因为上篇博文有提到

    1、Looper.prepare()是给这个Thread创建Looper对象,一个Thead只有一个Looper对象。

    2、Looper对象需要一个MessageQueue对象一个Looper实例也只有一个MessageQueue。

    3、调用Looper.loop();  不断遍历MessageQueue中是否有消息。

    4、Handler 作用是发消息到MessageQueue,从而回掉Handler 的HandleMessage的回掉方法。

    1. new Thread(new Runnable() {  
    2.             public void run() {  
    3.                 Looper.prepare();  
    4.                 Handler handler = new Handler(){  
    5.                     @Override  
    6.                     public void handleMessage(Message msg) {  
    7.                         Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();  
    8.                     }  
    9.                 };  
    10.                 handler.sendEmptyMessage(1);  
    11.                 Looper.loop();  
    12.             };  
    13.         }).start();  
    这样就Ok了。


    方法二:获取主线程的looper,或者说是UI线程的looper

    这个方法简单粗暴,不过和上面的方法不一样的是,这个是通过主线程的looper来实现的


    1. new Thread(new Runnable() {  
    2.             public void run() {  
    3.                 Handler handler = new Handler(Looper.getMainLooper()){ // 区别在这!!!!  
    4.                     @Override  
    5.                     public void handleMessage(Message msg) {  
    6.                         Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();  
    7.                     }  
    8.                 };  
    9.                 handler.sendEmptyMessage(1);  
    10.             };  
    11.         }).start();  


    大家如果有业务需要在子线程处理消息,用以上任意一种方法都是可以的。


    展开全文
  • 主线处理handler,大家都比较熟悉了,就是通过在onCreat中,new Handler  handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { System.out.println(...

    主线程处理handler,大家都比较熟悉了,就是通过在onCreat中,new Handler 

    handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            System.out.println("根据拦截条件拦截handler");
            return false;
        }
    }){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            System.out.println("handler没有被拦截");
        }
    };

    handler的构造方法有多个,可以没有参数,默认 Handler.Callback 的 boolean handlerMessage(Message msg)返回的是false,表示不做拦截

    如果构造方法中有Callback,那么如果设置拦截条件,比如msg.what =1之类的,并且返回值改为true,那么当msg=1时就会被拦截,

    二、如何自己创建一个Handler

    在开发过程中,常常需要自己创建一个线程来处理handler,那么一定不要自己写现成,因为有可能出现多线程并发出错,那么怎么创建呢?google早就考虑到了,所以使用google提供的 HandlerThread

    HandlerThread myThread = new HandlerThread("myHandlerThread");
    myThread.start();
    Handler myHandler = new Handler(myThread.getLooper()){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            System.out.println(Thread.currentThread()+"handler收到消息");
    
        }
    };
    
    myHandler.sendEmptyMessage(1);




    展开全文
  • 如果我们想在子线程上创建Handler,通过直接new的出来是会报异常的比如: [java] view plain copy newThread(newRunnable(){ publicvoidrun(){ Handlerhandler=newHandler(){ ...
  • 前言Android 提供了Handler和Looper来来满足线程间的通信,而前面我们所说的IPC指的是进程间的通信。这是两个完全不同的概念。Handler先进先出原则,Looper类用来管理特定线程内消息的交换(MessageExchange);1、为...
  • 我们经常是在主线创建handler,创建的步骤也直接new一个就行,并没有注意在子线程中创建。 下面是概念: 1.Handler:可以看做是一个工具类,用来向消息队列中插入消息的; 2.Thread:所有与Handler相关的功能都是与...
  • Android: 子线程创建Handler的两种方法

    千次阅读 2018-12-07 17:00:10
    方式一: 获取主线的looper(UI线程的looper---Looper.getMainLooper()) 此方法是通过主线的looper来实现的,简单使用. //noinspection Convert2Lambda new Thread(new Runnable() { ... Handler ha...
  • Handler作为线程之间传递消息的机制,当它被创建时,就会自动关联当前所在位置的线程和消息队列。
  • Android 子线程子线程通过Handler通信1、创建发送消息的子线程2、创建接收消息的子线程3、编辑主函数4、编写布局文件5、运行并观察结果 1、创建发送消息的子线程 创建一个Thread1类 import android.os.Handler; ...
  • 默认情况下,ActivityThread类为我们创建的了主线程的Looper和消息队列,所以当你创建Handler之后发送消息的时候,消息的轮训和handle都是在ui线程进行的。这种情况属于子线程给主线程发消息,通知主线程更新ui…等...
  • 子线程能创建handler

    2019-11-21 15:36:22
    子线程是可以创建hanlder的,但是如果你直接使用new thread来创建,代码会报loop的空指针错误,原因如下文,但是,Google给我们提供了HandlerThread,我们当然也可以利用HandlerThread中的思想在newThread里面实现子...
  • 子线程中创建handler

    2016-05-13 15:07:16
    不在主线中需要在handler中执行 Looper.prepare(); myhandler = new Handler(new Handler.Callback() { public boolean handleMessage(Message msg) { return false; } }); Looper.loop
  • 子线程的Handler 在使用handler时,会有在子线程创建handler的场景,那我们从Looper.java的源码中摘抄下面一段创建Hander的代码段: class LooperThread extends Thread { public Handler mHandler; public ...
  • 二、为什么子线程不调用Looper.prepare(),创建Handler后会报错呢? 三、主线中的Handler之前也没有调用Looper.prepare()方法,为什么就没有崩溃呢? 四、总结说 系列文章 Handler异步消息传递机制(一)...
  • 很多时候在项目中我们会用到一些独立的类,用来处理通用的逻辑,也有可能会牵扯到切换到UI线程进行比如Toast提示,不经意间会在当前类中new Handler,比如像下面这个, 假设A是一个单例模式,在整个应用生命周期都存在...
  • 使用handler进行子线程之间通信

空空如也

空空如也

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

子线程创建handler