1. 程式人生 > >在Android Studio上使用GSON+VOLLEY,秒處理網路資料成集合。感受框架的力量。搭配RecyclerView和SwipeRefreshLayout,實現底端載入更多,下拉重新整理。

在Android Studio上使用GSON+VOLLEY,秒處理網路資料成集合。感受框架的力量。搭配RecyclerView和SwipeRefreshLayout,實現底端載入更多,下拉重新整理。

【致謝,引用,宣告,前言】

關於GSON和VOLLEY,我百度了很多資料,個人感覺有兩篇部落格介紹的特別好,附上鍊接咯:

  GSON: http://blog.csdn.net/lk_blog/article/details/7685169 

VOLLEY:http://blog.csdn.net/guolin_blog/article/details/17482165 .

使用的資料來源url是根據徐大神在慕課網的視訊裡提到的url,不知道能不能在這裡發,就不單獨發了,反正會在程式碼出現的。

關於在Android Studio中匯入jar包,貌似方法有很多,我匯入VOLLEY和GSON是採用複製到lib目錄下,然後右鍵->As a Library,選中自己的Module:

如圖 (源自網路)


======================================================

【廢話】

我這篇比較基礎和入門,主要是融合了GSON VOLLEY搭配V7 V4 包裡的RecyclerView和SwipeRefreshLayout,做一個簡單的DEMO。實現載入網路資料,並顯示。利用兩個新控制元件做一個ListVIew的上下拉重新整理的效果。

後續會不斷的完善!歡迎各位提意見和BUG。

為什麼要用Android Studio,就不用說了吧,好吧 我說一下,因為我最近在換工作,70%的公司都要求使用Android Stuido。不過其實AS用習慣了還是很爽的,我現在都不想在Eclipse上碼程式碼了。

效果圖:

======================================================

【構建實體類DataBean.java】

以前我載入網路資料一般會用到HttpUrlConnection,然後根據返回的InputStream,讀取並處理成一串String資料(就是返回的json資料)。

然後再將這串String解析成JSONObject,再根據json的格式不斷的解析JSONArray...JSONObject...,最終得到我們的目標資料集合List<DataBean> mDatas。

經常一個粗心就哪裡寫錯了,而且程式碼重複量實在太大。利用GSON和VOLLEY,我只想說一句,秒     

   處理。

直接看程式碼:

首先是根據url返回的json,構建一個實體類: 我們這裡返回的json格式為:

{
    "status": 1,
    "data": [
        {
            "id": 1,
            "name": "Tony老師聊shell——環境變數配置檔案",
            "picSmall": "http://img.mukewang.com/55237dcc0001128c06000338-300-170.jpg",
            "picBig": "http://img.mukewang.com/55237dcc0001128c06000338.jpg",
            "description": "為你帶來shell中的環境變數配置檔案",
            "learner": 12312
        },
        {
            "id": 2,
            "name": "數學知識在CSS動畫中的應用",
            "picSmall": "http://img.mukewang.com/55249cf30001ae8a06000338-300-170.jpg",
            "picBig": "http://img.mukewang.com/55249cf30001ae8a06000338.jpg",
            "description": "數學知識與CSS結合實現酷炫效果",
            "learner": 45625
        },

。。。。。。。。。

我們根據"data"數組裡的資料格式,構建DataBean.java: (這個是跟GSON解析相關的)

package com.mcxtzhang.demo.windrecyclerdemo;
/**
 * Created by zhangxutong on 2015/12/28.
 */
public class DataBean {
    private String name;
    private String picSmall;
    public String getName() {
        return name;
}

    public String getPicSmall() {
        return picSmall;
}

    public void setName(String name) {
        this.name = name;
}

    public void setPicSmall(String picSmall) {
        this.picSmall = picSmall;
}

  /*  @Override
    public String toString() {
        return "DataBean{" +
                "name='" + name + '\'' +
                ", picSmall='" + picSmall + '\'' +
                '}';
    }*/
}
這裡說一個我自己當小白鼠驗證出來的東西,經過測試,使用GSON,toString() 不是一定要寫的,然後也不一定要寫出json資料裡的所有欄位,只要根據需要就可以了,例如:我這裡需要name和picSmall,則我的DataBean只有兩個屬性。

欄位(屬性)的命名,我是跟json資料裡的欄位保持一致的。OK,實體類構建完畢,繼續。

======================================================

【使用VOLLEY】

下面就是使用VOLLEY了,請新增網路訪問許可權!請新增網路訪問許可權!請新增網路訪問許可權! 重要的事說三遍,有的同學沒新增,不停的報錯/執行結果不正確,

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

然後,根據郭神blog所述,VOLLEY使用三部曲:

1. 建立一個RequestQueue物件。

//Volley begin
private RequestQueue mQueue;
private static final String url = "http://www.imooc.com/api/teacher?type=4&num=30";
//Volley end



2. 建立一個JsonRequest物件。 (摘自郭神blog,重點標紅:類似於StringRequest,JsonRequest也是繼承自Request類的,不過由於JsonRequest是一個抽象類,因此我們無法直接建立它的例項,那麼只能從它的子類入手了。JsonRequest有兩個直接的子類,JsonObjectRequest和JsonArrayRequest,從名字上你應該能就看出它們的區別了吧?一個是用於請求一段JSON資料的,一個是用於請求一段JSON陣列的。)

本例url返回的是JSONObject,所以用JsonObjectRequest物件。

//Volley begin
//GET 方式的http
/*StringRequest stringRequest = new StringRequest(url,
        new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                Log.d(TAG, response);
            }
        }, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        Log.e(TAG, error.getMessage(), error);
    }
});
mQueue.add(stringRequest);*/
//json 四個引數分別是:url, JSONObject物件這裡為null,一個請求成功的Listener,和一個請求失敗的Listener:
//
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, new Response.Listener<JSONObject>() {
    @Override
public void onResponse(JSONObject jsonObject) {
       // Log.i(TAG,jsonObject.toString());
if(null!=jsonObject){
            try {
                //傳入的"data" 是根據json返回字串得來的
JSONArray jsonArray = jsonObject.getJSONArray("data");
//上一句程式碼可能報錯,確認不報錯再建立下面的物件
                //註釋掉的是 原本不使用GSON的解析方法
                /*mDatas = new ArrayList<DataBean>();
                for (int i=0;i<jsonArray.length();i++){
                    JSONObject jsonData = jsonArray.getJSONObject(i);
                    DataBean data = new DataBean();
                    data.setName(jsonData .getString("name"));
                    data.setPicSmall(jsonData.getString("picSmall"));
                    mDatas.add(data);
                }*/
                //使用GSON載入 begin
String dataString = jsonArray.toString();
Gson gson = new Gson();
mDatas = gson.fromJson(dataString, new TypeToken<List<DataBean>>() {}.getType());
//使用GSON載入 end
                //資料載入完後 再載入介面卡
init();
} catch (JSONException e) {
                e.printStackTrace();
}
        }
    }
}, new Response.ErrorListener() {
    @Override
public void onErrorResponse(VolleyError volleyError) {
        Log.i(TAG,volleyError.getMessage(),volleyError);
}
});



3. 將JsonRequest物件新增到RequestQueue裡面。
mQueue.add(jsonObjectRequest);
//Volley end

忽略init();裡面是介面卡的設定和下拉重新整理的程式碼。這裡不用care。

======================================================

【GSON】:

上述 步驟 2,裡已經包括GSON的使用程式碼:

這裡是將json資料轉化為帶泛型的List 集合。

private List<DataBean> mDatas;

核心就是三句話:

得到json字串,

String dataString = jsonArray.toString();

new一個Gson物件,

Gson gson = new Gson();

利用gson.fromJson(json字串,new TypeToken<List<DataBean>>() {}.getType()),返回值就是傳入到TypeToken裡的集合型別

mDatas = gson.fromJson(dataString, new TypeToken<List<DataBean>>() {}.getType());
程式碼如下:
new Response.Listener<JSONObject>() {
    @Override
public void onResponse(JSONObject jsonObject) {if(null!=jsonObject){
            try {
                //傳入的"data" 是根據json返回字串得來的
JSONArray jsonArray = jsonObject.getJSONArray("data");
//上一句程式碼可能報錯,確認不報錯再建立下面的物件                //使用GSON載入 begin
String dataString = jsonArray.toString();
Gson gson = new Gson();
mDatas = gson.fromJson(dataString, new TypeToken<List<DataBean>>() {}.getType());
//使用GSON載入 end
                //資料載入完後 再載入介面卡
init();
} catch (JSONException e) {
                e.printStackTrace();
}
        }
    }
}

======================================================

至此,我們已經完成資料來源的get!並且存放在mDatas裡了。我們可以盡情的折騰這些資料了~未完待續

下面,大家就和我一起愉快的體驗一把RecyclerView和SwipeRefreshLayout,感受新控制元件的魅力,其實我個人感覺RecyclerView最爽的還是瀑布流的實現,很簡單,還有就是RecyclerView的增刪動畫,也是槓槓的,並且只要一行程式碼。廢話不多扯,先說RecyclerView。

======================================================

【匯入RecyclerView和SwipeRefreshLayout】:

關於在Android Studio中使用support包 就很簡單了,(我在Eclipse裡就被虐過很多次)

選中Project Structure:


選擇自己的Modules,然後在右邊的選項卡里點選Dependences:


點選右邊的綠色+號:


好了,在這裡愉快的搜尋RecyclerView和SwipeRefreshLayout,並且把他們都加入進來就好了。

======================================================

【RecyclerView】:先看一下佈局檔案:RecyclerView和ListView沒區別:而SwipeRefreshLayout是用ViewGroup實現的,所以可以包裹其他的控制元件,用它包裹住RecyclerView即可,沒有啥好說的。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.mcxtzhang.demo.windrecyclerdemo.MainActivity">
    <android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipelayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<!--        <com.mcxtzhang.demo.windrecyclerdemo.RefreshView
                    android:id="@+id/recyclerview"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />-->
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
    </android.support.v4.widget.SwipeRefreshLayout>
</RelativeLayout>
private RecyclerView mRecyclerView;
mRecyclerView = (RecyclerView)findViewById(R.id.recyclerview);
//如果item的內容不改變view佈局大小,那使用這個設定可以提高RecyclerView的效率
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(MainActivity.this,LinearLayoutManager.VERTICAL,false);
mRecyclerView.setLayoutManager(mLayoutManager);
這裡要說的就是LayoutManager了,RecyclerView之所以能實現這麼多的效果(ListVIew GridView 瀑布流),主要是由於它解耦的很好,只要改變LayoutManager或者Adapter裡的一些程式碼就可以實現很多改變。

我們這裡用的是最簡單的LinearLayoutManager,傳入的三個引數分別是 context,佈局的方向,和是否將資料反向。      

若使用LinearLayoutManager.HORIZONTAL ,則是水平方向的ListView,
若第三個引數為true,則會反向顯示整個mDatas裡的資料。

大家一試便知效果。

下面再給RecyclerView設定一個介面卡Adapter ,便可以讓它顯示資料了。

======================================================

【Adapter】:

程式碼裡有詳細註釋:

/**
 * RecyclerView 的Adapter強制我們使用ViewHolder模式,對於我這種熟讀徐老師《文藝Adapter》的青年來說,也是很輕鬆就接受了,看來Google也是強制我們每個程式設計師都成為一個文藝的青年。
 * 這裡回想一下以前ListView的BaseAdapter,在getView()裡還要判斷convertView是否為空來判斷是否是複用的,通過setTag,getTag放入ViewHolder物件。
 * 現在不用了,RecyclerView.Adapter<DataViewHolder>,將getView方法分解成兩個過程,
 * 一個是public DataViewHolder onCreateViewHolder(ViewGroup parent, int viewType),它專注於ViewHolder的建立。
 * 另一個是 public void onBindViewHolder(final DataViewHolder holder, int position),它專注於ViewHolder的繫結,資料的顯示,通過LOG檢視,該方法時在每次顯示item都被呼叫的(廢話,但是我比較喜歡驗證:))
 */

/**
 * ViewHolder的建立很簡單,
 * 一:開啟item的佈局layout,裡面有啥控制元件,就在這裡寫啥。
 * (所以如果用到Volley的NetworkImageView,那這裡就要用它替換ImageView,稍後會用到。)
 * 二:在構造方法裡,完成Item View 和ViewHolder裡屬性的繫結,
 * 其中findViewById裡的id值 就是item的佈局layout裡的值(好像太囉嗦了)
 *
 */

package com.mcxtzhang.demo.windrecyclerdemo;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import java.util.List;
/**
 * RecyclerView 的Adapter強制我們使用ViewHolder模式,對於我這種熟讀徐老師《文藝Adapter》的青年來說,也是很輕鬆就接受了,看來Google也是強制我們每個程式設計師都成為一個文藝的青年。
 * 這裡回想一下以前ListView的BaseAdapter,在getView()裡還要判斷convertView是否為空來判斷是否是複用的,通過setTag,getTag放入ViewHolder物件。
 * 現在不用了,RecyclerView.Adapter<DataViewHolder>,將getView方法分解成兩個過程,
 * 一個是public DataViewHolder onCreateViewHolder(ViewGroup parent, int viewType),它專注於ViewHolder的建立。
 * 另一個是 public void onBindViewHolder(final DataViewHolder holder, int position),它專注於ViewHolder的繫結,資料的顯示,通過LOG檢視,該方法時在每次顯示item都被呼叫的(廢話,但是我比較喜歡驗證:))
 */
public class DataAdapter extends RecyclerView.Adapter<DataViewHolder> {
    private List<DataBean> mDatas;
    private LayoutInflater mInflater;
//利用Volley 載入網路圖片用到
private RequestQueue mQueue;
//載入網路圖片2 利用ImageLoader    begin  //有軟快取 沒有硬快取
ImageLoader mImageLoader;
//載入網路圖片2 利用ImageLoader    end  //有軟快取 沒有硬快取
    //載入網路圖片使用NetworkImageView  //有軟快取 沒有硬快取  begin
private ImageLoader.ImageCache mImageCache;
//載入網路圖片使用NetworkImageView  //有軟快取 沒有硬快取  end
public DataAdapter(Context context, List<DataBean> mDatas, RequestQueue mQueue) {
        this.mDatas = mDatas;
        this.mInflater = LayoutInflater.from(context);
        this.mQueue = mQueue;
//載入網路圖片使用NetworkImageView   begin
mImageCache = new WindImageCache();
//載入網路圖片使用NetworkImageView   end
        //載入網路圖片2 利用ImageLoader    begin  //有軟快取 沒有硬快取
        //構建ImageLoader,傳入RequestQueue和ImageCache物件
mImageLoader = new ImageLoader(mQueue, mImageCache);
//載入網路圖片2 利用ImageLoader    end  //有軟快取 沒有硬快取
}

    /**
     * @param parent   其實就是RecyclerView
     * @param viewType 據我看到,模仿ListView底部載入更多會用到。
     * @return 建立的新的ViewHolder物件
     */
@Override
public DataViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new DataViewHolder(mInflater.inflate(R.layout.item, parent, false));
}

    /**
     * @param holder   複用的ViewHolder物件
     * @param position 當前的位置(有時候為了動畫效果,只調用notifyItemInserted(),notifyItemRemoved();
     *                 在增刪資料沒有呼叫notifyDataSetChanged();方法的時候,是不準的,不如ViewHolder.getLayoutPosition())
     *                 這裡沒有增刪資料來源,所以可以放心使用
     */
@Override
public void onBindViewHolder(final DataViewHolder holder, int position) {
        holder.textView.setText(mDatas.get(position).getName());
//載入網路圖片 利用ImageRequest    begin  //有雙快取
        //第一個引數就是圖片的URL地址,第二個引數是圖片請求成功的回撥,
        // 第三第四個引數分別用於指定允許圖片最大的寬度和高度,如果指定的網路圖片的寬度或高度大於這裡的最大值,則會對圖片進行壓縮,指定成0的話就表示不管圖片有多大,都不會進行壓縮。
        // 第五個引數用於指定圖片的顏色屬性,Bitmap.Config下的幾個常量都可以在這裡使用,其中ARGB_8888可以展示最好的顏色屬性,每個圖片畫素佔據4個位元組的大小,而RGB_565則表示每個圖片畫素佔據2個位元組大小。
        // 第六個引數是圖片請求失敗的回撥,
        //摘自郭神部落格
        /*ImageRequest imageRequest = new ImageRequest(mDatas.get(position).picSmall, new Response.Listener<Bitmap>() {
            @Override
            public void onResponse(Bitmap bitmap) {
                holder.imageView.setImageBitmap(bitmap);
            }
        }, 0, 0, Bitmap.Config.ARGB_8888, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                //請求失敗 設定預設圖片
                holder.imageView.setImageResource(R.mipmap.ic_launcher);
            }
        });
        mQueue.add(imageRequest);*/
        //載入網路圖片 利用ImageRequest    end  //有雙快取
        //載入網路圖片2 利用ImageLoader   begin
        //內部也是使用ImageRequest實現的,它可以過濾重複的連結,更高效。
        //ImageListener :通過呼叫ImageLoader的getImageListener()方法能夠獲取到一個ImageListener物件,getImageListener()方法接收三個引數
        // 第一個引數指定用於顯示圖片的ImageView控制元件,第二個引數指定載入圖片的過程中顯示的圖片,第三個引數指定載入圖片失敗的情況下顯示的圖片。
/*        ImageLoader.ImageListener imageListener = ImageLoader.getImageListener(holder.imageView, R.mipmap.ic_loading, R.mipmap.ic_loaderror);
        //呼叫ImageLoader的get()方法來載入圖片
        //兩個引數,第一個引數就是圖片的URL地址,第二個引數則是ImageListener物件,第三、四個引數是指定圖片允許的最大寬度和高度。
        mImageLoader.get(mDatas.get(position).getPicSmall(), imageListener,0,0);*/
        //載入網路圖片2 利用ImageLoader   end
        //載入網路圖片使用NetworkImageView   begin
        //可以呼叫它的setDefaultImageResId()方法、setErrorImageResId()方法和setImageUrl()方法來分別設定載入中顯示的圖片,載入失敗時顯示的圖片,以及目標圖片的URL地址
        //setImageUrl()方法接收兩個引數,第一個引數用於指定圖片的URL地址,第二個引數則是前面建立好的ImageLoader物件。
        //ImageLoader imageLoader = new ImageLoader(mQueue,mImageCache);
/*        NetworkImageView networkImageView = holder.imageView;
        networkImageView.setDefaultImageResId(R.mipmap.ic_loading);
        networkImageView.setErrorImageResId(R.mipmap.ic_loaderror);
        networkImageView.setImageUrl(mDatas.get(position).getPicSmall(),mImageLoader);*/
        //載入網路圖片使用NetworkImageView   end
}

    /**
     * @return item的個數,最好加個為空判斷。
     */
@Override
public int getItemCount() {
        return mDatas != null ? mDatas.size() : 0;
}
}

/**
 * ViewHolder的建立很簡單,
 * 一:開啟item的佈局layout,裡面有啥控制元件,就在這裡寫啥。
 * (所以如果用到Volley的NetworkImageView,那這裡就要用它替換ImageView,稍後會用到。)
 * 二:在構造方法裡,完成Item View 和ViewHolder裡屬性的繫結,
 * 其中findViewById裡的id值 就是item的佈局layout裡的值(好像太囉嗦了)
 */
class DataViewHolder extends RecyclerView.ViewHolder {
    TextView textView;
ImageView imageView;
//載入網路圖片使用NetworkImageView   begin
    //NetworkImageView imageView;
    //載入網路圖片使用NetworkImageView   end
public DataViewHolder(View itemView) {
        super(itemView);
//完成Item View 和ViewHolder裡屬性的繫結,begin
textView = (TextView) itemView.findViewById(R.id.item_name);
imageView = (ImageView) itemView.findViewById(R.id.item_image);
//載入網路圖片使用NetworkImageView   begin
        //imageView = (NetworkImageView) itemView.findViewById(R.id.item_image);
        //載入網路圖片使用NetworkImageView   end
        //完成Item View 和ViewHolder裡屬性的繫結,end
}
}

======================================================

【item的佈局檔案】:item.xml: 

如果使用Volley裡的NetworkImageView,則替換NetworkImageView,註釋ImageVIew。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="70dp"
android:orientation="horizontal"
android:background="#44ff0000"
android:layout_margin="5dp">
    <TextView
android:id="@+id/item_name"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:textSize="16sp"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
    <ImageView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:id="@+id/item_image"
android:layout_gravity="right"
android:src="@mipmap/ic_launcher"/>
<!-- //載入網路圖片使用NetworkImageView   begin-->
<!--    <com.android.volley.toolbox.NetworkImageView
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:id="@+id/item_image"
        android:layout_gravity="right"
        android:src="@mipmap/ic_launcher"/>-->
    <!-- //載入網路圖片使用NetworkImageView   end-->
</LinearLayout>

======================================================

【繫結Adapter和RecyclerVIew】:和ListVIew差不多。

mAdapter = new DataAdapter(MainActivity.this,mDatas,mQueue);
mRecyclerView.setAdapter(mAdapter);

======================================================

【WindImageCache】:

一個簡單的LruCache,這裡可以擴充套件,後續我會寫成雙快取。

package com.mcxtzhang.demo.windrecyclerdemo;
import android.graphics.Bitmap;
import android.util.LruCache;
import com.android.volley.toolbox.ImageLoader;
/**
 * Created by zhangxutong on 2015/12/28.
 */
public class WindImageCache implements ImageLoader.ImageCache {
    private LruCache<String,Bitmap> mCache;
    public WindImageCache() {
        mCache = new LruCache<String,Bitmap>((int) (Runtime.getRuntime().maxMemory()/10)){
            @Override
protected int sizeOf(String key, Bitmap value) {
                return value.getByteCount();
}
        };
}

    @Override
public Bitmap getBitmap(String s) {
        return mCache.get(s);
}

    @Override
public void putBitmap(String s, Bitmap bitmap) {
        if(null == getBitmap(s)){
            mCache.put(s,bitmap);
}
    }
}

======================================================

【關於Volley載入網路圖片】:

在Adapter的小節中,已經用程式碼寫了三種使用Volley載入圖片的方式:ImageRequest,ImageLoader,NetworkImageView,據說是後兩種比較好,效能高還可以過濾重複url請求。但是第一種ImageRequest已經替我們實現了雙快取,後兩種快取機制要自己實現,我們這裡使用的是上一節自定義的LruCache。

【ImageRequest】:

//載入網路圖片 利用ImageRequest    begin  //有雙快取
//第一個引數就是圖片的URL地址,第二個引數是圖片請求成功的回撥,
// 第三第四個引數分別用於指定允許圖片最大的寬度和高度,如果指定的網路圖片的寬度或高度大於這裡的最大值,則會對圖片進行壓縮,指定成0的話就表示不管圖片有多大,都不會進行壓縮。
// 第五個引數用於指定圖片的顏色屬性,Bitmap.Config下的幾個常量都可以在這裡使用,其中ARGB_8888可以展示最好的顏色屬性,每個圖片畫素佔據4個位元組的大小,而RGB_565則表示每個圖片畫素佔據2個位元組大小。
// 第六個引數是圖片請求失敗的回撥,
//摘自郭神部落格
ImageRequest imageRequest = new ImageRequest(mDatas.get(position).picSmall, new Response.Listener<Bitmap>() {
    @Override
    public void onResponse(Bitmap bitmap) {
        holder.imageView.setImageBitmap(bitmap);
    }
}, 0, 0, Bitmap.Config.ARGB_8888, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError volleyError) {
        //請求失敗 設定預設圖片
        holder.imageView.setImageResource(R.mipmap.ic_launcher);
    }
});
mQueue.add(imageRequest);
//載入網路圖片 利用ImageRequest    end  //有雙快取

【ImageLoader】:

內部也是使用ImageRequest實現的,它可以過濾重複的連結,更高效。

1. 建立一個RequestQueue物件。
2. 建立一個ImageLoader物件。
3. 獲取一個ImageListener物件。
4. 呼叫ImageLoader的get()方法載入網路上的圖片。

//載入網路圖片 利用ImageLoader    begin  //有軟快取 沒有硬快取
ImageLoader mImageLoader;
//載入網路圖片 利用ImageLoader    end  //有軟快取 沒有硬快取
//載入網路圖片2 利用ImageLoader    begin  //有軟快取 沒有硬快取
//構建ImageLoader,傳入RequestQueue和ImageCache物件
mImageLoader = new ImageLoader(mQueue, mImageCache);
//載入網路圖片2 利用ImageLoader    end  //有軟快取 沒有硬快取
//載入網路圖片2 利用ImageLoader   begin
//內部也是使用ImageRequest實現的,它可以過濾重複的連結,更高效。
//ImageListener :通過呼叫ImageLoader的getImageListener()方法能夠獲取到一個ImageListener物件,getImageListener()方法接收三個引數
// 第一個引數指定用於顯示圖片的ImageView控制元件,第二個引數指定載入圖片的過程中顯示的圖片,第三個引數指定載入圖片失敗的情況下顯示的圖片。
ImageLoader.ImageListener imageListener = ImageLoader.getImageListener(holder.imageView, R.mipmap.ic_loading, R.mipmap.ic_loaderror);
//呼叫ImageLoader的get()方法來載入圖片
//兩個引數,第一個引數就是圖片的URL地址,第二個引數則是ImageListener物件,第三、四個引數是指定圖片允許的最大寬度和高度。
mImageLoader.get(mDatas.get(position).getPicSmall(), imageListener,0,0);
//載入網路圖片2 利用ImageLoader   end

【NetworkImageView】:

1. 建立一個RequestQueue物件。(同上)
2. 建立一個ImageLoader物件。(同上)
3. 在佈局檔案中新增一個NetworkImageView控制元件。(見item.xml佈局檔案)

<com.android.volley.toolbox.NetworkImageView
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:id="@+id/item_image"
        android:layout_gravity="right"
        android:src="@mipmap/ic_launcher"/>

4. 在程式碼中獲取該控制元件的例項。(ViewHolder裡)
//載入網路圖片使用NetworkImageView   begin
//NetworkImageView imageView;
//載入網路圖片使用NetworkImageView   end
//載入網路圖片使用NetworkImageView   begin
//imageView = (NetworkImageView) itemView.findViewById(R.id.item_image);
//載入網路圖片使用NetworkImageView   end

5. 設定要載入的圖片地址。(Adapter 的onBindViewHolder裡)

//載入網路圖片使用NetworkImageView   begin
//可以呼叫它的setDefaultImageResId()方法、setErrorImageResId()方法和setImageUrl()方法來分別設定載入中顯示的圖片,載入失敗時顯示的圖片,以及目標圖片的URL地址
//setImageUrl()方法接收兩個引數,第一個引數用於指定圖片的URL地址,第二個引數則是前面建立好的ImageLoader物件。
//ImageLoader imageLoader = new ImageLoader(mQueue,mImageCache);
NetworkImageView networkImageView = holder.imageView;
networkImageView.setDefaultImageResId(R.mipmap.ic_loading);
networkImageView.setErrorImageResId(R.mipmap.ic_loaderror);
networkImageView.setImageUrl(mDatas.get(position).getPicSmall(),mImageLoader);
//載入網路圖片使用NetworkImageView   end

======================================================

【三種載入圖片方式的區別】:

ImageRequest:雙快取,但是不會過濾重複連線。

ImageLoader:緩衝策略自定義,會過濾重複連結。

NetworkImageView:快取策略自定義,由於是控制元件,所以會根據自身控制元件大小,自動對載入的圖片進行壓縮,不會浪費記憶體(載入到記憶體中的圖片和顯示的是一樣的大小),不用手動控制這個壓縮圖片的過程。這是最好的一點。如果不想壓縮圖片,則將layout_width和layout_height都設定成wrap_content即可。

======================================================

【SwipeRefreshLayout】:

我掌握的也不多,很簡單,包裹在RecyclerView外面後,向下拉動就會有進度條滾動的效果了。如圖:


控制元件的初始化和其他一樣,

private SwipeRefreshLayout mSwipeRefreshLayout;
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipelayout);

可以設定進度條的顏色,最多可以設定四個顏色:

//設定 進度條的顏色變化,最多可以設定4種顏色
mSwipeRefreshLayout.setColorSchemeColors(Color.parseColor("#ff00ff"),Color.parseColor("#ff0f0f"),Color.parseColor("#0000ff"),Color.parseColor("#000000"));

設定進度條距離頂部的間距:

//setProgressViewOffset(boolean scale, int start, int end) 調整進度條距離螢幕頂部的距離
mSwipeRefreshLayout.setProgressViewOffset(false, 0, (int) TypedValue
        .applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, getResources()
                .getDisplayMetrics()));
//設定監聽器,這裡就簡單的每當重新整理(圓形進度條出現)時,延遲5秒將重新整理狀態改為false,即重新整理結束。進度條也會消失
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
    @Override
public void onRefresh() {
        Log.i(TAG," onRefresh() now:"+mSwipeRefreshLayout.isRefreshing());
mSwipeRefreshLayout.postDelayed(new Runnable() {
            @Override
public void run() {
                mSwipeRefreshLayout.setRefreshing(false);
}
        },5000);
}
});
以上已經實現的 該控制元件自帶的,下拉重新整理功能。

【實現下滑到底端載入更多】:

這裡也是通過監聽OnScrollListener實現,在onScrooled()方法裡判斷,如果向下滑並且最後一個item可見,則執行載入更多操作。

//資料集的長度
private int mTotalCount;
//當前可見的最後一個item的id(最大值為資料集長度-1)
private int mLastVisiblePos;

/**
 *  下滑到底部 載入更多,也是通過重寫OnScroll