从头开始敲代码之《从BaseApplication/Activity开始(四)》

转载请注明出处:王亟亟的大牛之路

早上无聊看以前下的一大堆资料,发现一个用JNI实现的模糊效果,效果都差不多,但是对JNI的不熟悉让我不太推荐这种办法(不了解的总不方便,调试,修改都是)

然后在Git上找到个不错的实现,还是分2种的,应对于各种需要。

这一篇文章会介绍什么

1.模糊视图处理
2.线程操作优化

1.Renderscript

2.FastBlur

效果图

布局:

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/picture"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop" />

    <LinearLayout
        android:id="@+id/controls"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#7f000000"
        android:orientation="vertical"
        android:layout_gravity="bottom"/>

    <TextView
        android:id="@+id/text"
        android:gravity="center_horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="测试用的字"
        android:textColor="@android:color/black"
        android:layout_gravity="center"
        android:textStyle="bold"
        android:textSize="48sp" />
</FrameLayout>

并不是自定义控件,而是对图像本身进行了操作。

1.创建了一个空的bitmap,把背景的一部分复制进去,之后我会对这个bitmap进行模糊处理并设置为TextView的背景。

2.通过这个bitmap保存Canvas的状态;

3.在父布局文件中把Canvas移动到TextView的位置;

4.把ImageView的内容绘到bitmap中;

5.此时,我们就有了一个和TextView一样大小的bitmap,它包含了ImageView的一部分内容,也就是TextView背后一层布局的内容;

6.创建一个Renderscript的实例;

7.把bitmap复制一份到Renderscript需要的数据片中;

8.创建Renderscript模糊处理的实例;

9.设置输入,半径范围然后进行模糊处理;

10.把处理后的结果复制回之前的bitmap中;

11.已经把bitmap进行模糊处理了,可以将它设置为TextView背景了;

2种形式在ViewPager中分别实现,RSBlurFragment,FastBlurFragment

FuzzyActivity(容器)

public class FuzzyActivity extends FragmentActivity {

        private CustomPagerAdapter pagerAdapter;
        private RSBlurFragment rsBlurFragment;
        private FastBlurFragment fastBlurFragment;

        private ViewPager viewPager;
        private ArrayList<Fragment> fragments ;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_fuzzy_layout);
            fragments = new ArrayList<Fragment>();
            rsBlurFragment=new RSBlurFragment();
            fastBlurFragment=new FastBlurFragment();
            fragments.add(rsBlurFragment);
            fragments.add(fastBlurFragment);

            pagerAdapter =
                    new CustomPagerAdapter(
                            getSupportFragmentManager(),fragments);
            viewPager = (ViewPager) findViewById(R.id.pager);
            viewPager.setAdapter(pagerAdapter);
            viewPager.setPageTransformer(true, new ZoomOutPageTransformer());

            viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                }

                @Override
                public void onPageSelected(int position) {
                }

                @Override
                public void onPageScrollStateChanged(int state) {

                }
            });
        }

        public class CustomPagerAdapter extends FragmentStatePagerAdapter {
            private ArrayList<Fragment> fragments ;

            public CustomPagerAdapter(FragmentManager fm) {
                super(fm);

            }

            public CustomPagerAdapter(FragmentManager fm,ArrayList<Fragment> fragments) {
                super(fm);
                this.fragments=fragments;
            }

            @Override
            public Fragment getItem(int i) {
                return fragments.get(i);
            }

            @Override
            public int getCount() {
                return fragments.size();
            }

            @Override
            public CharSequence getPageTitle(int position) {
                return fragments.get(position).toString();
            }
        }
    }

RSBlurFragment

public class RSBlurFragment extends Fragment {
    private ImageView image;
    private TextView maimai;
    private TextView statusText;
    private CheckBox downScale;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.blur_layout, container, false);
        image = (ImageView) view.findViewById(R.id.picture);
        maimai = (TextView) view.findViewById(R.id.text);
        image.setImageResource(R.drawable.fuzzybg);
        statusText = addStatusText((ViewGroup) view.findViewById(R.id.controls));
        addCheckBoxes((ViewGroup) view.findViewById(R.id.controls));
        applyBlur();
        return view;
    }

    private void applyBlur() {
        image.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                image.getViewTreeObserver().removeOnPreDrawListener(this);
                image.buildDrawingCache();

                Bitmap bmp = image.getDrawingCache();
                blur(bmp, maimai);
                return true;
            }
        });
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    private void blur(Bitmap bkg, View view) {
        long startMs = System.currentTimeMillis();

        float scaleFactor = 1;
        float radius = 20;

        if (downScale.isChecked()) {
            scaleFactor = 8;
            radius = 2;
        }

        Bitmap overlay = Bitmap.createBitmap((int) (view.getMeasuredWidth() / scaleFactor),
                (int) (view.getMeasuredHeight() / scaleFactor), Bitmap.Config.ARGB_8888);

        Canvas canvas = new Canvas(overlay);

        canvas.translate(-view.getLeft() / scaleFactor, -view.getTop() / scaleFactor);
        canvas.scale(1 / scaleFactor, 1 / scaleFactor);
        Paint paint = new Paint();
        paint.setFlags(Paint.FILTER_BITMAP_FLAG);
        canvas.drawBitmap(bkg, 0, 0, paint);

        RenderScript rs = RenderScript.create(getActivity());

        Allocation overlayAlloc = Allocation.createFromBitmap(
                rs, overlay);

        ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(
                rs, overlayAlloc.getElement());

        blur.setInput(overlayAlloc);

        blur.setRadius(radius);

        blur.forEach(overlayAlloc);

        overlayAlloc.copyTo(overlay);

        view.setBackground(new BitmapDrawable(
                getResources(), overlay));

        rs.destroy();
        statusText.setText(System.currentTimeMillis() - startMs + "ms");
    }

    @Override
    public String toString() {
        return "RenderScript";
    }

    private TextView addStatusText(ViewGroup container) {
        TextView result = new TextView(getActivity());
        result.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        result.setTextColor(0xFFFFFFFF);
        container.addView(result);
        return result;
    }

    private void addCheckBoxes(ViewGroup container) {
        downScale = new CheckBox(getActivity());
        ViewGroup.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
        downScale.setLayoutParams(lp);
        downScale.setText("Downscale before blur");
        downScale.setVisibility(View.VISIBLE);
        downScale.setTextColor(0xFFFFFFFF);
        downScale.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                applyBlur();
            }
        });
        container.addView(downScale);
    }
}

FastBlurFragment

public class FastBlurFragment extends Fragment {
    private final String DOWNSCALE_FILTER = "downscale_filter";

    private ImageView image;
    private TextView text;
    private CheckBox downScale;
    private TextView statusText;

    ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.blur_layout, container, false);
        image = (ImageView) view.findViewById(R.id.picture);
        text = (TextView) view.findViewById(R.id.text);
        image.setImageResource(R.drawable.fuzzybg);
        statusText = addStatusText((ViewGroup) view.findViewById(R.id.controls));
        addCheckBoxes((ViewGroup) view.findViewById(R.id.controls));

        if (savedInstanceState != null) {
            downScale.setChecked(savedInstanceState.getBoolean(DOWNSCALE_FILTER));
        }
        LogUtils.d("------<onCreateView  "+Thread.currentThread().getName());
        initImage();
        return view;
    }

    private void initImage(){
        singleThreadExecutor.execute(new SonThread());
    }

    private void applyBlur() {
        image.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                image.getViewTreeObserver().removeOnPreDrawListener(this);
                image.buildDrawingCache();

                Bitmap bmp = image.getDrawingCache();
                blur(bmp, text);
                return true;
            }
        });
    }

    private void blur(Bitmap bkg, View view) {
        long startMs = System.currentTimeMillis();
        float scaleFactor = 1;
        float radius = 20;
        if (downScale.isChecked()) {
            scaleFactor = 8;
            radius = 2;
        }

        Bitmap overlay = Bitmap.createBitmap((int) (view.getMeasuredWidth()/scaleFactor),
                (int) (view.getMeasuredHeight()/scaleFactor), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(overlay);
        canvas.translate(-view.getLeft()/scaleFactor, -view.getTop()/scaleFactor);
        canvas.scale(1 / scaleFactor, 1 / scaleFactor);
        Paint paint = new Paint();
        paint.setFlags(Paint.FILTER_BITMAP_FLAG);
        canvas.drawBitmap(bkg, 0, 0, paint);

        overlay = FastBlur.doBlur(overlay, (int) radius, true);
        view.setBackground(new BitmapDrawable(getResources(), overlay));
        statusText.setText(System.currentTimeMillis() - startMs + "ms");
    }

    @Override
    public String toString() {
        return "Fast blur";
    }

    private void addCheckBoxes(ViewGroup container) {

        downScale = new CheckBox(getActivity());
        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
        downScale.setLayoutParams(lp);
        downScale.setText("Downscale before blur");
        downScale.setVisibility(View.VISIBLE);
        downScale.setTextColor(0xFFFFFFFF);
        downScale.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                singleThreadExecutor.execute(new SonThread());
                LogUtils.d("------<addCheckBoxes  " + Thread.currentThread().getName());
            }
        });
        container.addView(downScale);
    }

    private TextView addStatusText(ViewGroup container) {
        TextView result = new TextView(getActivity());
        result.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        result.setTextColor(0xFFFFFFFF);
        container.addView(result);
        return result;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putBoolean(DOWNSCALE_FILTER, downScale.isChecked());
        super.onSaveInstanceState(outState);
    }

    class SonThread implements Runnable{
        public void run() {
            LogUtils.d("------<sonThread  "+Thread.currentThread().getName());
            applyBlur();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        singleThreadExecutor.shutdown();
    }
}

运行效果:

顺便提一下版本的问题,ScriptIntrinsicBlur只支持API17以上,也可以用Renderscript的support lib降低一些API版本的要求

实现的理论在上面已经列明了,来说下为什么在FastBlur的实现过程中使用线程操作。

我们知道在Android中渲染一帧的时间应该不超过16ms(60fps),但如果在UI线程中做模糊处理就会让帧率降到了17fps。显然这是不可接受的,我们需要把这个操作移到子线程中操作了。

然后就是 说下 ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

少侠们我们一定要放弃new Thread …….一系列啊

诸如:

new Thread(new Runnable() {

    @Override
    public void run() {}

}).start();

1.每次新建对象性能差。

2. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。

3. 缺乏更多功能,如定时执行、定期执行、线程中断。

用Executors提供四种线程池可以更好的方便我们去管理我们的线程

1.newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

2.newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

3.newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

4.newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

使用方法跟我代码中差不多但是,一定会更高效,更合理。

周末愉快!!

源码地址:http://yunpan.cn/cHfZLUjzGbZ4e 访问密码 b78e

分析的出处http://trickyandroid.com/advanced-blurring-techniques/

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-07 13:31:00

从头开始敲代码之《从BaseApplication/Activity开始(四)》的相关文章

从头开始敲代码之《从BaseApplication/Activity开始》

转载请注明出处王亟亟的大牛之路 其安易持,其未兆易谋:其脆易泮,其微易散.为之于未有,治之于未乱.合抱之木,生于毫末:九层之台,起于垒土:千里之行,始于足下.为者败之,执者失之.是以圣人无为故无败,无执故无失.民之从事,常于几成而败之.慎终如始,则无败事.是以圣人欲不欲,不贵难得之货,学不学,复众人之所过,以辅万物之自然而不敢为. 作为系列专题的第一篇,这一篇文章属于小难产,中间夹杂着一些工作上的事,一些蛋疼的事(学车之类的),说实在的,做了Coder之后发现业余时间还真不是太多....唉...

从头开始敲代码之《从BaseApplication/Activity开始(五)》(自定义控件,实现点击/滑动翻页)

转载请注明出处:王亟亟的大牛之路 开场白惯用鼓励诗句: 黑发不知勤学早,白首方悔读书迟. -- 颜真卿<劝学诗> 这一系列的博文这是第五篇了,感谢大家的支持以及陪伴,往后我也会继续努力写出高质量的内容,谢谢 今天上的是一个自定义View,新鲜出炉,先上下效果(是一张张截图拼接的Gif动画都看不出来了,大家理解就行可以下Demo跑) 样例分析(最简单的描述了) 黑色线条是我们的手机 红色是我们自定义的"TitleBar" 蓝色是我们的自定义布局 紫色是自定义布局填充的内容 我

从头开始敲代码之《从BaseApplication/Activity开始(二)》

转载请注明出处:王亟亟的大牛之路 愿意花时间写东西不容易,人啊,都是有血有肉有思想的,借鉴是学习,纯Copy就不好了,谢谢 部分资料参考于网上. <赠梁任父同年>黄遵宪 寸寸河山寸寸金,侉离分裂力谁任? 杜鹃再拜忧天泪,精卫无穷填海心. 上一篇我们讲到了简易的封装 对我们提高效率的好处,这一篇继续写下去,如果第一篇没看过的希望能看下,方便理解.链接:亟亟在安卓的进阶实例 这一次我们利用最基本的Activity生命周期中的方法,来对用户蓝牙进行识别操作,并在过程中考虑用户层面的操作理解,顺便补充

每天下午5点半下班,但是我很少在晚上1点之前睡过觉。因为都在敲代码

有时候,并不是我不想睡觉,不想休息,我也想舒适,也很想舒舒服服的坐着不工作,但很难做到,一天不敲代码,一天不学习新知识现在就浑身难受,不知道我这股热情能坚持多久,但这样的强度已经连续坚持了7个多月了,我很充实也很充实,每天我的精神饱满,战斗力极强.在做项目的时候,有一些细节方面的东西,我总想做到最好,总想做到用户体验最优,代码封装最优.有时候睡觉的时候也在想.我对未来是充满信心和期待的,我并不着急,我还很年轻,永远都年轻~ 前几天,小杰来公司面试,被我公司面试官虐的不要不要的,我总以为他很厉害,

使用Alcatraz为Xcode安装XActivatePowerMode插件, 从此敲代码逼格大大滴~

Alcatraz 是一款 Xcode的插件管理工具,可以用来管理XCode的 插件.模版以及颜色配置的工具. 关于Alcatraz的安装,这里有一篇不错的博文,请参考安装:http://www.cnblogs.com/wendingding/p/4964661.html 最近有一款插件叫ActivatePowerMode,堪称装逼神器啊,敲代码的时候,炫彩的火花尾巴效果简直屌炸天~,详情可以看XActivatePowerMode在github中的介绍https://github.com/qfis

程序员不能只会敲代码还要会投资理财

程序员不能只会敲代码,还要会理财或者说投资. 当我们步入职场,随着我们工作经验的增长我们的薪资相应的也会快速提高,很多人可能思维上还没有改变过来,不知道如何利用自己的闲钱去保值或者增值.当然现在互联网理财发展已经比较的成熟了,大多数的人也知道用自己发的工资直接购买余额宝来赚取利息,余额宝可以说是开启了国人理财的意识.对于我们普通人来说可以有以下几种投资: XX宝比如余额宝(货币基金),收益比银行活期存款或者某些定期存款还高,风险低几乎不会损失你的本金,但是一年的收益还是不能抵抗通货膨胀: 互联网

iOS Sprite Kit教程之编敲代码以及Xcode的介绍

iOS Sprite Kit教程之编敲代码以及Xcode的介绍 Xcode界面介绍 一个Xcode项目由非常多的文件组成,比如代码文件.资源文件等.Xcode会帮助开发人员对这些文件进行管理.所以,Xcode的界面也比較复杂,如图1.40所看到的. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" > 图

(016)给定一个有序数组(递增),敲代码构建一棵具有最小高度的二叉树(keep it up)

给定一个有序数组(递增),敲代码构建一棵具有最小高度的二叉树. 因为数组是递增有序的.每次都在中间创建结点,类似二分查找的方法来间最小树. struct TreeNode { int data; TreeNode* leftChild; TreeNode* rightChild; }; void newNode(TreeNode*& vNode, int vData) { vNode = new TreeNode; vNode->data = vData; vNode->leftChi

十年码农,过了十年他们依旧在敲代码

摘要:话说程序员也是一个吃青春饭的职业,经常需要加班.高强度工作.新技术学习需求等等,让青春不再来的从业者感觉吃力,但仍然有一大批人因为各种原因十年如一日的敲着代码,十年历程是怎样的一种经历,你会成为其中之一吗? 十年前的2004年,中国网民突破9000万可喜可贺,第三代互动式搜索引擎搜狗刚刚问世,新浪.搜狐.网易是中国顶级的互联网企业,2004互联网大事记里看不到BAT的影子,小编在读初中,当然,也有一批很平凡的程序员在敲代码. 来看看这十几位码农十年或平凡.或漂泊的历程(以下程序员信息主要来