Android应用进入最近任务列表时模糊显示的实现方案咨询
实现方案:应用内允许截图 + 最近任务列表模糊显示
以下是针对需求的几种可行实现方案,覆盖不同场景和兼容性需求:
方案一:利用窗口可见性变化监听(推荐)
重写Activity的onWindowVisibilityChanged方法,该方法会在窗口可见性发生变化时触发(包括进入最近任务列表的场景,无论Activity是否处于resumed状态),精准控制FLAG_SECURE的添加与移除。
@Override public void onWindowVisibilityChanged(int visibility) { super.onWindowVisibilityChanged(visibility); if (visibility == View.INVISIBLE) { // 进入最近任务列表,开启模糊保护 getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE); } else if (visibility == View.VISIBLE) { // 返回应用,移除保护以允许截图 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE); } }
这个方案是系统级实现,性能最优,且能覆盖所有进入最近任务的场景。
方案二:全局应用生命周期监听(多Activity场景)
如果应用包含多个Activity,可以通过ProcessLifecycleOwner统一监听应用前后台状态,批量控制所有Activity的窗口保护。
首先在Application类中初始化监听:
@Override public void onCreate() { super.onCreate(); ProcessLifecycleOwner.get().getLifecycle().addObserver(new LifecycleEventObserver() { @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { if (event == Lifecycle.Event.ON_STOP) { // 应用进入后台,为所有存活Activity设置FLAG_SECURE for (Activity activity : ActivityCollector.getActivities()) { if (activity.getWindow() != null) { activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE); } } } else if (event == Lifecycle.Event.ON_START) { // 应用回到前台,移除所有Activity的FLAG_SECURE for (Activity activity : ActivityCollector.getActivities()) { if (activity.getWindow() != null) { activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE); } } } } }); }
需要配合一个Activity管理类ActivityCollector,用来跟踪所有Activity实例:
public class ActivityCollector { private static final List<Activity> ACTIVITIES = new ArrayList<>(); public static void addActivity(Activity activity) { ACTIVITIES.add(activity); } public static void removeActivity(Activity activity) { ACTIVITIES.remove(activity); } public static List<Activity> getActivities() { return new ArrayList<>(ACTIVITIES); } }
在每个Activity的onCreate中调用ActivityCollector.addActivity(this),onDestroy中调用ActivityCollector.removeActivity(this)即可。
方案三:自定义模糊遮罩层(兼容特殊设备)
如果部分厂商设备对FLAG_SECURE支持不佳,可以通过自定义全屏模糊遮罩的方式实现。核心逻辑是在应用进入后台时,显示覆盖整个窗口的模糊视图。
示例代码:
private View blurOverlay; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); blurOverlay = findViewById(R.id.blur_overlay); blurOverlay.setVisibility(View.GONE); } @Override public void onWindowVisibilityChanged(int visibility) { super.onWindowVisibilityChanged(visibility); if (visibility == View.INVISIBLE) { blurOverlay.setVisibility(View.VISIBLE); // 截取当前界面并模糊后设置为遮罩背景 Bitmap screenshot = captureScreen(); Bitmap blurredBitmap = blurImage(screenshot, this); ((ImageView) blurOverlay).setImageBitmap(blurredBitmap); } else { blurOverlay.setVisibility(View.GONE); } } // 截取当前界面 private Bitmap captureScreen() { View rootView = getWindow().getDecorView().getRootView(); rootView.setDrawingCacheEnabled(true); Bitmap bitmap = Bitmap.createBitmap(rootView.getDrawingCache()); rootView.setDrawingCacheEnabled(false); return bitmap; } // 模糊处理图片(使用RenderScript) private Bitmap blurImage(Bitmap bitmap, Context context) { RenderScript rs = RenderScript.create(context); Allocation input = Allocation.createFromBitmap(rs, bitmap); Allocation output = Allocation.createTyped(rs, input.getType()); ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); blurScript.setRadius(18f); blurScript.setInput(input); blurScript.forEach(output); output.copyTo(bitmap); rs.destroy(); return bitmap; }
布局中需要添加一个全屏的ImageView作为遮罩:
<ImageView android:id="@+id/blur_overlay" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:visibility="gone"/>
注意事项
- 兼容性测试:部分厂商对
FLAG_SECURE的实现有差异,需在目标设备上验证效果。 - 多窗口适配:若应用支持多窗口模式,需额外处理窗口大小变化时的可见性逻辑。
- 性能优化:自定义模糊方案需注意Bitmap的内存回收,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Raa
相关产品推荐
相关产品推荐

