Handler创建方式

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 对象;



作者:世道无情
链接:https://www.jianshu.com/p/8800b97fe4b2
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值