美文网首页
Handler(一) - 如何创建Handler

Handler(一) - 如何创建Handler

作者: 世道无情 | 来源:发表于2019-01-27 16:27 被阅读0次

    1. 概述


    在子线程更新UI程序会崩溃,解决方案就是:创建 Message对象,然后用handler发送出去,然后调用handler的handleMessage(Message msg),从中取出msg对象,在这里更新UI即可,这种方式叫做 异步消息处理线程

    2. 创建handler对象


    下边分别在主线程和子线程中创建handler对象:
    public class MainActivity extends AppCompatActivity {
    
        private Handler handler1 ;
        private Handler handler2 ;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // 方式 1:在主线程中创建handler
            handler1 = new Handler() ;
            // 方式 2:在子线程中创建handler
            new Thread(new Runnable() {
                @Override
                public void run() {
                    handler2 = new Handler() ;
                }
            }).start();
        }
    }
    
    运行结果:

    在子线程中创建的handler崩溃,报错信息为Can't create handler inside thread that has not called Looper.prepare() :意思是 没有调用Looper.prepare()禁止创建handler,也就是说在子线程中创建handler对象,先调用 Looper.prepare()方法:就可以

            new Thread(new Runnable() {
                @Override
                public void run() {
                    Looper.prepare();
                    handler2 = new Handler() ;
                }
            }).start();
    

    3. handler源码分析


    1>:为什么在子线程中 不调用 Looper.prepare() ,创建handler 对象就报错?

    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());
                }
            }
            
            // 获取looper对象,如果 looper 对象为空,则抛出异常,异常就是上边程序报错的错误
            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 = callback;
            mAsynchronous = async;
        }
    

    什么时候 looper对象为空,可以看下 Looper.myLooper():

        public static @Nullable Looper myLooper() {
            // 从 sThreadLocal 中取出 looper 对象,如果 sThreadLocal 中存在 looper对象,就返回,
            // 如果不存在,就返回空
            return sThreadLocal.get();
        }
    

    到这里应该可以想到,是在 Looper.prepare()方法中获取的 looper 对象,就是在子线程中创建 handler 对象之前 调用的 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中是否存在 looper,如果为null,就 new Looper对象设置进去
            sThreadLocal.set(new Looper(quitAllowed));
        }
    

    到这里就解释了:
    第一:在子线程中创建 handler 之前,必须要先调用 Looper.prepare()来获取 looper 对象,如果 looper 对象为null,那么在 handler 构造方法 就会报错:Can't create handler inside thread that has not called Looper.prepare();
    第二:一个线程中只有一个 looper 对象;

    2>:为什么在 主线程中 不用调用 Looper.prepare(),不会崩溃?

    原因是:在程序一启动的时候,系统已经自动帮我们调用了 Looper.prepare()方法了,在 ActivityThread中的 main() 方法:

    public static void main(String[] args) {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
            SamplingProfilerIntegration.start();
    
            CloseGuard.setEnabled(false);
    
            // 这个方法调用 Looper.prepare() 方法,如下
            Looper.prepareMainLooper();
    
            ActivityThread thread = new ActivityThread();
            thread.attach(false);
    
            if (false) {
                Looper.myLooper().setMessageLogging(new
                        LogPrinter(Log.DEBUG, "ActivityThread"));
            }
    
            Looper.loop();
        }
    
    
        public static void prepareMainLooper() {
            // 这个就是 Looper.prepare()方法
            prepare(false);
            synchronized (Looper.class) {
                if (sMainLooper != null) {
                    throw new IllegalStateException("The main Looper has already been prepared.");
                }
                sMainLooper = myLooper();
            }
        }
    

    可以看到,应用程序主程序中始终存在 looper 对象,不用手动调用 Looper.prepare()方法;

    4. 总结


    1>:创建handler有2种方式:主线程和子线程;

    主线程中可以直接创建handler对象,不用调用 Looper.prepare()方法,因为程序一启动系统就帮我们调用了该方法;
    子线程中必须先调用 Looper.prepare(),然后才能创建 handler 对象,否则直接报错;

    2>:一个线程对应一个 looper 对象;

    相关文章

      网友评论

          本文标题:Handler(一) - 如何创建Handler

          本文链接:https://www.haomeiwen.com/subject/pbtwkqtx.html