在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 + '\'' + '}'; }*/ }這裡說一個我自己
欄位(屬性)的命名,我是跟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