从服务启动活动时出现延迟 [英] Delay while launching activity from service

查看:68
本文介绍了从服务启动活动时出现延迟的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a broadcast receiver which receives screen off broadcast, and when the screen is turned off, it launches an Activity. I've named this activity LockScreenActivity. I've added getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); in onCreate() of the activity, so that it appears on top of the Android lockscreen, which is exactly what I want. This works well enough, mostly. Problem happens whenever I press home button to send any app to the background.

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

When I press home button to return to home screen from any app, and then immediately press power button to turn off the screen, and press power button in a second to turn in back on, it shows the Android lock screen. My activity gets created some 3-4 seconds later. This is a huge delay and is unacceptable. In other scenarios, this delay does not happen. If I've been in home screen for some time, or some other app is open, and I click power button twice in quick succession, I see my LockScreenActivity before seeing the Android lockscreen.

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

My app also has a few other normal activities (launched from App drawer) and a service which shows a persistent notification. The same LockScreenActivity is launched whenever the notification is clicked. Interestingly enough, if I press home button to minimize some app and immediately click the notification of my app, it opens the LockScreenActivity without any delay.

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

I've searched a lot for any solution. Here's what I've tried out so far:

  1. 通过在注册广播接收器时传递一个处理程序,使广播接收器在单独的线程中运行
  2. 在广播接收器的onReceive()中获取了唤醒锁,并在LockScreenActivity的onResume()中将其释放了
  3. 通过在清单中指定一个不同的taskAffinity,为LockScreenActivity创建一个单独的任务堆栈.我还玩过很多与活动堆栈相关的选项组合,但到目前为止没有任何帮助.
  4. 不是直接启动活动,而是向该服务发送了意图,然后该服务启动了活动. 不幸的是,没有任何反应.
  1. Made the broadcast receiver run in separate thread by passing a handler when registering the broadcast receiver
  2. Acquired a wakelock in the broadcast receiver's onReceive() and released it in onResume() of LockScreenActivity
  3. Made a separate task stack for LockScreenActivity by specifying a different taskAffinity in manifest. I've also played with lot of combinations of the options related to activity stack, but nothing has helped so far.
  4. Instead of launching the activity directly, sent an intent to the service which then launches the activity. Nothing has worked, unfortunately.

这是活动和服务的清单声明:

Here's the manifest declaration of the activity, and service:

<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()在服务启动时被调用.

WakeLockHelper is a class which manages all the wakelocks in my app. registerScreenReceiver() is called by the Service when it starts.

这是LockScreenActivity的onCreate():

Here's the onCreate() of LockScreenActivity:

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);
}

这是按预期方式运行时的日志:(屏幕最初处于打开状态;它已关闭并再次打开)

Here's the log when things work as expected: (Screen is intially on; it is turned off and on again)

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实际上开始.现在,屏幕最初处于打开状态;我从某个应用程序(任何应用程序,甚至是我自己的应用程序的其他活动)按回家;屏幕关闭后又打开:

Not much delay between screen off and sending the intent and the LockScreenActivity actually starting. Now Screen is initially on; I press home from some app (any app, even some other activity of my own app); Screen is turned off and on again:

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秒.

Here, as you can see, screen off broadcast is received in time, service gets the intent immediately and send the intent to LockScreenActivity, but onCreate() of LockScreenActivity is delayed by 3 seconds.

这是服务启动LockScreenActivity的方式:

This is how the LockScreenActivity is started by the service:

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

这是传递给通知的未决意图(仅表明它具有相同的作用):

This is the pending intent passed to the notification (just to show that it does the same thing):

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也没有运行太多.可能是什么问题呢?我可以做些什么来克服这个问题? 任何建议/想法将不胜感激.

I'm not having any idea why this is happening. GC is also not running too much. What could be the problem? What can I possibly do to overcome this? Any suggestions/ideas would be greatly appreciated.

可以在以下位置找到整个代码: https://github.com/aravindsagar/SmartLockScreen/tree/backend_code_strengthening

The entire code can be found at: https://github.com/aravindsagar/SmartLockScreen/tree/backend_code_strengthening

推荐答案

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

After much digging, found out the cause of the problem. Apparently it's not a bug, it is a feature which does not allow Services or BroadcastReceivers to launch activities for up to 5 seconds after home button is pressed. No easy way to overcome this.

此处的更多信息: https://code.google.com/p/android/issues/detail?id = 4536

我用添加到正在运行的服务的窗口管理器中的窗口替换了活动.这不会造成任何延迟.

I replaced the activity with a Window added to the window manager of the running service. This does not cause any delay.

这篇关于从服务启动活动时出现延迟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆