从服务启动活动时出现延迟 [英] Delay while launching activity from service
问题描述
我有一个广播接收器,它接收屏幕关闭广播,当屏幕关闭时,它将启动活动.我已将此活动命名为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:
- 通过在注册广播接收器时传递一个处理程序,使广播接收器在单独的线程中运行
- 在广播接收器的
onReceive()
中获取了唤醒锁,并在LockScreenActivity的onResume()
中将其释放了 - 通过在清单中指定一个不同的taskAffinity,为LockScreenActivity创建一个单独的任务堆栈.我还玩过很多与活动堆栈相关的选项组合,但到目前为止没有任何帮助.
- 不是直接启动活动,而是向该服务发送了意图,然后该服务启动了活动. 不幸的是,没有任何反应.
- Made the broadcast receiver run in separate thread by passing a handler when registering the broadcast receiver
- Acquired a wakelock in the broadcast receiver's
onReceive()
and released it inonResume()
of LockScreenActivity - 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.
- 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屋!