Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Volley學習(四)NetworkImageView+LruCache(源碼簡讀)圖片請求小例子

Volley學習(四)NetworkImageView+LruCache(源碼簡讀)圖片請求小例子

編輯:關於Android編程

今天來寫一個關於圖片請求的小例子,我們用NetworkImageView這個類來實現,這個類可以直接用在xml控件中,當作imageview,而且內部原理也是使用的ImageLoader,所以綜合性還是不錯的

效果圖如下:
這裡寫圖片描述

本例就沒有再去進行封裝代碼了,封裝代碼在前幾篇中有寫到,下面2張圖是
返回的json格式的數據,本例也就從中獲取picSmall、name即可<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxpbWcgYWx0PQ=="這裡寫圖片描述" src="/uploadfile/Collfiles/20160727/20160727104958502.png" title="\" />

下面就是onResponse返回的一串字符串(只不過這個字符串的格式是Json類型)

    StringRequest request = new StringRequest(Method.GET, url,
                new Listener() {
                    @Override
                    public void onResponse(String sb) {
                        Log.e("Safly", "onResponse-->>" + sb);
                        parseJsonFromServer(sb);
                        setAdapter();
                    }
            }, new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError arg0) {
                    }
                });

然後就開始解析,用JsonObject(當然也可以用JsonObject的另外寫法比如jsonObject.optInt的寫法,還可以用JsonReader等等)

    private void parseJsonFromServer(String sb) {
        datas = new ArrayList();
        JSONObject jsonObject;
        try {
            jsonObject = new JSONObject(sb.toString());
            JSONArray jsonArray = jsonObject
                    .getJSONArray("data");
            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject jsonData = jsonArray
                        .getJSONObject(i);
                DataBean newsBean = new DataBean();
                newsBean.setImageUrl(jsonData
                        .getString("picSmall"));
                newsBean.setTitle(jsonData.getString("name"));
                // 添加對象,組建集合
                datas.add(newsBean);
            }
            Log.i("Safly", "datas.size-->>"+datas.size());
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

最後就看adapter中的內容即可
我們在稍微看下NetworkImageView源碼類
這裡寫圖片描述

它裡面有2個方法是進行設置控件的默認圖片,以及下載失敗的提示圖片,結果這2個方法在Volley中都沒有內部調用,所以說我們可以在adapter中,進行預設置,我們之前看源碼得知,下載完畢圖片後,還會進行更新操作,下載失敗後,就會volley內部去進行操作

    /**
       * 接下來就是跟imageloader裡面的請求代碼思路一樣了
       */
        ImageContainer newContainer = mImageLoader.get(mUrl,
                new ImageListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        if (mErrorImageId != 0) {
                            setImageResource(mErrorImageId);
                        }
                    }

然後我們就可以利用如下的源碼進行設置了一些參數了,下邊是volley的代碼

   public void setImageUrl(String url, ImageLoader imageLoader) {
        mUrl = url;
        mImageLoader = imageLoader;
        // The URL has potentially changed. See if we need to load it.
        loadImageIfNecessary(false);
    }

對應我們代碼中的部分

 viewHolder.imageview_item.setImageUrl(url, VolleyTool.getInstance(context).getImageLoader()); 
  //私有構造方法  
    private VolleyTool(Context context) {  
        //創建請求隊列  
        queue = Volley.newRequestQueue(context);  
        //創建圖片加載器  
        imageLoader = new ImageLoader(queue, new LruImageCache());  
    }  
    //公共、靜態的方法  
    public static VolleyTool getInstance(Context context) {  
        if (instance == null) {  
            instance = new VolleyTool(context);  
        }  
        return instance;  
    }  

看看構造器中進行了哪些操作?初始化queue、ImageLoader
我們在看看對應volley中的ImageLoader的構造器部分如下:

    public interface ImageCache {
        public Bitmap getBitmap(String url);
        public void putBitmap(String url, Bitmap bitmap);
    }

    /**
     * Constructs a new ImageLoader.
     * @param queue The RequestQueue to use for making image requests.
     * @param imageCache The cache to use as an L1 cache.
     */
    public ImageLoader(RequestQueue queue, ImageCache imageCache) {
        mRequestQueue = queue;
        mCache = imageCache;
    }

很明顯源碼中ImageCache,只有getBitmap、putBitmap方法,而我們呢?用到了LruCache強緩存處理,以完善內存緩存的控制管理

那我們就來看看這個LruChche的源碼把如下:
首先看看構造器部分:

  /**
     * @param maxSize for caches that do not override {@link #sizeOf}, this is
     *     the maximum number of entries in the cache. For all other caches,
     *     this is the maximum sum of the sizes of the entries in this cache.
     */
    public LruCache(int maxSize) {
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        }
        this.maxSize = maxSize;
        this.map = new LinkedHashMap(0, 0.75f, true);
    }

如果maxSize<=0 就會跑異常,那麼這個參數是什麼意思呢?
我們看看百度的翻譯:這是高速緩存中的條目的最大數目。對於所有其他高速緩存,這是該緩存中的項的大小的最大和。
意思就是此緩存能緩存的最大值是多少

緩存肯定需要放東西把,我們看看put做了什麼相關處理的操作?

    public final V put(K key, V value) {
        if (key == null || value == null) {
            throw new NullPointerException("key == null || value == null");
        }

        V previous;
        synchronized (this) {
            putCount++;
            size += safeSizeOf(key, value);
            previous = map.put(key, value);
            if (previous != null) {
                size -= safeSizeOf(key, previous);
            }
        }

        if (previous != null) {
            entryRemoved(false, key, previous, value);
        }

        trimToSize(maxSize);
        return previous;
    }

大概意思就是:放進來一個就putCount++就累加進來數量,參數一看就知道啥意思了,那麼safeSizeOf這個是啥意思呢?我們去看看

    private int safeSizeOf(K key, V value) {
        int result = sizeOf(key, value);
        if (result < 0) {
            throw new IllegalStateException("Negative size: " + key + "=" + value);
        }
        return result;
    }
    protected int sizeOf(K key, V value) {
        return 1;
    }

針對到本例子就是請求的一個圖片的內存大小,請求一個就累加size += safeSizeOf(key, value);我們該問了,它對存在的還會累加麼?我們在回到put方法中,

if (previous != null) {
                size -= safeSizeOf(key, previous);
            }

這個意思是如果之前有緩存的話,就不再添加了,就在剪掉即可
最後看下put方法中的代碼
trimToSize(maxSize);
他的意思就是刪除最大的條目,直到剩余的條目總數或低於所請求的大小。百度翻譯的意思就是,容量超過就會刪除訪問少的條目

get方法也就相對簡單了,就是取出來就可。

所以我們的代碼在看的話,就不是那麼復雜了:

    /** 
     * 使用LRU回收算法的緩存類 
     */  
    class LruImageCache implements ImageCache {  

        // 緩存容器  
        private LruCache cache;  

        public LruImageCache() {  
            // 計算緩存的最值  
            int maxSize = (int) (Runtime.getRuntime().maxMemory() / 8);  
            //創建緩存對象實例  
            cache = new LruCache(maxSize) {  
                @Override  
                protected int sizeOf(String key, Bitmap value) {  
                    // 返回bitmap占用的內存大小  
                    return value.getRowBytes() * value.getHeight();  
                }  
            };  
        }  

        // 從緩存中取圖片對象  
        @Override  
        public Bitmap getBitmap(String url) {  
            return cache.get(url);  
        }  

        // 將圖片對象保存到緩存容器中  
        @Override  
        public void putBitmap(String url, Bitmap bitmap) {  
            cache.put(url, bitmap);  
        }  

    }  

另外注意一點就是在item布局中

   

需要android:scaleType=”fitXY”

我這個demo沒有出現圖片錯亂的現象,有的朋友說會有錯亂的現象,我做了一個實驗,初始化有網絡,然後就關掉網絡,進行滑動依然是沒有問題的如下:
這裡寫圖片描述

另外下載的圖片緩存到哪裡去了呢?如下
這裡寫圖片描述

以下就是代碼區別############################



    







       


    




SaflyApplication

package com.example.saflyimage;

import android.app.Application;

import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;


public class SaflyApplication extends Application {
    public static RequestQueue requestQueue;
    @Override
    public void onCreate() {
        super.onCreate();
        requestQueue = Volley.newRequestQueue(getApplicationContext());
    }
    public static RequestQueue getRequestQueue() {
        return requestQueue;
    }
}


DataBean

package com.example.saflyimage;

public class DataBean {
    private String imageUrl;

    private String title;

    public DataBean(String imageUrl, String title) {
        super();
        this.imageUrl = imageUrl;
        this.title = title;
    }

    public DataBean() {
        super();
        // TODO Auto-generated constructor stub
    }

    public String getImageUrl() {
        return imageUrl;
    }

    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }



}


MainActivity

package com.example.saflyimage;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ListView;

import com.android.volley.Request.Method;
import com.android.volley.Response;
import com.android.volley.Response.Listener;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;

public class MainActivity extends Activity {
    private List datas;

    private ListView mListView;
    private SaflyAdapter saflyAdapter; 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mListView = (ListView) findViewById(R.id.mListView);
        String url = "http://www.imooc.com/api/teacher?type=4&num=30";

        StringRequest request = new StringRequest(Method.GET, url,
                new Listener() {

                    @Override
                    public void onResponse(String sb) {
                        Log.e("Safly", "onResponse-->>" + sb);
                        parseJsonFromServer(sb);
                        setAdapter();
                    }

                }, new Response.ErrorListener() {

                    @Override
                    public void onErrorResponse(VolleyError arg0) {

                    }
                });
        // 設置標簽
        request.setTag("abcGet");
        SaflyApplication.getRequestQueue().add(request);
        SaflyApplication.getRequestQueue().start();
    }

    /**
     * 設置適配器
     */
    private void setAdapter() {
        saflyAdapter = new SaflyAdapter(MainActivity.this,datas);

        mListView.setAdapter(saflyAdapter);

    }
    /**
     * 解析json數據
     * @param sb
     */
    private void parseJsonFromServer(String sb) {
        datas = new ArrayList();
        JSONObject jsonObject;
        try {
            jsonObject = new JSONObject(sb.toString());
            JSONArray jsonArray = jsonObject
                    .getJSONArray("data");
            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject jsonData = jsonArray
                        .getJSONObject(i);
                DataBean newsBean = new DataBean();
                newsBean.setImageUrl(jsonData
                        .getString("picSmall"));
                newsBean.setTitle(jsonData.getString("name"));
                // 添加對象,組建集合
                datas.add(newsBean);
            }
            Log.i("Safly", "datas.size-->>"+datas.size());
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}


SaflyAdapter

package com.example.saflyimage;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.android.volley.toolbox.NetworkImageView;

public class SaflyAdapter extends BaseAdapter {

    private ArrayList dataBeans;
    private Context context;
    private LayoutInflater inflater;

    public SaflyAdapter(Context context, List datas) {
        super();
        this.dataBeans = (ArrayList) datas;
        this.context = context;
        this.inflater = LayoutInflater.from(context);
    }

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

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return dataBeans.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final ViewHolder viewHolder;
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.listview_item, parent,
                    false);
            viewHolder = new ViewHolder(convertView);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        DataBean dataBean = dataBeans.get(position);
        viewHolder.textview_item.setText(dataBean.getTitle());

        // 設置未加載默認圖片
        viewHolder.imageview_item.setDefaultImageResId(R.drawable.ic_launcher);
        // 設置加載異常的圖片
        viewHolder.imageview_item.setErrorImageResId(R.drawable.anzhuanghsibai);

        String url = dataBean.getImageUrl();
        viewHolder.imageview_item.setImageUrl(url,
                VolleyTool.getInstance(context).getImageLoader());

        return convertView;
    }

    class ViewHolder {
        NetworkImageView imageview_item;
        TextView textview_item;

        public ViewHolder(View view) {
            super();
            this.imageview_item = (NetworkImageView) view
                    .findViewById(R.id.imageview_item);
            this.textview_item = (TextView) view
                    .findViewById(R.id.textview_item);
        }

    }

}


VolleyTool

package com.example.saflyimage;  
import android.content.Context;  
import android.graphics.Bitmap;  
import android.support.v4.util.LruCache;  
import com.android.volley.RequestQueue;  
import com.android.volley.toolbox.ImageLoader;  
import com.android.volley.toolbox.ImageLoader.ImageCache;  
import com.android.volley.toolbox.Volley;  

public class VolleyTool {  
    //初始化請求隊列、圖片加載器  
    private RequestQueue queue;  
    private ImageLoader imageLoader;  

    //私有靜態實例  
    private static VolleyTool instance;  
    //私有構造方法  
    private VolleyTool(Context context) {  
        //創建請求隊列  
        queue = Volley.newRequestQueue(context);  
        //創建圖片加載器  
        imageLoader = new ImageLoader(queue, new LruImageCache());  
    }  
    //公共、靜態的方法  
    public static VolleyTool getInstance(Context context) {  
        if (instance == null) {  
            instance = new VolleyTool(context);  
        }  
        return instance;  
    }  

    //得到請求隊列  
    public RequestQueue getQueue() {  
        return queue;  
    }  
    //得到圖片加載器  
    public ImageLoader getImageLoader() {  
        return imageLoader;  
    }  

    /** 
     * 使用LRU回收算法的緩存類 
     */  
    class LruImageCache implements ImageCache {  

        // 緩存容器  
        private LruCache cache;  

        public LruImageCache() {  
            // 計算緩存的最值  
            int maxSize = (int) (Runtime.getRuntime().maxMemory() / 8);  
            //創建緩存對象實例  
            cache = new LruCache(maxSize) {  
                @Override  
                protected int sizeOf(String key, Bitmap value) {  
                    // 返回bitmap占用的內存大小  
                    return value.getRowBytes() * value.getHeight();  
                }  
            };  
        }  

        // 從緩存中取圖片對象  
        @Override  
        public Bitmap getBitmap(String url) {  
            return cache.get(url);  
        }  

        // 將圖片對象保存到緩存容器中  
        @Override  
        public void putBitmap(String url, Bitmap bitmap) {  
            cache.put(url, bitmap);  
        }  

    }  
}  
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved