<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Android 12归档 - 日志</title>
	<atom:link href="https://www.log.show/tag/android-12/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.log.show/tag/android-12/</link>
	<description>LOG.SHOW</description>
	<lastBuildDate>Sun, 04 Jan 2026 09:18:05 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://www.log.show/wp-content/uploads/2025/11/cropped-logo-32x32.png</url>
	<title>Android 12归档 - 日志</title>
	<link>https://www.log.show/tag/android-12/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Android 的毛玻璃(高斯模糊)方案</title>
		<link>https://www.log.show/log/android-blur/</link>
					<comments>https://www.log.show/log/android-blur/#respond</comments>
		
		<dc:creator><![CDATA[LOGGER]]></dc:creator>
		<pubDate>Thu, 25 Dec 2025 04:29:36 +0000</pubDate>
				<category><![CDATA[LOG]]></category>
		<category><![CDATA[Android 12]]></category>
		<category><![CDATA[Android Development]]></category>
		<category><![CDATA[BlurView]]></category>
		<category><![CDATA[CPU Usage]]></category>
		<category><![CDATA[FPS]]></category>
		<category><![CDATA[Gaussian Blur]]></category>
		<category><![CDATA[Performance Monitoring]]></category>
		<category><![CDATA[UI Optimization]]></category>
		<category><![CDATA[WindowBlur]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[毛玻璃效果]]></category>
		<category><![CDATA[高斯模糊]]></category>
		<guid isPermaLink="false">https://log.show/?p=479</guid>

					<description><![CDATA[<p>原生方案 Android在Android12更新时支持了原生的高斯模糊，但是基本只能用于窗口模糊或者ViewG [&#8230;]</p>
<p><a href="https://www.log.show/log/android-blur/">Android 的毛玻璃(高斯模糊)方案</a>最先出现在<a href="https://www.log.show">日志</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">原生方案</h2>



<p class="wp-block-paragraph">Android在<a href="https://source.android.com/docs/core/display/window-blurs?hl=zh-cn">Android12更新时支持了原生的高斯模糊</a>，但是基本只能用于窗口模糊或者ViewGroup模糊。大概效果如下：</p>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="814" height="544" src="https://log.show/wp-content/uploads/2025/12/image-1.png" alt="" class="wp-image-480" srcset="https://www.log.show/wp-content/uploads/2025/12/image-1.png 814w, https://www.log.show/wp-content/uploads/2025/12/image-1-300x200.png 300w, https://www.log.show/wp-content/uploads/2025/12/image-1-768x513.png 768w" sizes="(max-width: 814px) 100vw, 814px" /></figure>



<p class="wp-block-paragraph">分别为：仅背景模糊处理 (a)、仅模糊处理后方屏幕 (b)、背景模糊处理和模糊处理后方屏幕 (c)。我们希望达到的要求为a效果，下面是官方的a效果的使用方案步骤。</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">对浮动窗口使用背景模糊处理可实现窗口背景效果，这是底层内容的模糊处理图像。如需为窗口添加模糊处理的背景，请执行以下操作：</p>



<ol class="wp-block-list">
<li>调用&nbsp;<a href="https://developer.android.com/reference/android/view/Window?hl=zh-cn#setBackgroundBlurRadius(int)">Window#setBackgroundBlurRadius(int)</a>&nbsp;设置背景模糊处理半径。或者，在窗口主题中设置&nbsp;<a href="https://developer.android.com/reference/android/R.attr?hl=zh-cn#windowBackgroundBlurRadius">R.attr.windowBackgroundBlurRadius</a>。</li>



<li>将&nbsp;<a href="https://developer.android.com/reference/android/R.attr?hl=zh-cn#windowIsTranslucent">R.attr.windowIsTranslucent</a>&nbsp;设为 true，使窗口变为半透明。模糊处理是在窗口 Surface 下面绘制的，因此窗口必须是半透明的，才能显示出模糊处理效果。</li>



<li>（可选）调用&nbsp;<a href="https://developer.android.com/reference/android/view/Window?hl=zh-cn#setBackgroundDrawableResource(int)">Window#setBackgroundDrawableResource(int)</a>&nbsp;添加具有半透明颜色的矩形窗口背景可绘制对象。或者，在窗口主题中设置&nbsp;<a href="https://developer.android.com/reference/android/R.attr?hl=zh-cn#windowBackground">R.attr.windowBackground</a>。</li>



<li>对于具有圆角的窗口，可通过将具有<a href="https://developer.android.com/guide/topics/resources/drawable-resource?hl=zh-cn#corners-element">圆角</a>的&nbsp;<a href="https://developer.android.com/guide/topics/resources/drawable-resource?hl=zh-cn#Shape">ShapeDrawable</a>&nbsp;设为窗口背景可绘制对象来确定模糊处理区域的圆角。</li>



<li>处理启用和停用模糊处理的状态。如需了解详情，请参阅<a href="https://source.android.com/docs/core/display/window-blurs?hl=zh-cn#guidelines">在应用中使用窗口模糊处理的准则</a>部分。</li>
</ol>
</blockquote>



<p class="wp-block-paragraph">但是这个方案有很多问题：</p>



<ol class="wp-block-list">
<li>我不是在单独窗口使用模糊，或者我希望在当前页面简单显示一个View(Group)</li>



<li>低于Android12的处理逻辑过于复杂</li>
</ol>



<h2 class="wp-block-heading">第三方库方案</h2>



<p class="wp-block-paragraph">根据更新时间，使用成本，以及Star数量，我选择使用：</p>



<p class="wp-block-paragraph"><a href="https://github.com/Dimezis/BlurView">https://github.com/Dimezis/BlurView</a></p>



<p class="wp-block-paragraph"> 它不仅可以在多种View显示需求下使用，并且自动适配了低于Android12的代码。</p>



<h3 class="wp-block-heading">使用步骤</h3>



<h4 class="wp-block-heading">1. 导入第三方库</h4>



<h4 class="wp-block-heading">2. 设置布局</h4>



<ul class="wp-block-list">
<li>你需要用一个 `BlurTarget` 包裹你目前的根布局。假设你的毛玻璃View出现在固定的位置，则你只需要包裹原来View的父布局即可，这样比较节省占用！</li>



<li>然后你需要把需要模糊的内容放在 `BlurView` 布局中</li>



<li>注意注意注意！！！ `BlurView` 与 `BlurTarget` 为同级，而非父子布局！！！</li>
</ul>



<p class="wp-block-paragraph">示例：</p>



<pre class="wp-block-code"><code>    &lt;!--This is the content to be blurred by the BlurView. 
    It will render normally, and BlurView will use its snapshot for blurring--&gt;
    &lt;eightbitlab.com.blurview.BlurTarget
        android:id="@+id/target"
        android:layout_width="match_parent"
        android:layout_height="match_parent"&gt;
        
        &lt;!--Your main content here--&gt;

    &lt;/eightbitlab.com.blurview.BlurTarget&gt;

    &lt;eightbitlab.com.blurview.BlurView
      android:id="@+id/blurView"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      app:blurOverlayColor="@color/colorOverlay"&gt;
    
       &lt;!--Any child View here, TabLayout for example. This View will NOT be blurred --&gt;
    
    &lt;/eightbitlab.com.blurview.BlurView&gt;</code></pre>



<h4 class="wp-block-heading">3. 模糊配置</h4>



<pre class="wp-block-code"><code>    private fun setupBlurView() {
        val radius = 20f  //模糊半径，越大占用越多！

        val windowBackground = window.decorView.background

        binding.blurView
            .setupWith(binding.target)           // ← 要模糊的根View，通常是最接近的父容器
            .setFrameClearDrawable(windowBackground)  // 防止透明区域变黑/变奇怪
            .setBlurRadius(radius)
    }</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">性能适配</h2>



<p class="wp-block-paragraph">以上代码基本可以实现很多毛玻璃效果。但是我推荐你在低端机型关闭这个效果，使用地透明度的纯色背景。</p>



<p class="wp-block-paragraph">下面是一个直接可以使用的性能监控工具，它会在运行10秒后返回平均结果，你可以根据结果重新设置布局属性（当然我推荐你保存下来这个结果，避免每次打开都重复获取和设置）：</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">注意：</p>



<ul class="wp-block-list">
<li>CPU 使用率：Android 从 API 26（Oreo）开始，系统越来越严格限制普通 App 读取其他进程的 /proc/[pid]/stat，但读取 整体系统 的 /proc/stat 仍然在大多数设备上可行（不保证 100% 成功，尤其是一些定制 ROM 或高安全设备可能会返回空或抛异常）。</li>



<li>这个工具类只计算整体系统 CPU（不是只算你 App 的），因为你关心的是“设备当前是否很忙”，而不是只看自己 App。</li>
</ul>
</blockquote>



<h3 class="wp-block-heading">工具代码：</h3>



<pre class="wp-block-code"><code>import android.os.Handler
import android.os.Looper
import android.view.Choreographer
import java.io.RandomAccessFile
import kotlin.math.max
import kotlin.math.min

/**
 * 10秒性能快照工具类
 * - 监控 FPS（UI 渲染帧率）
 * - 监控整体系统 CPU 使用率（通过 /proc/stat）
 * - 10秒后返回结果，并给出是否“高占用”的简单判断
 */
class PerformanceSnapshot private constructor() {

    companion object {
        // 单例懒加载
        val instance by lazy { PerformanceSnapshot() }
    }

    private var frameCount = 0L
    private var lastFrameTimeNs = 0L
    private var fpsSamples = mutableListOf&lt;Double&gt;()   // 每秒一个 FPS 样本

    private var cpuSamples = mutableListOf&lt;Float&gt;()    // 每秒一个 CPU% 样本

    private var prevIdle = -1L
    private var prevTotal = -1L

    private val handler = Handler(Looper.getMainLooper())
    private val choreographer = Choreographer.getInstance()

    private val frameCallback = object : Choreographer.FrameCallback {
        override fun doFrame(frameTimeNanos: Long) {
            if (lastFrameTimeNs == 0L) {
                lastFrameTimeNs = frameTimeNanos
            }

            frameCount++

            val elapsedNs = frameTimeNs - lastFrameTimeNs
            if (elapsedNs &gt;= 1_000_000_000L) {  // 每秒计算一次
                val fps = (frameCount * 1_000_000_000.0) / elapsedNs
                fpsSamples.add(fps.coerceIn(0.0, 120.0))  // 限制合理范围

                frameCount = 0
                lastFrameTimeNs = frameTimeNanos
            }

            choreographer.postFrameCallback(this)
        }
    }

    /**
     * 采集一次 CPU 使用率（整体系统）
     * 返回 -1 表示读取失败
     */
    private fun sampleCpuUsage(): Float {
        try {
            val reader = RandomAccessFile("/proc/stat", "r")
            val line = reader.readLine() ?: return -1f
            reader.close()

            val toks = line.split("\\s+".toRegex()).filter { it.isNotBlank() }
            if (toks.size &lt; 11) return -1f

            // cpu user nice system idle iowait irq softirq steal guest guest_nice
            val user   = toks&#91;1].toLongOrNull() ?: 0L
            val nice   = toks&#91;2].toLongOrNull() ?: 0L
            val system = toks&#91;3].toLongOrNull() ?: 0L
            val idle   = toks&#91;4].toLongOrNull() ?: 0L
            val iowait = toks&#91;5].toLongOrNull() ?: 0L
            val irq    = toks&#91;6].toLongOrNull() ?: 0L
            val softirq= toks&#91;7].toLongOrNull() ?: 0L
            // 忽略 steal/guest 等（通常为0）

            val total = user + nice + system + idle + iowait + irq + softirq
            val idleDiff = idle - prevIdle
            val totalDiff = total - prevTotal

            return if (prevTotal &gt; 0 &amp;&amp; totalDiff &gt; 0) {
                val usage = 100f * (totalDiff - idleDiff) / totalDiff
                usage.coerceIn(0f, 100f)
            } else {
                -1f
            }.also {
                prevIdle = idle
                prevTotal = total
            }
        } catch (e: Exception) {
            return -1f
        }
    }

    /**
     * 开始 10 秒监控，返回结果
     * @param onComplete 回调：(平均FPS, 平均CPU%, 是否认为是高占用)
     */
    fun startMonitoring(onComplete: (avgFps: Double, avgCpu: Float, isHighLoad: Boolean, message: String) -&gt; Unit) {
        // 重置
        fpsSamples.clear()
        cpuSamples.clear()
        frameCount = 0L
        lastFrameTimeNs = 0L
        prevIdle = -1L
        prevTotal = -1L

        // 第一次采样 CPU（建立基线）
        sampleCpuUsage()

        // 开启 FPS 监控
        choreographer.postFrameCallback(frameCallback)

        // 每秒采样一次 CPU（大约 10 次）
        var seconds = 0
        val cpuSampler = object : Runnable {
            override fun run() {
                if (seconds &gt;= 10) {
                    // 停止监控
                    choreographer.removeFrameCallback(frameCallback)
                    handler.removeCallbacks(this)

                    // 计算平均值
                    val avgFps = if (fpsSamples.isNotEmpty()) {
                        fpsSamples.average()
                    } else 0.0

                    val avgCpu = if (cpuSamples.isNotEmpty()) {
                        val valid = cpuSamples.filter { it &gt;= 0 }
                        if (valid.isNotEmpty()) valid.average().toFloat() else -1f
                    } else -1f

                    // 我的简单高占用判断逻辑（可自行调整阈值）
                    val isHighLoad = when {
                        avgCpu &lt; 0 -&gt; false                     // 无法读取 CPU → 不算高
                        avgCpu &gt; 80f -&gt; true                     // CPU 非常高
                        avgCpu &gt; 65f &amp;&amp; avgFps &lt; 48.0 -&gt; true    // CPU 中高 + FPS 偏低
                        avgFps &lt; 42.0 -&gt; true                    // FPS 严重偏低（即使 CPU 不高）
                        else -&gt; false
                    }

                    val msg = buildString {
                        append("10秒监控结果：\n")
                        append("  • 平均 FPS: %.1f\n".format(avgFps))
                        append("  • 平均 CPU: %.1f%%\n".format(avgCpu))
                        append("  • 判断：${if (isHighLoad) "高占用（建议关闭模糊）" else "正常"}")
                        if (avgCpu &lt; 0) append("\n（CPU 数据读取失败，仅参考 FPS）")
                    }

                    onComplete(avgFps, avgCpu, isHighLoad, msg)
                    return
                }

                val cpu = sampleCpuUsage()
                if (cpu &gt;= 0) cpuSamples.add(cpu)

                seconds++
                handler.postDelayed(this, 1000L)
            }
        }

        handler.post(cpuSampler)
    }
}</code></pre>



<h3 class="wp-block-heading">使用代码：</h3>



<pre class="wp-block-code"><code>// 在适当的地方调用（比如 Fragment/Activity 的某个按钮或初始化时）
PerformanceSnapshot.instance.startMonitoring { avgFps, avgCpu, isHighLoad, message -&gt;
    Log.d("Perf", message)
    
    if (isHighLoad) {
        // 关闭模糊
        binding.blurView.setBlurRadius(0f)
        // 或完全 detach：blurView.setupWith(null) 等
    } else {
        // 恢复模糊
        binding.blurView.setBlurRadius(20f)
    }
}</code></pre>



<p class="wp-block-paragraph">我依然推荐你在打开APP（或者某个Activity）3-5秒后再启动这个工具。因为内容加载以及页面频繁跳转CPU计算或许会有影响！</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">2026年1月4日更新内容</h3>



<p class="wp-block-paragraph">如果你是在Activity中调用了一个次级窗口或者其它Activity，那么你或许需要使用下面的方案，以下以BottomSheetDialogFragment</p>



<pre class="wp-block-code"><code>            //差不多就是，在跟View添加BlurTarget，然后获取根布局的BlurTarget，setupWith它就可以了
            val activity = context as? Activity ?: return
            val targetView = activity.window.decorView.findViewById&lt;BlurTarget>(R.id.target)
            mVB.blurView.setupWith(targetView)
                .setBlurRadius(15f)
                .setFrameClearDrawable(activity.window.decorView.background)
                .setBlurAutoUpdate(true)</code></pre>



<p class="wp-block-paragraph">圆角的方案：</p>



<pre class="wp-block-code"><code>        viewModel.blurView.outlineProvider = object : ViewOutlineProvider() {
                override fun getOutline(view: View, outline: Outline) {
                    // 直接根据 View 的宽高设置圆角矩形
                    // 16f.dpToPx() 是将 16dp 转为像素，如果你没有扩展函数，可以直接写数值（比如 48）
                    val radiusInPx = TypedValue.applyDimension(
                        TypedValue.COMPLEX_UNIT_DIP, 16f, resources.displayMetrics
                    )

                    // 设置圆角矩形区域 (左, 上, 右, 下, 半径)
                    outline.setRoundRect(0, 0, view.width, view.height, radiusInPx)
                }
            }</code></pre>
<p><a href="https://www.log.show/log/android-blur/">Android 的毛玻璃(高斯模糊)方案</a>最先出现在<a href="https://www.log.show">日志</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.log.show/log/android-blur/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
