替代已弃用FLAG_SHOW_WHEN_LOCKED,Android锁屏启动Activity方案
解决锁屏下通过广播启动Activity的问题
嘿,这个问题我之前做项目时刚好踩过坑,给你梳理下完整的解决思路,保证能搞定!
首先你碰到的No virtual method setShowWhenLocked(Z)V错误,多半是两个原因:
- 你的项目
minSdkVersion低于27,毕竟setShowWhenLocked()和setTurnScreenOn()是API 27才新增的方法 - 调用对象不对——这俩是Window类的方法,得通过Activity的
getWindow()来调用,不能瞎找个类就调用
下面分不同Android版本给你具体实现步骤:
1. 基础配置(全版本通用)
先在要启动的Activity的AndroidManifest.xml里声明必要属性:
<activity android:name=".YourTargetActivity" android:showOnLockScreen="true" <!-- 早期版本兼容属性,API27+可配合新方法使用 --> android:turnScreenOn="true"> </activity>
另外如果是静态注册广播接收器,别忘了在Manifest里注册好;动态注册的话就在代码里处理就行。
2. 分API版本处理Activity逻辑
API 27及以上(推荐写法)
在TargetActivity的onCreate()里,在setContentView()之前调用Window的方法:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 先处理锁屏亮屏逻辑 Window window = getWindow(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { window.setShowWhenLocked(true); window.setTurnScreenOn(true); } setContentView(R.layout.activity_target); // 其他初始化代码... }
如果你的minSdk直接设为27+,可以不用版本判断直接调用。
API 23到26(过渡版本)
这部分版本旧的FLAG还没完全弃用,用旧写法兼容:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Window window = getWindow(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) { window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); } setContentView(R.layout.activity_target); }
API 22及以下
直接用最原始的FLAG组合即可:
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
3. Android 10(API29)及以上的额外注意事项
从Android10开始,系统对后台启动Activity限制更严,如果你的广播是在APP后台触发的,得满足以下条件之一:
- 广播是用户可见事件触发的(比如通知的PendingIntent)
- 你的APP持有
SYSTEM_ALERT_WINDOW权限(但这个权限需要用户手动授予,不推荐滥用) - 使用符合后台启动规则的方式,比如
ActivityOptions.makeLaunchIntoPipMode()
如果还需要解锁屏幕,API28及以上可以这么做:
KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { keyguardManager.requestDismissKeyguard(this, null); }
4. 广播接收器里的启动逻辑
在广播接收器里启动Activity时,必须加FLAG_ACTIVITY_NEW_TASK标记,非Activity环境启动Activity都得加这个:
Intent intent = new Intent(context, YourTargetActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent);
这套流程走下来,锁屏下通过广播启动Activity的需求就完全实现了,我自己项目里这么写一直没出问题!
内容的提问来源于stack exchange,提问作者Dave




