从服务启动活动时出现延迟

9
我有一个广播接收器,接收屏幕关闭的广播,并在屏幕关闭时启动一个活动。我把这个活动命名为LockScreenActivity。我在这个活动的onCreate()方法中添加了getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);,这样它就会出现在Android锁屏界面的上方,这正是我想要的。大部分时间它都能正常工作,但是当我按下Home按钮将任何应用程序发送到后台时,问题就发生了。
当我从任何应用程序按Home按钮返回到主屏幕,然后立即按电源按钮关闭屏幕,并在一秒钟内再次按电源按钮打开屏幕时,它会显示Android锁屏界面。我的活动会在3-4秒后才被创建,这是一个巨大的延迟,是不可接受的。在其他情况下,不会出现这种延迟。如果我已经在主屏幕停留了一段时间,或者某些其他应用程序正在运行,并且我快速连续点击电源按钮两次,我会在看到Android锁屏界面之前看到我的LockScreenActivity。
我的应用程序还有一些其他普通活动(从应用程序抽屉中启动)和一个显示持续性通知的服务。每当单击该通知时,都会启动同一LockScreenActivity。有趣的是,如果我按Home按钮最小化某个应用程序,并立即单击我的应用程序的通知,则会立即打开LockScreenActivity而没有任何延迟。
我已经搜索了很多解决方案。下面是我到目前为止尝试过的:
  1. 通过在注册广播接收器时传递处理程序来使广播接收器在单独的线程中运行
  2. 在广播接收器的onReceive()中获取一个wakelock,在LockScreenActivity的onResume()中释放它
  3. 通过在清单文件中指定不同的taskAffinity来为LockScreenActivity创建一个单独的任务堆栈。我还尝试了许多与活动堆栈相关的选项组合,但迄今为止没有什么帮助。
  4. 不再直接启动活动,而是向服务发送意图,然后由服务启动活动。很遗憾,没有任何作用。
以下是该活动和服务的清单声明:
<activity
        android:name=".LockScreenActivity"
        android:label="@string/app_name"
        android:excludeFromRecents="true"
        android:taskAffinity="@string/task_lockscreen">
</activity>
<service
        android:name=".services.BaseService"
        android:enabled="true" >
</service>

广播接收器:
public class ScreenReceiver extends BroadcastReceiver {
private static final String LOG_TAG = ScreenReceiver.class.getSimpleName();
private static final String HANDLER_THREAD_NAME = "screen_receiver_thread";
public static final String WAKELOCK_TAG = "lockscreen_overlay_create_wakelock";

@Override
public void onReceive(Context context, Intent intent) {
    if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
        WakeLockHelper.acquireWakeLock(WAKELOCK_TAG, context);
        Log.d(LOG_TAG, "Screen off");
        context.startService(BaseService.getServiceIntent(context, null, BaseService.ACTION_START_LOCKSCREEN_ACTIVITY));
    } else {
        if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
            Log.d(LOG_TAG, "Screen on");
        }
    }
}

public static void registerScreenReceiver(Context context){
    new BroadcastReceiverRegistration().execute(context);
}

private static class BroadcastReceiverRegistration extends AsyncTask<Context, Void, Void>{
    @Override
    protected Void doInBackground(Context... params) {
        Context context = params[0];
        if(Utility.checkForNullAndWarn(context, LOG_TAG)){
            return null;
        }
        HandlerThread handlerThread = new HandlerThread(HANDLER_THREAD_NAME);
        handlerThread.start();
        Looper looper = handlerThread.getLooper(); //Will block till thread is started, hence using AsyncTask
        Handler handler = new Handler(looper);

        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
        filter.addAction(Intent.ACTION_SCREEN_ON);
        BroadcastReceiver mReceiver = new ScreenReceiver();

        context.registerReceiver(mReceiver, filter, null, handler);
        return null;
    }
}
}

WakeLockHelper是一个类,它管理我应用程序中的所有唤醒锁。当服务启动时,registerScreenReceiver()将被调用。

下面是LockScreenActivity��onCreate():

protected void onCreate(Bundle savedInstanceState) {
    Log.d(LOG_TAG, "LockscreenActivity onCreate()");
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_lock_screen);
    if (savedInstanceState == null) {
        getFragmentManager().beginTransaction()
                .add(R.id.container, new LockScreenFragment())
                .commit();
    }
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    getWindow().setDimAmount((float) 0.4);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);

    int systemUiVisibilityFlags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
            View.SYSTEM_UI_FLAG_FULLSCREEN |
            View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
            View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        systemUiVisibilityFlags = systemUiVisibilityFlags | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
    }
    getWindow().getDecorView().setSystemUiVisibility(systemUiVisibilityFlags);
}

以下是当事情按预期进行时的日志记录:(屏幕最初处于开启状态;然后关闭并再次打开)
09-19 11:00:09.384  31226-31243/com.pvsagar.smartlockscreen D/ScreenReceiver﹕ Screen off
09-19 11:00:09.384  31226-31226/com.pvsagar.smartlockscreen D/BaseService﹕ Starting lockscreen overlay.
09-19 11:00:09.394  31226-31226/com.pvsagar.smartlockscreen D/LockScreenActivity﹕ LockscreenActivity onCreate()
09-19 11:00:09.735  31226-31243/com.pvsagar.smartlockscreen D/ScreenReceiver﹕ Screen on

屏幕关闭后发送意图和LockScreenActivity实际启动之间没有多大的延迟。现在屏幕最初是开启的;我从某个应用程序(任何应用程序,甚至是我的应用程序的其他活动)按下主页键; 屏幕关闭并再次打开:
09-19 11:02:51.557  31226-31243/com.pvsagar.smartlockscreen D/ScreenReceiver﹕ Screen off
09-19 11:02:51.557  31226-31226/com.pvsagar.smartlockscreen D/BaseService﹕ Starting lockscreen overlay.
09-19 11:02:51.708  31226-31243/com.pvsagar.smartlockscreen D/ScreenReceiver﹕ Screen on
09-19 11:02:54.851  31226-31226/com.pvsagar.smartlockscreen D/LockScreenActivity﹕ LockscreenActivity onCreate()

正如您所看到的,屏幕关闭广播及时接收,并且服务立即获取该意图并将其发送到LockScreenActivity,但是LockScreenActivity的onCreate()会延迟3秒。

以下是服务启动LockScreenActivity的方式:

Intent lockscreenIntent = new Intent(this, LockScreenActivity.class);
lockscreenIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Log.d(LOG_TAG, "Starting lockscreen overlay.");
startActivity(lockscreenIntent);

这是传递给通知的挂起意图(只是为了展示它做同样的事情):
Intent notificationIntent = new Intent(context, LockScreenActivity.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
notificationBuilder.setContentIntent(pendingIntent);

我不知道为什么会出现这种情况。GC也没有运行太多。可能是什么问题呢?有什么方法可以解决吗? 如果您有任何建议或想法,将不胜感激。

整个代码可以在此处找到:https://github.com/aravindsagar/SmartLockScreen/tree/backend_code_strengthening


我也尝试使用了不同的启动器,但问题仍然存在。我该如何知道发生了什么?我的意思是如何找出问题所在? - aravindsagar
1
这个回答解决了你的问题吗?在HOME按钮按下后立即从服务启动活动而不需要5秒延迟 - Sam
2个回答

9

经过深入调查,我们找到了问题的原因。显然这不是一个 bug,而是一种功能,该功能在按下 Home 键后不允许服务或广播接收器启动活动,直至 5 秒钟之后。没有简单的方法可以解决这个问题。

更多信息请参见:https://code.google.com/p/android/issues/detail?id=4536

我用一个窗口替换了这个活动,并将其添加到正在运行的服务的窗口管理器中。这样不会造成任何延迟。


2
请在这里查找解决方案。
对于我来说,使用待处理意图并立即发送请求解决了我的问题,希望它也能帮助到你 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接