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
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Kotlin中,你可以使用`Handler`来处理和管理线程之间的消息传递。以下是在Kotlin中创建`Handler`的示例代码: ```kotlin import android.os.Handler import android.os.Looper import android.os.Message // 在主线程中创建Handler val handler = Handler(Looper.getMainLooper()) // 在后台线程中创建Handler val backgroundHandler = Handler(Looper.getMainLooper()) // 在主线程中发送消息到Handler handler.post { // 在主线程中执行操作 } // 在后台线程中发送消息到Handler backgroundHandler.post { // 在后台线程中执行操作 } // 在主线程中处理消息 val mainHandler = object : Handler(Looper.getMainLooper()) { override fun handleMessage(msg: Message) { // 处理接收到的消息 } } // 发送消息到主线程的Handler mainHandler.sendMessage(Message.obtain().apply { // 设置消息内容 }) ``` 上述代码中,我们首先通过`Handler(Looper.getMainLooper())`在主线程中创建了一个`handler`对象。类似地,你也可以在后台线程中创建`Handler`,只需传递对应的`Looper`对象即可。 然后,你可以使用`post`方法将任务/操作发送到相应的`Handler`,以在对应的线程中执行。例如,通过`handler.post { }`可以将任务发送到主线程中执行,而通过`backgroundHandler.post { }`可以将任务发送到后台线程中执行。 如果你需要处理消息,可以创建一个继承自`Handler`的子类,并重写`handleMessage`方法来处理接收到的消息。你可以在`handleMessage`方法中根据消息的类型进行相应的处理逻辑。 最后,你可以使用`sendMessage`方法将消息发送到主线程的`Handler`中,并在`handleMessage`方法中处理接收到的消息。 请注意,在Android中,只有主线程(也称为UI线程)可以更新UI元素。如果你需要在其他线程中更新UI,请使用`Handler`或其他适当的方法将任务发送到主线程执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值