Handler学习(一)- 使用

handler使用:

1)若在Activity主线程中直接用handler -  handler和looper在主线程

handler和looper均在主线程,这里可以不需要自己调looper,因为activity的ActivityThread中已经创建并调了loop,而且由于handler一般是用来更新主线程UI的,所以需要保证消息分发来自同一个线程,否则界面更新处理来自多个looper发送的消息会出现布局混乱,而加锁等线程同步会让更新变的更慢还可能出现死锁,得不偿失。

ActivityThread的main函数代码段最下面

    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

        // Install selective syscall interception
        AndroidOs.install();

        long startTime = CheckTime.getTime();
        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");

        ...

        Looper.prepareMainLooper();  //here prepare 创建looper

        ...

        ActivityThread thread = new ActivityThread();

        ...

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        CheckTime.checkTime(startTime, "ActivityThreadMain", 400);
        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        Looper.loop();  //looper.loop 从messageQueneu取消息分发

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

 上面代码可看到ActivityThread中已经有调用prepareMainLooper,所以当我们在Activity主线程中调用Looper.prepare时,会报 E AndroidRuntime: Caused by: java.lang.RuntimeException: Only one Looper may be created per thread 这个crash.

这个异常抛出位置即在Looper.java的这里,这里sThreadLocal可以看到是static修饰的,该ThreadLocale里是有个map,以当前线程为key,value为传入的值。所以当get到当前线程中loop值不为null,即抛出该异常。

也是因为sLocaleThread,所以Handler可以轻松的取到每个线程的looper,从而获取到messageQueue中的消息

// sThreadLocal.get() will return null unless you've called prepare().
    @UnsupportedAppUsage
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

2)在Activity主线程中创建子线程,并使用handle更新UI - handler和looper在子线程中

如上,这种方式即常用handler方式,在子线程中做一些耗时操作,完成后发送handler消息,在主线程中更新UI。这里使用时就需要自己调用Loop的prepare在当前子线程创建的looper的Thread及MessageQueue做事件分发

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

上面prepare代码中调到的new Looper()即这块代码,thread 相当于looper这里可以看到looper和MessageQueue是一一对应的

3)使用HandlerThread - handler和looper在子线程

android 开发现在更推崇HandlerThread 这种方式来实现,HandlerThread已经帮我们创建好子线程,并prepare,loop了looper

HandlerThread继承Thread,重写了run方法,在run方法中创建looper并loop

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

当使用该HandlerThread get looper时,如下,可以看到如果子线程是alive的,则会等待looper被创建,并返回。所以这里返回的looper是运行在子线程中的。

 /**
     * 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;
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值