盗版毕加索

来源:互联网 发布:win8.1配置java环境 编辑:程序博客网 时间:2024/05/20 00:13

突然感触blog对于开发人员是多麽的重要,无论你是否写过blog,只要你身在技术的阵营中,就一定从blog中受益过。至于写与不写,只是个人习惯问题。

我是android菜鸟,此篇blog写给同样刚刚进入android怀抱的菜鸟们,让我们尽情的fighting with android!

最近在开发一个程序,用到了GridView这个View,遇到的问题就是当加载的图片达到50k以上时,GridView的滑动会出现明显卡顿,其实不光是GridView控件,其他控件listview、viewpager等都会遇到这个问题。甚至出现oom,也就是由于内存不足而crash。
出现卡顿问题原因:显而易见,图片大,导致imageView.setImageResource需要更多时间,图片没加载完,滑动就卡主
oom出现原因:大。

知道了原因就好解决了,三级缓存技术+异步加载,于是我就想自己写个库以后再遇到图片的加载就都是这个套就ok了,谁知github上有个叫毕加索的,都是套路,这个Picasso那是相当的nb,不但三级缓存+异步加载,而且还可以设置bitmap属性、设置图片大小、设置加载前显示的图片、加载错误显示的图片、从resourceId加载图片、从sd卡加载图片、从网络加载图片;服务可真周全,只有你想不到的。使用起来相当简单。
Picasso.with(context).load(url).placeholder(R.drawable.user_placeholder).error(R.drawable.user_placeholder_error).into(imageView);

技术是自己的,只有学到了知识,自己才会强大。把别人的库用的很6什么也证明不了。

三级缓存:内存、sd卡、网络。当需要加载一个image时,首先检测是否存在于内存,然后检测sd卡,都没有那就乖乖的从网络加载。
异步加载:当gridView滑动时,图片太大,滑动就阻塞在哪里。解决办法就是异步加载,开个线程,线程在后台慢慢折腾,流畅对我们更重要。别tm问我流畅是谁

一口吃不了胖子,Picasso很厉害,我们这里只实现精简版的Picaso,我们要实现的功能就是二级缓存+异步加载。二级就是内存和sd卡,异步就是后台线程。我们的Picaso初步设计成单利模式,这样所有的Image加载都可以轻松使用,当有image需要加载时,我们首先查看内存,内存没有就将这个任务添加到堆栈中,Picaso会有个线程一直循环检测这个stack,有任务就执行加载,没有任务就wait等待。理想效果就是滑动的时候,即使图片很大,也不会阻塞,顶多就是滑动到大图片,显示空白但是滑动流畅,慢慢的空白被异步线程加载。

下面就构思下,我们要实现的库,伪代码先给出框架

public class Picaso{//not Picasso    private static Picaso;//单利模式    private MemoCache memCache;//内存缓存    private Stack taskStack;//任务队列    private LoadThread loadThread;//后台加载线程    public Picaso instancePicaso(){}    public void loadImage(){}    private class MemoCache{}    private class LoadThread extends Thread{}}

下面对上面的代码说下思路:

  • instancePicaso函数是单例模式,就是返回本地的Picaso变量,而不是每次都实例化一个Picaso类。
  • MemoCache 内存缓存类,使用软引用,将加载过的bitmap存储到map中,下次再使用相同的item时直接返回。
    (这里涉及到的知识点为对象的强引用、软引用、弱引用、虚引用;还有lruCache类的使用。)
  • taskStack是个堆栈,作用就是当加载的image不在内存缓存中,那么new个新任务,并添加到这个栈中,这样另外的一个线程负责循环读取堆栈并执行加载任务。
  • loadThread线程,这个就是后台负责循环加载任务的线程,taskStack中有数据就读取并执行,没有数据就睡觉。
    (这里涉及的知识点有线程的中止方式isInterrupted,队列数据的原子操作synchronized,线程的wait和notifyAll)

到这里你可以自己动手实现你的毕加索了。后面会给我的源码。

这里在普及下加载图片的基础知识
无论是从drawable资源中还是从cs卡中,方法都差不多。
我们最终是将pic添加到imageview中,imageview的方法是ImageView.setImageBitmap(Bitmap bitmap),而bitmap的来源是使用BitmapFactory.decodeStream(InputStream)或者BitmapFactory.decodeStream(InputStream, Rect, Options)
InputStream来源是context.getResources().openRawResource(resourseId);
Rect是限制大小的类
Options是一个关键的类,里面可以压缩数据,设置图片编码方式。
图片的编码方式有:
编码方式有:(ARGB分别代表透明度、红、绿、蓝)
Bitmap.Config ALPHA_8 占8位(具体情况不清楚)
Bitmap.Config ARGB_4444 占16位(ARGB各4位)//废弃了
Bitmap.Config ARGB_8888 占32位(ARGB各8位)//包含三基色的同时还包含透明度,所以很大
Bitmap.Config RGB_565 占16位(R5位G6位B5位)//显示效果还可以,大小适中
下面给出使用方法的栗子,对,栗子:

    /********************************************     * 根据资源id和context获取特定options的bitmap      * @param resourseId    资源id     * @param context       环境上下文     * @return      获取到的bitmap     ***********************************************/    private Bitmap getImageBitmap(int resourseId, Context context){        BitmapFactory.Options opts = new BitmapFactory.Options();        opts.inJustDecodeBounds = true;        Bitmap oldBitmap = BitmapFactory.decodeResource(context.getResources(), resourseId);        int oldWidth = oldBitmap.getWidth();        int oldHeight = oldBitmap.getHeight();        opts.inSampleSize = calcCompressSize(oldWidth, oldHeight, 128, 128);        opts.inJustDecodeBounds = false;        opts.inPreferredConfig = Bitmap.Config.RGB_565;        //InputStream is = context.getResources().openRawResource(resourseId);        //return BitmapFactory.decodeStream(is, null, opts);        return BitmapFactory.decodeResource(context.getResources(), resourseId, opts);    }    /********************************************     *   * 获取压缩比率,根据最小的高度比或宽度比,来获取倍率     * @param oldWidth  pic的原始宽度     * @param oldHeight pic的原始高度     * @param reqWidth  pic指定宽度     * @param reqHeight pic指定高度     * @return  返回压缩比率,应该为2的倍数,如果不是,会自定找离2最近的那个整数倍的数     ****************************************************************/    private int calcCompressSize(int oldWidth, int oldHeight, int reqWidth, int reqHeight){        if(oldWidth >= reqWidth || oldHeight >= reqHeight){            return 1;        }        int widthRatio = Math.round(oldWidth/reqWidth);        int heightRatio = Math.round(oldHeight/reqHeight);        return widthRatio >= heightRatio ? widthRatio:heightRatio;    }

最后给出Picaso的完整代码,在需要加载image的地方使用Picaso.instansePicaso,最后用完了记得stop下,为了关闭它的那个线程。

- -!, 我是链接

1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 起诉后对方没钱怎么办 法院起诉人不到怎么办 治安拘留跑了怎么办 看守所里生病了怎么办 二审上诉被驳回怎么办 醉酒驾车取保候审以后怎么办 小案子证据不足怎么办 撞车不严重逃逸怎么办 被执行人没有财产执行怎么办 挖到人头了怎么办 取保保证金不退怎么办 被诬陷经济诈骗怎么办 醉驾刑事拘留后怎么办 被别人举报赌博怎么办 涉黄刑事拘留怎么办取保候审 换了车牌保险怎么办 车辆转让后保险怎么办 立案后警察不管怎么办 打架后对方讹人怎么办 工商被恶意举报怎么办 店铺被工商举报怎么办 被买单侠恐吓怎么办? 团伙作案刑事拘留怎么办取保 欢乐麻将老输怎么办 回不了家怎么办身份证 没注意闯红灯了怎么办 摩托车被套牌了怎么办? 发现员工偷钱怎么办 盗窃刑事拘留7天怎么办 盗窃抓不到人怎么办 发现宿舍被盗后怎么办(  ) 发现宿舍被盗后怎么办() 回收到赃物电瓶怎么办 不知情买了赃物怎么办 盗窃单位要报警怎么办 上网吸烟被逮住怎么办 有人在微信骂我怎么办 网吧抽烟被拍照怎么办 诈骗被拘留该怎么办 行政拘留人跑了怎么办 车牌号被偷了怎么办