我有一个广播接收器,它接收屏幕关闭广播,当屏幕关闭时,它将启动“Activity ”。我已将此 Activity 命名为LockScreenActivity。我在 Activity 的getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);中添加了onCreate(),以便它出现在Android锁屏顶部,这正是我想要的。大多数情况下,这已经足够好了。每当我按下主页按钮将任何应用程序发送到后台时,都会发生问题。

当我按下主屏幕按钮以从任何应用返回主屏幕,然后立即按电源按钮以关闭屏幕,并在一秒钟内按电源按钮以重新打开时,它显示了Android锁定屏幕。约3-4秒后,我的 Activity 被创建。这是一个巨大的延迟,是 Not Acceptable 。在其他情况下,这种延迟不会发生。如果我已经进入主屏幕一段时间,或者打开了其他某个应用程序,并且快速连续两次单击电源按钮,那么在看到Android锁屏之前,我会看到LockScreenActivity。

我的应用程序还具有其他一些常规 Activity (从“应用程序”抽屉中启动)和显示持久性通知的服务。每当单击通知时,都会启动相同的LockScreenActivity。有趣的是,如果我按下主页按钮以最小化某些应用程序,然后立即单击我的应用程序通知,它将立即打开LockScreenActivity。

我已经搜索了很多解决方案。到目前为止,这是我尝试过的方法:

  • 通过在注册广播接收器
  • 时传递一个处理程序,使广播接收器在单独的线程中运行
  • 在广播接收机的onReceive()中获取了唤醒锁,并在LockScreenActivity
  • onResume()中释放了它。
  • 通过在 list 中指定不同的taskAffinity,为LockScreenActivity创建了单独的任务堆栈。我也玩过很多与 Activity 堆栈相关的选项组合,但到目前为止没有任何帮助。
  • 不是直接启动 Activity ,而是向该服务发送了一个 Intent ,然后该服务启动了 Activity 。
    不幸的是,没有任何工作。

  • 这是 Activity 和服务的 list 声明:
    <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
    

    屏幕关闭与发送 Intent 之间的延迟不多,并且LockScreenActivity实际上开始。现在,屏幕最初处于打开状态;我从某个应用程序(任何应用程序,甚至是我自己的应用程序的其他 Activity )按回家;屏幕关闭后再次打开:
    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()
    

    如您所见,在这里,及时接收到了屏幕关闭广播,服务会立即获得该 Intent 并将其发送给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 (仅表明它具有相同的作用):
    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

    最佳答案

    经过大量挖掘,找出了问题的原因。显然,这不是一个错误,它是一项功能,该功能不允许服务或BroadcastReceivers在按下主屏幕按钮后最多5秒钟启动 Activity 。没有简单的方法可以克服这个问题。

    更多信息在这里:https://code.google.com/p/android/issues/detail?id=4536

    我用添加到正在运行的服务的窗口管理器中的窗口替换了 Activity 。这不会引起任何延迟。

    10-07 22:31