android多任务列表高斯模糊

Android实现高斯模糊的效果网上能搜索到很多,但是关于多任务列表高斯模糊处理的文章缺比较少,这里简单记录一下我自己的实现过程,虽然有些瑕疵,但是思路最重要,记录一下。关于这个瑕疵,也会在接下来正文里有介绍。

先上一张MIUI11下的多任务预览图模糊的效果,要实现这个效果,首先要确定具体的实现思路,我的思路分为以下四步:

1 监听多任务按键事件,Android中,返回键的监听可以通过重写onBackPressed或者拦截按键点击事件来实现。但是对于多任务键的监听比较特殊,无法通过按键拦截来实现监听(至少我的小米手机上是这样的),但是我们可以通过广播来监听多任务键。先贴一下代码吧

 /**
     * 参数
     */
    private static final String SYSTEM_REASON = "reason";
    private static final String SYSTEM_HOME_RECENT_APPS = "recentapps";

    private Context mContext;
    private BroadcastReceiver mDeviceKeyReceiver = null;
    private OnKeyListener mListener;


    public DeviceKeyMonitor (Context context, final OnKeyListener listener) {
        mContext = context;
        mListener = listener;
        mDeviceKeyReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action=intent.getAction();
                if(!TextUtils.isEmpty(action)){

                    if (intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
                        String reason = intent.getStringExtra(SYSTEM_REASON);

                        if (reason == null)
                            return;

                        // 最近任务列表键
                        if (reason.equals(SYSTEM_HOME_RECENT_APPS)) {
                            mListener.onRecentClick();

                        }
                    }
                }
            }
        };
        mContext.registerReceiver(mDeviceKeyReceiver, new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
    }

    public interface OnKeyListener{
        void onRecentClick();//多任务键监听
    }

    public void unregister(){
        if (mDeviceKeyReceiver != null){
            mContext.unregisterReceiver(mDeviceKeyReceiver);
            mDeviceKeyReceiver = null;

        }
    }

然后在activity中重写onRecentClick事件。

2 第二步就是对当前activity截图,核心代码如下

/***
     * 截取当前activity
     * @param activity
     * @return
     */
    public static Bitmap activityShot(Activity activity) {
        /*获取windows中最顶层的view*/
        View view = activity.getWindow().getDecorView();

        //允许当前窗口保存缓存信息
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();

        //获取状态栏高度
        Rect rect = new Rect();
        view.getWindowVisibleDisplayFrame(rect);
        int statusBarHeight = rect.top;

        WindowManager windowManager = activity.getWindowManager();

        //获取屏幕宽和高
        DisplayMetrics outMetrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(outMetrics);
        int width = outMetrics.widthPixels;
        int height = outMetrics.heightPixels;

        //去掉状态栏
        Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache(), 0, statusBarHeight, width,
                height - statusBarHeight);

        //销毁缓存信息
        view.destroyDrawingCache();
        view.setDrawingCacheEnabled(false);


        return bitmap;
    }

方法返回的bitmap就是我们截取activity之后的bitmap。

3 第三步,将截取的activity高斯模糊处理。关于高斯模糊,在Android中常用的高斯模糊技术有三种RenderScript 、fastBlur对RenderScript和fastBlur的优化。由于本文使用的高斯模糊框架是RenderScript,所以这里简单介绍一下RenderScript,其他两种方式的详细介绍网上有大量的文章可以参考。

RenderScript是在Android上的高性能运行密集型运算的框架,RenderScript主要用于数据并行计算,尤其对图像处理、摄影分析和计算机视觉特别有用。RenderScript是在Android3.0(API 11)引入的。而Android图片高斯模糊处理,通常也是用这个库来完成。它提供了我们Java层调用的API,实际上是在c/c++ 层来处理的,所以它的效率和性能通常是最高的。要使用RenderScript完成图片高斯模糊只需要以下几步:

(1) 初始化一个RenderScript Context:RenderScript 上下文环境通过create(Context)方法来创建,它保证RenderScript的使用并且提供一个控制后续所有RenderScript对象(如:ScriptIntrinsicBlur、Allocation等)生命周期的对象。

(2)通过Script至少创建一个Allocation:一个Allocation是提供存储大量可变数据的RenderScript 对象。在内核中,Allocation作为输入和输出,在内核中通过rsGetElementAt_type ()和rsSetElementAt_type()方法来访问Allocation当script全局绑定的时候。使用createFromBitmap 和createTyped来创建Allocation。

(3)创建ScriptIntrinsic:它内置了RenderScript 的一些通用操作,如高斯模糊、扭曲变换、图像混合等等,更多的操作请看ScriptIntrinsic的子类,本文要用的高斯模糊处理就是用的它的子类ScriptIntrinsicBlur。
(4)填充数据到Allocations:除了使用方法createFromBitmap创建的Allocation外,其它的第一次创建时都是填充的空数据。

(5)** 设置模糊半径**:设置一个模糊的半径,其值为 0-25。

(6) 启动内核,调用方法处理:调用forEach 方法模糊处理。

(7) ** 从Allocation 中拷贝数据**:为了能在Java层访问Allocation的数据,用Allocation其中一个copy方法来拷贝数据。
(8) 销毁RenderScript对象:可以用destroy方法来销毁RenderScript对象或者让它可以被垃圾回收,destroy 之后,就能在用它控制的RenderScript对象了(比如在销毁了之后,再调用ScriptIntrinsic或者Allocation的方法是要抛异常的)。

对应的核心代码如下

public static Bitmap rsBlur(Context context, Bitmap source, int radius){
        Bitmap inputBmp = source;
        //(1)
        //初始化一个RenderScript Context
        RenderScript renderScript =  RenderScript.create(context);

//        Log.i(TAG,"setDrawingCacheEnabledle size:"+inputBmp.getWidth()+"*"+inputBmp.getHeight());

        // Allocate memory for Renderscript to work with
        //(2)
        //创建输入输出的allocation
        final Allocation input = Allocation.createFromBitmap(renderScript,inputBmp);
        final Allocation output = Allocation.createTyped(renderScript,input.getType());
        //(3)
        // Load up an instance of the specific script that we want to use.
        //创建ScriptIntrinsic
        ScriptIntrinsicBlur scriptIntrinsicBlur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript));
        //(4)
        //填充数据
        scriptIntrinsicBlur.setInput(input);
        //(5)
        // Set the blur radius
        //设置模糊半径
        scriptIntrinsicBlur.setRadius(radius);
        //(6)
        // Start the ScriptIntrinisicBlur
        //启动内核
        scriptIntrinsicBlur.forEach(output);
        //(7)
        // Copy the output to the blurred bitmap
        //copy数据
        output.copyTo(inputBmp);
        //(8)
        //销毁renderScript
        renderScript.destroy();
        return inputBmp;

    }

4 第四步,将高斯模糊处理之后的bitmap填充到activity的根布局中,在这之前先简单介绍一下activity的布局结构图

这是从网上找的一张图,通过这张图可以看到,每个activity都包含一个Window对象,在Android中的window对象其实就是PhoneWindow。PhoneWindow内部又包含一个DecorView,这个DecorView就是整个activity的根布局。所以要将模糊处理之后的bitmap填充到整个activity中就需要在decoriew中做手脚。

因为的decorview本身就是一个FrameLayout,我们可以在decorview中创建一个imageview,然后将处理后的图片填充到imageview中去。核心代码如下

@Override
    public void onRecentClick() {
//        Toast.makeText(this,"按了多任务键",Toast.LENGTH_LONG).show();
//      group = (ViewGroup) this.getWindow().getDecorView();
        group.removeView(imageView);
//      创建imageview
        imageView = new ImageView(this);
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        imageView.setLayoutParams(params);

//      截图,并将图片高斯模糊处理
        Bitmap bitmap=PicUtil.rsBlur(GaussianBlurActivity.this,PicUtil.activityShot(GaussianBlurActivity.this),20);
//      将处理后的图片填充到imageview
        imageView.setImageBitmap(bitmap);
        group.addView(imageView);

    }

5 第五步,退出多任务模式时将界面的imageview删除

@Override
    protected void onResume() {
        super.onResume();
      
        for(int i=0;i<group.getChildCount();i++){
            group.removeView(imageView);
        }


    }

贴上最终效果:

前文说过,按照这个思路实现的效果是有瑕疵的,具体的表现就是,当按下多任务键的时候有时候会先出现模糊效果,然后模糊效果又消失了,猜测是和广播发送和接收的时机有关,具体原因有待进一步研究。

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
Android开发中,最近任务高斯模糊可以通过以下步骤实现: 1. 首先,在你的布局文件中添加一个FrameLayout,用于显示最近任务列表。 2. 然后,在你的Activity中获取最近任务列表的视图,并将其转换为Bitmap对象。 3. 接下来,使用RenderScript库中的高斯模糊算法对Bitmap对象进行模糊处理。 4. 最后,将处理后的Bitmap对象设置为最近任务列表的背景,从而实现高斯模糊效果。 下面是一些示例代码,展示了如何在Android应用中实现最近任务高斯模糊效果: ``` // 获取最近任务列表的视图 View recentTasksView = getRecentTasksView(); // 将视图转换为Bitmap对象 Bitmap bitmap = Bitmap.createBitmap( recentTasksView.getWidth(), recentTasksView.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); recentTasksView.draw(canvas); // 使用RenderScript库中的高斯模糊算法对Bitmap对象进行模糊处理 bitmap = blurBitmap(bitmap, 25); // 将处理后的Bitmap对象设置为最近任务列表的背景 recentTasksView.setBackground(new BitmapDrawable(getResources(), bitmap)); ``` 其中,blurBitmap()方法可以使用以下代码实现: ``` private Bitmap blurBitmap(Bitmap bitmap, int radius) { RenderScript rs = RenderScript.create(this); Allocation input = Allocation.createFromBitmap(rs, bitmap, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); Allocation output = Allocation.createTyped(rs, input.getType()); ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); blur.setInput(input); blur.setRadius(radius); blur.forEach(output); output.copyTo(bitmap); rs.destroy(); return bitmap; } ``` 需要注意的是,高斯模糊算法需要较高的计算资源,因此在处理大尺寸的Bitmap对象时可能会出现性能问题。为了避免这种情况,可以考虑在后台线程中进行处理,或者使用更加轻量级的模糊算法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值