android学习

在子线程中如何创建Handler?

2022-01-21  本文已影响0人  GoLearning轻松学
    Handler myHandler;

    public void method(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                myHandler = new Handler(new Handler.Callback() {
                    @Override
                    public boolean handleMessage(@NonNull Message msg) {
                        return false;
                    }
                });
                Looper.loop();
            }
        });
    }

我们看这种方式,我们只能在线程中创建一个handler,但任何一个线程都应该能创建N多个handler,我们用这种方式无法创建,因为这一个线程是一个内部类,内部类,在外部类无法得到这个内部类的对象的,那么晚就无法拿到它的Looper,既然拿不到它的Looper,那么这种创建方式就是错误的,那么要怎么创建可以的呢?

public class MyHandlerThread extends Thread{
    Looper looper;
    @Override
    public void run() {
        super.run();
        Looper.prepare();
        looper = Looper.myLooper();
        Looper.loop();
    }

    Looper getLooper() {
        return looper;
    }

    @Override
    public synchronized void start() {
        super.start();
    }
}

因为我们要在多个地方,线程能够创建多个handler,那么你必须要new一个handler,new handler是必须要传looper,这个loogper必须能拿到,你能拿到这个线程对应的looper,那怎么拿呢?

  MyHandlerThread thread = new MyHandlerThread();
        thread.start();
        //这里存在着一个并发的问题
        //sleep(10);//为了解决并发问题,只能在这里睡眠10毫秒,但是在Android当中使用sleep是不可取的
        Handler handler1 = new Handler(thread.getLooper());//我无法保证这里的getLooper()不为null
        Handler handler2 = new Handler(thread.getLooper());

这里把线程封装成一个类,之后又一个独立的对象looper,所以这时候,在这个run里面prepare一下,之后把这个looper赋值保存起来,赋值之后再调用Looper.loop(),有了这个动作,我就可以再任何地方拿到,这样子下来就可以通过new 一个线程,创建线程之后拿就把这个线程的looper创建了,创建好了之后,拿就把这个looper传进handler去。
不过这里有一个并发的问题,这里不能保证getLooper()一定就有值,因为线程的执行也不会马上给你执行到run方法里面,把值赋值好,这得看CPU的心情。解决这个问题,上面用到一种指标的方式sleep(10);这个sleep在Android当中是不能这么使用的,会造成用户画面的卡顿。
HandlerThread就为我们解决了这个并发问题。来看看他是如何解决的。

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

    /**
     * This method returns the Looper associated with this thread. If this thread not been started
     * or for any reason isAlive() returns false, this method will return null. If this thread
     * has been started, this method will block until the looper has been initialized.  
     * @return The looper.
     */
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

在这里看到当“线程已经启动但是Looper对象还没有创建完成”时会进行等待,当创建完成时会唤醒等待,这时getLooper()就可以返回已经创建完成的Looper对象了。之所以需要这个“等待-唤醒”机制,因为获取Looper是在主线程中进行的,而创建Looper是在子线程中进行的,必须使用这个机制来完成两者的状态同步。

上一篇下一篇

猜你喜欢

热点阅读