找了半天,没有找到太现成的,只能自己动手写一写了,最后试了试,感觉效果凑乎,先用着吧

为了解决该安全风险,主要用到了 BlurView 三方框架
- github地址 - BlurView(国内外)
 - gitcode地址 - BlurView(国内)
 
人生,哪有事事如意?
框架介绍
Effect

Tip:不支持 SurfaceView, TextureView, VideoView, MapFragment, GLSurfaceView, etc 模糊

框架引入
 implementation 'com.github.Dimezis:BlurView:version-2.0.3'
 
视图引入
Tip:是处于BlurView的视图是不会被模糊的
  <eightbitlab.com.blurview.BlurView
      android:id="@+id/blurView"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      app:blurOverlayColor="@color/colorOverlay">
       <!--Any child View here, TabLayout for example. This View will NOT be blurred -->
  </eightbitlab.com.blurview.BlurView>
 
调用方式
    float radius = 20f;
    View decorView = getWindow().getDecorView();
    // ViewGroup you want to start blur from. Choose root as close to BlurView in hierarchy as possible.
    ViewGroup rootView = (ViewGroup) decorView.findViewById(android.R.id.content);
    
    // Optional:
    // Set drawable to draw in the beginning of each blurred frame.
    // Can be used in case your layout has a lot of transparent space and your content
    // gets a too low alpha value after blur is applied.
    Drawable windowBackground = decorView.getBackground();
    blurView.setupWith(rootView, new RenderScriptBlur(this)) // or RenderEffectBlur
           .setFrameClearDrawable(windowBackground) // Optional
           .setBlurRadius(radius)
 
关于这部分尚未使用,就不做解释了

事前注意
主要记录我在使用中遇到的问题
AndroidX 兼容了吗?
 android.useAndroidX=true
 
View未加载完就设置 blurView 了?
这个并是不必现问题,可能基本遇不到,仅做记录(该 rootView 可以使用xml中最外层布局控件)
    rootView.viewTreeObserver.addOnGlobalLayoutListener {
        blurView.setupWith(contextView, algorithm)
            .setFrameClearDrawable(background)
            .setBlurRadius(radius)//如不要需要,无需设置
    }
 
仓库引用不到?
如果你运气不错的话,直接引入框架可能就可以使用了,但是我运气可能不太好
 implementation 'com.github.Dimezis:BlurView:version-2.0.3'
 
根据介绍 JCenter 仓库已经关闭了,需要配置 jitpack

解决方式
repositories {
        maven { url 'https://jitpack.io' }
  }
allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}
 
小课堂
我们常见的远程仓库主要有三种 JCenter、mavenCentral、jitpack
- JCenter:JCenter是JFrog公司提供的Android第三方库的仓库,JFrog公司宣布即将废弃该仓库,jcenter仓库是也曾经google默认推荐的第三方库。最早宣布废弃时,2022年2月后,将不可以下载上边的库,如果这些库的开发
者不做库迁移,那么普通开发者将无法使用这些库,不过,好在最后JFrog公司可能和Google达成了什么协议,后续还能下载,但不能更新维护。目前Google推荐使用mavenCentral仓库。 - mavenCentral:sonatype公司提供的第三方仓库,当时使用比较麻烦,审核也比较严格,比如你发布库的时候,库的包名,你必须要有这个域名的所有权,才能发布,不像jcenter谁先用,就归谁。目前Google推荐使用的第三方仓库。
 - jitpack (https://jitpack.io/):在jcenter废弃后,逐渐被用的越来越多,使用比较简单,适合个人开发者使用,缺点是不是Google官方推荐,使用时要手动添加maven依赖。
 
实践检验
build.gradle 引入框架
  implementation 'com.github.Dimezis:BlurView:version-2.0.3'
 
控件引入
关于这部分要了解视图层次的概念,感觉有以下几点需要特别注意一下
- 最外层布局可以采用 
FrameLayout、RelativeLayout、ConstraintLayout,不然可能无法达到视图覆盖的效果 - 模糊效果是 
直接将模糊后的视图覆盖到原正常视图之上 - 正常视图位于底层,从xml角度一般先写,模糊视图后写,可以参考栈结构
 
activity_main (引入BlurView)
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/ic_launcher_background"
        android:orientation="vertical">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:gravity="center"
            android:textSize="20sp"
            android:text="放置正常视图,模糊后被覆盖"
            android:textColor="#333333" />
    </LinearLayout>
    <eightbitlab.com.blurview.BlurView
        android:id="@+id/blur_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:blurOverlayColor="#78ffffff">
        <!--        <LinearLayout-->
        <!--            android:layout_width="match_parent"-->
        <!--            android:layout_height="match_parent"-->
        <!--            android:orientation="vertical">-->
        <!--            <TextView-->
        <!--                android:layout_width="match_parent"-->
        <!--                android:layout_height="50dp"-->
        <!--                android:gravity="center"-->
        <!--                android:text="放置模糊后的正常视图,模糊后依旧正常显示"-->
        <!--                android:textColor="#333333" />-->
        <!--        </LinearLayout>-->
    </eightbitlab.com.blurview.BlurView>
</android.support.constraint.ConstraintLayout>
 
使用方式
关于 BlurView 所需 rootView 
- 可以采用 
xml内的最外层ViewGroup - 也可以采用 
Window的ContentView 
基础使用
package com.example.blurview
import android.os.Build
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
import android.view.ViewGroup
import eightbitlab.com.blurview.BlurAlgorithm
import eightbitlab.com.blurview.BlurView
import eightbitlab.com.blurview.RenderEffectBlur
import eightbitlab.com.blurview.RenderScriptBlur
class MainActivity : AppCompatActivity() {
    private val blurView: BlurView by lazy {
        findViewById(R.id.blur_view)
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val contextView = window.decorView.findViewById<ViewGroup>(android.R.id.content)
        blurView.setupWith(contextView, RenderScriptBlur(this@MainActivity))
    }
    override fun onPause() {
        super.onPause()
        blurView.visibility = View.VISIBLE
    }
    override fun onResume() {
        super.onResume()
        blurView.visibility = View.GONE
    }
}
 
兼容使用
- 用到了 
Window相关的DecorView原理 (系统级) - 因 
RenderScriptBlur过时,用到了RenderEffectBlur(框架级) 
package com.example.blurview
import android.os.Build
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
import android.view.ViewGroup
import eightbitlab.com.blurview.BlurAlgorithm
import eightbitlab.com.blurview.BlurView
import eightbitlab.com.blurview.RenderEffectBlur
import eightbitlab.com.blurview.RenderScriptBlur
class MainActivity : AppCompatActivity() {
    private val blurView: BlurView by lazy {
        findViewById(R.id.blur_view)
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val background = window.decorView.background
        val contextView = window.decorView.findViewById<ViewGroup>(android.R.id.content)
        val radius = 20f
        val algorithm: BlurAlgorithm = getBlurAlgorithm()
        blurView.setupWith(contextView, algorithm)
            .setFrameClearDrawable(background)
            .setBlurRadius(radius) //如不要需要,无需设置
    }
    override fun onPause() {
        super.onPause()
        blurView.visibility = View.VISIBLE
    }
    override fun onResume() {
        super.onResume()
        blurView.visibility = View.GONE
    }
    /**
    * 兼容处理
    * */
    private fun getBlurAlgorithm(): BlurAlgorithm {
        val algorithm: BlurAlgorithm = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            RenderEffectBlur()
        } else {
            RenderScriptBlur(this)
        }
        return algorithm
    }
}
 
有那么一刻想优化一下么?
我发现在后台切换卡片时,当卡片处于当前 position,好像会偶显正常视图,基于这点可以考虑同时兼容前后台监听来实现更好的效果
以前写过一篇 Android进阶之路 - 前后台切换监听,有兴趣的话可以去看下
随机找了一篇别人的伪代码,各位可以简单参考下
public class MainActivity extends AppCompatActivity {
 
    private boolean isForeground = false;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
 
    @Override
    protected void onResume() {
        super.onResume();
        if (isForeground) {
            // 从后台进入前台,恢复界面状态和数据
            // TODO: 恢复界面状态和数据
        }
        isForeground = true;
    }
 
    @Override
    protected void onPause() {
        super.onPause();
        if (!isAppOnForeground()) {
            // 从前台进入后台,保存界面状态和数据
            // TODO: 保存界面状态和数据
        }
        isForeground = false;
    }
 
    /**
     * 判断当前应用是否处于前台
     */
    private boolean isAppOnForeground() {
        ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
        if (appProcesses == null) {
            return false;
        }
        String packageName = getPackageName();
        for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
            if (appProcess.processName.equals(packageName)
                    && appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                return true;
            }
        }
        return false;
    }
}









