从后台线程调用 startActivity 并且主线程被阻塞时,Activity 延迟启动

Posted

技术标签:

【中文标题】从后台线程调用 startActivity 并且主线程被阻塞时,Activity 延迟启动【英文标题】:Activity starts with delay when calling startActivity from background thread and the main thread being blocked 【发布时间】:2019-08-25 00:06:51 【问题描述】:

我正在尝试阻止主线程并向用户显示对话活动(在另一个 android:process 中运行)以做出是/否决定。用户单击是或否后,对话活动结束,主线程恢复。请注意,我的项目需要阻塞主线程。

开始对话:

private boolean getUserDecision() 
    DialogRunnable dialogRunnable = new DialogRunnable();
    Thread thread = new Thread(dialogRunnable);
    thread.start();
    while (thread.isAlive()) 
        try 
            // block the thread until user enters his decision
            thread.join();
         catch (InterruptedException e) 
            e.printStackTrace();
        
    
    return dialogRunnable.decision;

还有DialogRunnable:

class DialogRunnable extends Runnable 
    public boolean decision;

    @Override
    public void run() 
        Looper.prepare();
        Intent intent = /* intent for launching the dialog */
        intent.setResultMessenger(new Messenger(new Handler() 
            @Override
            public void handleMessage(Message msg) 
                Looper.myLooper().quit();
                decision = msg.arg1 == 1;
            
        ));
        startActivity(intent);
        Looper.loop();
    

意外行为

如果在主线程上调用getUserDecision,对话框会在明显延迟(~ 1 秒)后启动,但从后台线程调用该方法会立即启动对话框。为什么?

【问题讨论】:

“请注意,我的项目需要阻塞主线程”——你为什么这么认为? @CommonsWare 我实际上正在为 AOSP 开发一个系统框架,它挂钩某些绑定器调用。这不是一个普通的应用程序。 你可以试试developer.android.com/reference/android/os/AsyncTask 如果阻塞主线程,Android 会抛出 ANR。 @DavidWasser 没有 ANR,一切正常。唯一的问题是前面提到的延迟。 【参考方案1】:

这是因为应用程序的onPause 的活动管理器服务waiting 完成。并且由于主线程被阻塞,ActivityManagerService 等待500ms 并放弃,然后启动下一个活动。

【讨论】:

以上是关于从后台线程调用 startActivity 并且主线程被阻塞时,Activity 延迟启动的主要内容,如果未能解决你的问题,请参考以下文章

为啥我从后台工作人员调用的委托在主线程中运行

本机调用阻塞主线程

通过 Unity 中的后台线程调用主线程中的函数

CoreMotion 显然是从后台线程调用 UI API

Dbus/GLib 主循环,后台线程

AsyncTask 坑 哪些线程可以调用AsyncTask