Picasso简介<一>

来源:互联网 发布:mysql 倒序 编辑:程序博客网 时间:2024/05/16 04:03

一,简介:

1简意:picasso是Square公司开源的一个Android图形缓存库,地址http://square.github.io.picasso/

2.突出优点:可以实现图片下载和缓存功能

在实际开发中异步图片加载时需考虑:

(1)在adapter中需要取消已经不在视野范围的ImageView图片资源的加载,否则会导致图片错位,Picasso已经解决了这个问题

(2)复杂的图片进行压缩,尽量减少内存的消耗

(3)实现内存缓存和二级硬盘缓存的效果

3.使用Picasso框架解决的图片下载中遇到的问题:

(1)在adapter中回收和取消当前下载

(2)使用最少的内存完成图片的转换

(3)自带内存和硬盘缓存

(4)图形转换,比如大小、旋转等

(5)加载网络资源和本地资源

(6)采用链式调用

4.与Universal-ImageLoader库对比:
1.都有高效的网络图片下载和缓存性能;
2.Universal-ImageLoader功能多,灵活使用配置;
3.Picasso使用复杂的图片压缩转换来尽可能的减少内存消耗;
4.在Adapter中需要取消已经不在视野范围的ImageView图片资源的加载,否则会导致图片错位,Picasso已经解决了这个


二,简单使用

1.加载一张图片:

(1)添加依赖:点击app右键---》open module settings -->Dependencies下---右上角+号-->dependecy,输入picasso,选择com.squareup.picasso.Picasso

(2)使用,如,为按钮设置监听,imageview显示图片

布局:定义一个button,一个ImageView

代码:

        button.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    Picasso.with(MainActivity.this).load(IMAGE_PATH).placeholder(R.mipmap.ic_launcher).fit().into(mImageView);                }        });

 private final String IMAGE_PATH = "http://www.leawo.cn/attachment/201404/15/1077476_1397532112ke37.png";


Picasso.with(Context).load(图片路径).placeholder(显示前的图片).fit().into(显示到哪里)

效果:(添加网络权限)点击按钮后显示一张网络图片(但是在显示之前会有一个短暂的显示本地图片的过程)


2.用listView来显示url请求回来的数据:新闻图片+内容

(1)布局,定义ListView,在Activity中为该listView绑定控件id,

(2)自定义Picasso类:提供几个方法,如下:

public class PicassoUtils {    /**     * 指定图片宽高进行加载     * @param context     * @param path     * @param width     * @param height     * @param imageView     */    public static void loadImageWithSize(Context context , String path , int width ,                                     int height , ImageView imageView){        Picasso.with(context).load(path).resize(width , height).centerCrop().into(imageView);    }    /**     * 根据resID来加载图片     * @param context     * @param path     * @param resID     * @param imageView     */    public static void loadImageWithHolder(Context context , String path , int resID , ImageView imageView){        Picasso.with(context).load(path).placeholder(resID).into(imageView);    }    /**     * 自定义裁剪类来加载图片     * @param context     * @param path     * @param imageView     */    public static void loadImageWithCrop(Context context , String path , ImageView imageView){        Picasso.with(context).load(path).transform(new CropSquareTransformation()).into(imageView);    }    /**     * 实现对图片的自定义裁剪     */    public static class CropSquareTransformation implements Transformation{        @Override        public Bitmap transform(Bitmap source) {            //获取图片的宽度和高度中的最小值            int size = Math.min(source.getWidth() , source.getHeight());            int x = (source.getWidth() - size)/2;            int y = (source.getHeight() - size)/2;            Bitmap result = Bitmap.createBitmap(source , x ,y ,size , size);            if(result != null){                source.recycle();//进行回收            }            return result;  //返回图片        }        @Override        public String key() {            return "square()";  //自己取一个名字        }    }}

(3)根据url,查看返回结果,创建实体类,这里取图片,summary,subject:

url:本来

http://litchiapi.jstv.com/api/GetFeeds?column=17&PageSize=20&pageIndex=1&val=AD908EDAB9C3ED111A58AF86542CCF50
bean类:

public class NewsItem {    private String subject ;        //新闻主题    private String summary ;        //新闻内容    private String cover ;          //新闻图片    public String getSubject() {        return subject;    }    public void setSubject(String subject) {        this.subject = subject;    }    public String getSummary() {        return summary;    }    public void setSummary(String summary) {        this.summary = summary;    }    public String getCover() {        return cover;    }    public void setCover(String cover) {        this.cover = cover;    }}

(4)创建访问任务,这里先用AsyncTask:代码如下:

    /**     * 异步任务实现:String,void,返回类型:一个list<NewsItem>集合     */    class MyTask extends AsyncTask<String , Void , List<NewsItem>>{        /**         * 准备执行前:显示窗口进度条         */        @Override        protected void onPreExecute() {            super.onPreExecute();            //进度条窗口显示            dialog.show();        }        @Override        protected List<NewsItem> doInBackground(String... params) {            //创建HttpClient对象            HttpClient httpClient = new DefaultHttpClient();            //创建HttpGet            HttpGet httpGet = new HttpGet(params[0]);            //创建返回对象            HttpResponse response = null;            //创建List<NewsItem>集合            List<NewsItem> list = new ArrayList<>();            try {                //获取返回结果对象Response                response = httpClient.execute(httpGet);                //判断是否请求成功                if(response.getStatusLine().getStatusCode() == 200){                    //获取HttpEntity对象                    HttpEntity entity =  response.getEntity();                    String json_value = EntityUtils.toString(entity , "utf-8");                    //根据返回数据进行解析:                    //http://litchiapi.jstv.com/api/GetFeeds?column=17&PageSize=20&pageIndex=1&val=AD908EDAB9C3ED111A58AF86542CCF50                    JSONArray jsonArray = new JSONObject(json_value)                            .getJSONObject("paramz").getJSONArray("feeds");                    //获取每一条数据                    for(int i = 0; i < jsonArray.length(); i++){                        JSONObject element = jsonArray.getJSONObject(i).getJSONObject("data");                        NewsItem item = new NewsItem();                        item.setCover(element.getString("cover"));                        item.setSubject(element.getString("subject"));                        item.setSummary(element.getString("summary"));                        list.add(item);                    }                }            } catch (Exception e) {                e.printStackTrace();            }            return list;        }        @Override        protected void onPostExecute(List<NewsItem> newsItems) {            super.onPostExecute(newsItems);                        //完成时初始化MyAdapter            adapter = new MyAdapter(newsItems);            //为listView设置MyAdapter            listView.setAdapter(adapter);            //进度条窗口取消            dialog.cancel();        }    }
其中窗口进度条:

    //定义进度条窗口    private ProgressDialog dialog ;

        //创建进度条窗口对象        dialog = new ProgressDialog(this);        //设置窗口标题        dialog.setTitle("loading......");

(5)自定义MyAdapter继承BaseAdapter:

    /**     * 自定义适配器     */    class MyAdapter extends BaseAdapter{        //List<NewsItem>集合        private List<NewsItem> data;        /**         * 初始化适配器         * @param data         */        public MyAdapter(List<NewsItem> data){            this.data = data;        }        @Override        public int getCount() {            return data.size();        }        @Override        public Object getItem(int position) {            return data.get(position);        }        @Override        public long getItemId(int position) {            return 0;        }        @Override        public View getView(int position, View convertView, ViewGroup parent) {                        //创建MyViewHolder            MyViewHolder holder = null;                        //一次            if(convertView == null){                holder = new MyViewHolder();                convertView = getLayoutInflater().inflate(R.layout.my_adapter_layout , parent , false);                holder.cover = (ImageView)convertView.findViewById(R.id.cover_img);                holder.subject = (TextView)convertView.findViewById(R.id.subject);                holder.summary = (TextView)convertView.findViewById(R.id.summary);                convertView.setTag(holder);                Log.d(TAG , "convertView:" +position);            }else {                holder = (MyViewHolder)convertView.getTag();            }            //分别设置图片,主题,内容            holder.subject.setText(data.get(position).getSubject());            //Log.d(TAG , data.get(position).getSubject());            holder.summary.setText(data.get(position).getSummary());            //Log.d(TAG , data.get(position).getSummary());            PicassoUtils.loadImageWithSize(ListViewActivity.this , "http://litchiapi.jstv.com" + data.get(position).getCover(),                    400,300,holder.cover);            return convertView;        }    }

MyViewHolder:

    private static class MyViewHolder{        ImageView cover;        TextView subject;        TextView summary;    }

MyAdapter的布局:就是一个图片,两个textView(对应新闻图片,标题,内容)
记得添加网络权限:

<uses-permission android:name="android.permission.INTERNET"/>




(6)如果需要解决用户飞速下滑(即不想浏览中间某些新闻)时,picasso可以解决:

自定义onScrollListener类:

    /**     * 自定义OnScrollListener类     */    public class  ListScroller implements AbsListView.OnScrollListener{        /**         * 下滑状态改变时调用         * @param view         * @param scrollState         */        @Override        public void onScrollStateChanged(AbsListView view, int scrollState) {            //创建Picasso            final Picasso picasso = Picasso.with(ListViewActivity.this);            //判断状态            if(scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_TOUCH_SCROLL){                //更新                picasso.resumeTag(ListViewActivity.this);            }else {                //暂停                picasso.pauseTag(ListViewActivity.this);            }        }        @Override        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {        }    }

为listView设置滑动监听:

        //listView.setOnScrollListener(new ListScroller());
即可以,截图略
附注代码地址:

https://github.com/maiyu-green/PicassoDemo


三,picasso的特点与常用设置方法:

通过以上的简单介绍,我们大概知道:

1.Picasso的特点:

总结以上,picasso的特点:
(1)自带内存和硬盘二级缓存功能
(2)加载本地资源,资产,SD卡及ContentProvider中的图片
(3)在Adapter中取消已经不在视野范围的ImageView图片资源的加载,否则会导致图片错位,Picasso解决了图片错位问题
(4)使用图片压缩尽可能的减少内存消耗
(5)图形转换操作,如变换大小,旋转等,提供了接口来让用户自定义转换操作

2.Picasso的常用设置方法

(1)加载本地资源、资产目录、SD卡已经ContentProvider的图像

基本语法:

Picasso.with(上下文).load(图片).into(ImageView)

加载图片资源:

        //加载资源图片        Picasso.with(this).load(R.mipmap.ic_launcher).into(mImageView);        //加载资产目录图片        Picasso.with(this).load("file://android_asset/logo.png").into(mImageView);        //加载SD Card图片文件        Picasso.with(this).load(new File("路径")).into(mImageView);        //加载网络图片        Picasso.with(this).load("url地址").into(mImageView);


下面是RequestCreator常用设置方法

(2)设置占位图片:下载前,下载出错时的图像,picasso会尝试3次请求,三次都失败会显示error方法:

        Picasso.with(context)                .load(url)                //下载前显示图片                .placeholder(R.mipmap.ic_launcher)                //下载出错显示图片                .error(R.mipmap.ic_launcher)                .into(mImageView);
(3)无淡入淡出:

                .noFade()
(4)图片重新调整大小:有两个方法

.resize(width,height)

.resizeDimen(targetWidthResId , targetHieghtResId)
(5)图片剪切类型:centerCrop,fit,centerInside

放在load之后:centerCrop与centerInside需要配合resize(),放在它之后,而fit不能再resize(),

centerCrop----会根据resize()方法的宽高进行裁剪

centerInside---会根据resize()方法的宽高进行比例缩放

如一张长方形图片,resize(100,100)后,centerCrop---结果正方形,centerInside结果--长方形缩小图

(6)自定义图形转换:为了更好的适配布局和减少存储空间,

利用transform方法:

    /**     * 实现对图片的自定义裁剪     */    public static class CropSquareTransformation implements Transformation{        @Override        public Bitmap transform(Bitmap source) {            //获取图片的宽度和高度中的最小值            int size = Math.min(source.getWidth() , source.getHeight());            int x = (source.getWidth() - size)/2;            int y = (source.getHeight() - size)/2;            Bitmap result = Bitmap.createBitmap(source , x ,y ,size , size);            if(result != null){                source.recycle();//进行回收            }            return result;  //返回图片        }        @Override        public String key() {            return "square()";  //自己取一个名字        }    }
(7)图片旋转:

.rotate()方法

(8)设置图片质量对于不透明的图片可以使用RGB_565(一个像素点占用2个字节)来优化内存。

默认情况下Android使用ARGB_8888---一个像素点占用4个字节

用肉眼看,效果差不多

.config(Bitmap.Config.GRB_566)

(9)查看大图时放弃内存缓存memory cache:

Picasso默认会使用设备的15%的内存作为内存图片缓存,且现有的API无法清空内存缓存

  在查看大图时放弃使用内存缓存,图片从网络下载完成后会自动缓存到磁盘中,加载会从磁盘中加载,这样可以加速内存回收

        Picasso.with(getApplicationContext())                .load(url)                //NO_CACHE指图片加载跳过从内存缓存查找,NO_STORE指图片存储时不往内存缓存中存储                .memoryPolicy(MemoryPolicy.NO_CACHE , MemoryPolicy.NO_STORE)                .into(mImageView);

(10)设置tag标签:可以用来pause,resume和cancel访问

        Picasso.with(this).pauseTag("pause标签");        Picasso.with(this).resumeTag("resume标签");        Picasso.with(this).cancelTag("标签");
以下是在manifest中的设置:

(11)新进程中查看大图:

列表页的内存已经非常稳定,但查看大图时,常占用20多兆内存,加上现有进程内存,容易OOM

所以,在新进程中打开Activity成为比较巧取的避免oom的方式

        <activity android:name=".MainActivity"            android:process=":picture"/>
只要在定义activity是添加process属性,即可在新进程中打开此activity,因为Picasso也将在新进程中创建基于新ApplicationContext的单例

3.Picasso在Application的常见设置

    private void intoPicasso(){        Picasso picasso = new Picasso.Builder(this)                //设置内存缓存大小 10m                .memoryCache(new LruCache(10 << 20))                //下载图片的格式,采用rgb_565节省一半内存                .defaultBitmapConfig(Bitmap.Config.RGB_565)                //配置下载器                //.downloader(new UrlConnectionDownloader())                //.downloader(new OkHttpDownloader())                .downloader(new MyDownLoader(getCacheDir() , 20 << 20))                //设置调试标志,位于左上角                //红色---代表从网络下载的图片                //蓝色--代表从磁盘缓存加载的图片                //绿色--代表从内存中加载的图片                .indicatorsEnabled(true)                .build();        Picasso.setSingletonInstance(picasso);    }