【致谢,引用,声明,前言】
关于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
经常一个粗心就哪里写错了,而且代码重复量实在太大。利用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了,请添加网络访问权限!请添加网络访问权限!请添加网络访问权限! 重要的事说三遍,有的同学没添加,不停的报错/运行结果不正确,
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() { @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() { @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 (); for (int i=0;iJSONObject 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 >() {}.getType()); //使用GSON加载 end //数据加载完后 再加载适配器 init(); } catch (JSONException e) { e.printStackTrace(); } } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { Log.i(TAG,volleyError.getMessage(),volleyError); } });
mQueue.add(jsonObjectRequest);
//Volley end
忽略init();里面是适配器的设置和下拉刷新的代码。这里不用care。
======================================================
【GSON】:
上述 步骤 2,里已经包括GSON的使用代码:
这里是将json数据转化为带泛型的List 集合。
private ListmDatas;
核心就是三句话:
得到json字符串,
String dataString = jsonArray.toString();
new一个Gson对象,
Gson gson = new Gson();
利用gson.fromJson(json字符串,new TypeToken>() {}.getType()),返回值就是传入到TypeToken里的集合类型
mDatas = gson.fromJson(dataString, new TypeToken>() {}.getType());
代码如下:
new Response.Listener() { @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 >() {}.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"?>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:id="@+id/swipelayout" android:layout_width="wrap_content" android:layout_height="wrap_content"> android:id="@+id/recyclerview" android:layout_width="match_parent" android:layout_height="match_parent" />
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
* 一个是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,将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 { private List 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 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 () { @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"?>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"> 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" /> 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"/>
======================================================
【绑定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,Bitmap> mCache; public WindImageCache() { mCache = new LruCache ,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() { @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布局文件)
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 //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;
/** * 下滑到底部 加载更多,也是通过重写OnScrollListener实现 * 在onScrolled()方法里判断,如果已经可见的最后一个item,并且是向下滑(dy>0),且当前没有在刷新,则执行刷新操作。 */ mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } /** * @param recyclerView * @param dx 下滑为负 上滑为正 * @param dy */ @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); //数据集的长度 mTotalCount = mAdapter.getItemCount(); // (类似id,所以最大值也是数据集长度-1) mLastVisiblePos = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition(); Log.i(TAG,"getItemCount();"+ mTotalCount+ ".findLastVisibleItemPosition();"+ mLastVisiblePos +", dy :"+dy ); //下拉到底端: 刷新 dy :纵坐标的位移 (上一个点 - 现在的点, 所以下滑为负,上滑为正) if(mLastVisiblePos + 1 ==mTotalCount && !mSwipeRefreshLayout.isRefreshing() && dy>0){ //手动设置当前刷新状态为true mSwipeRefreshLayout.setRefreshing(true); //模拟取消: //实际中这里要替换为加载更多数据,稍后完善 mSwipeRefreshLayout.postDelayed(new Runnable() { @Override public void run() { mSwipeRefreshLayout.setRefreshing(false); } },5000); } } });
========================================================================================================================
处女座写到这里就算完结了,算是RecyclerView+SwipreRefreshLayout(一)吧。
后续会更新!计划加入
Toolbar
点击呈现大图,大图可缩放 移动。
把刷新和加载更多的数据功能完善(目前只有UI和模拟操作)。
实现ImageLoader和NetworkImageView 的二级缓存。
瀑布流
原生ListView。
【源代码】:
http://download.csdn.net/detail/zxt0601/9382618