Picasso簡介

一,簡介:

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);
    }









發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章