Android代码优化----PullToRefresh+universal-image-loader实现从网络获取数据并刷新

 

 【声明】 

欢迎转载,但请保留文章原始出处→_→ 

生命壹号:http://www.cnblogs.com/smyhvae/

文章来源:http://www.cnblogs.com/smyhvae/p/4488049.html

联系方式:[email protected] 

 效果图:(gif图太大了,有点卡,建议将图片保存到本地查看或者直接本文末尾的源码查看gif图)

Android代码优化----PullToRefresh+universal-image-loader实现从网络获取数据并刷新

加载网络图片我们用universal-image-loader,然后实现ListView的上拉下拉刷新我们用PullToRefresh。下面开始写代码。

整个代码的工程文件结构如下:

Android代码优化----PullToRefresh+universal-image-loader实现从网络获取数据并刷新

  • libs文件夹下是需要用到的一些库和开源框架(这里有个picasso框架,是用来加载网络图片的,暂时不用哈,留着以后备用,现在这个项目用的是universal-image-loader)。
  • adapter文件夹下是listView的自定义适配器(本文的重点)
  • entities是从网络获取到json数据,解析之后,用来存放这些数据的实体
  • utils文件夹下是url的常量
  • MainActivity.java是主程序的入口
  • MyApplication才是真正的app的第一个入口,这个不多解释,都懂得。

一、开始写代码:

(1)activity_main.xml(MainActvity的布局)

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

 2     xmlns:tools="http://schemas.android.com/tools"

 3     android:layout_width="match_parent"

 4     android:layout_height="match_parent">

 5 

 6     <com.handmark.pulltorefresh.library.PullToRefreshListView

 7         android:id="@+id/lv"

 8         android:layout_width="match_parent"

 9         android:layout_height="match_parent">

10 

11 

12     </com.handmark.pulltorefresh.library.PullToRefreshListView>

13 </RelativeLayout>

 

这里就放了个PullToRefreshListView,其实本质上还是个ListView

(2)item_listview.xml(ListView中单个item的布局)

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

 2               xmlns:tools="http://schemas.android.com/tools"

 3               android:layout_width="match_parent"

 4               android:layout_height="match_parent"

 5               android:orientation="vertical"

 6     >

 7 

 8     <LinearLayout

 9         android:layout_width="match_parent"

10         android:layout_height="wrap_content"

11         android:layout_marginBottom="15dp"

12         android:gravity="center_vertical"

13         android:orientation="horizontal"

14         android:paddingTop="28dp">

15 

16         <!--作者头像-->

17         <ImageButton

18             android:id="@+id/mVideoAvatarBtn"

19             android:layout_width="56dp"

20             android:layout_height="56dp"

21             android:background="@mipmap/defaultimg"/>

22 

23         <!--昵称-->

24         <TextView

25             android:id="@+id/mVideoNicknameTv"

26             android:layout_width="match_parent"

27             android:layout_height="wrap_content"

28             android:layout_alignParentTop="true"

29             android:layout_marginLeft="13dp"

30             android:layout_toRightOf="@+id/mVideoAvatarIv"

31             android:singleLine="true"

32             android:text="张三"

33             android:textSize="16sp"/>

34 

35     </LinearLayout>

36 

37 

38     <!--视频缩略图-->

39     <ImageButton

40         android:id="@+id/mVideoImgBtn"

41         android:layout_width="wrap_content"

42         android:layout_height="wrap_content"

43 

44         />

45 

46 

47 </LinearLayout>

 

单个item中,一个是头像,一个是文本,一个是图片(包裹内容),其布局效果如下:
Android代码优化----PullToRefresh+universal-image-loader实现从网络获取数据并刷新

(3)MyApplication.java:

 1 package com.smyhvae.pulltorefreshdemo;

 2 

 3 import android.app.Application;

 4 

 5 import com.nostra13.universalimageloader.core.ImageLoader;

 6 import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;

 7 

 8 /**

 9  * Created by smyhvae on 2015/5/8.

10  */

11 public class MyApplication extends Application {

12 

13     @Override

14     public void onCreate() {

15         super.onCreate();

16 

17 

18         //创建默认的ImageLoader配置参数

19         ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(this)

20                 .writeDebugLogs() //打印log信息

21                 .build();

22 

23 

24         //Initialize ImageLoader with configuration.

25         ImageLoader.getInstance().init(configuration);

26     }

27 

28 }

 

主程序一进来,我们就在onCreate()中创建ImageLoader的配置参数,并初始化到ImageLoader中。

 

(4)JavaBean的实体:

这个其实就是下面的这些实体:
Android代码优化----PullToRefresh+universal-image-loader实现从网络获取数据并刷新

这个不需要赘述,代码略,在本文最后有源码下载链接。

(5)ViewHolder.java:(ListView的万能模板,嘿嘿)

 1 package com.smyhvae.pulltorefreshdemo.adapter;

 2 

 3 import android.content.Context;

 4 import android.util.SparseArray;

 5 import android.view.LayoutInflater;

 6 import android.view.View;

 7 import android.view.ViewGroup;

 8 

 9 /**

10  * Created by smyhvae on 2015/5/4.

11  * 通用的viewHolder类

12  */

13 public class ViewHolder {

14 

15     private SparseArray<View> mViews;

16     private int mPosition;

17     private View mConvertView;

18 

19     public ViewHolder(Context context, ViewGroup parent, int layoutId, int position) {

20         this.mPosition = position;

21         this.mViews = new SparseArray<View>();

22 

23         mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false);

24 

25         mConvertView.setTag(this);

26 

27     }

28 

29     public static ViewHolder get(Context context, View convertView, ViewGroup parent, int layoutId, int position) {

30         if (convertView == null) {

31             return new ViewHolder(context, parent, layoutId, position);

32         } else {

33             ViewHolder holder = (ViewHolder) convertView.getTag();

34             holder.mPosition = position; //即时ViewHolder是复用的,但是position记得更新一下

35             return holder;

36         }

37     }

38 

39     /*

40     通过viewId获取控件

41      */

42     //使用的是泛型T,返回的是View的子类

43     public <T extends View> T getView(int viewId) {

44         View view = mViews.get(viewId);

45 

46         if (view == null) {

47             view = mConvertView.findViewById(viewId);

48             mViews.put(viewId, view);

49         }

50 

51         return (T) view;

52     }

53 

54     public View getConvertView() {

55         return mConvertView;

56     }

57 

58 }

 

(6)ListViewAdapter.java:(同样是ListView的万能模板)

 1 package com.smyhvae.pulltorefreshdemo.adapter;

 2 

 3 import android.content.Context;

 4 import android.view.LayoutInflater;

 5 import android.view.View;

 6 import android.view.ViewGroup;

 7 import android.widget.BaseAdapter;

 8 

 9 import java.util.List;

10 

11 /**

12  * Created by smyhvae on 2015/5/4.

13  * 通用的ListView的BaseAdapter,所有的ListView的自定义adapter都可以继承这个类哦

14  */

15 public abstract class ListViewAdapter<T> extends BaseAdapter {

16 

17     //为了让子类访问,于是将属性设置为protected

18     protected Context mContext;

19     protected List<T> mDatas;

20     protected LayoutInflater mInflater;

21     private int layoutId; //不同的ListView的item布局肯能不同,所以要把布局单独提取出来

22 

23     public ListViewAdapter(Context context, List<T> datas, int layoutId) {

24         this.mContext = context;

25         mInflater = LayoutInflater.from(context);

26         this.mDatas = datas;

27         this.layoutId = layoutId;

28     }

29 

30     @Override

31     public int getCount() {

32         return mDatas.size();

33     }

34 

35     @Override

36     public T getItem(int position) {

37         return mDatas.get(position);

38     }

39 

40     @Override

41     public long getItemId(int position) {

42         return position;

43     }

44 

45     @Override

46     public View getView(int position, View convertView, ViewGroup parent) {

47         //初始化ViewHolder,使用通用的ViewHolder,一样代码就搞定ViewHolder的初始化咯

48         ViewHolder holder = ViewHolder.get(mContext, convertView, parent, layoutId, position);//layoutId就是单个item的布局

49 

50         convert(holder, getItem(position));

51         return holder.getConvertView(); //这一行的代码要注意了

52     }

53 

54     //将convert方法公布出去

55     public abstract void convert(ViewHolder holder, T t);

56 

57 }

 

(7)【非常非常重要】VideoListViewAdapter.java:

这个才是我们的这个ListView的自定义适配器哦:

  1 package com.smyhvae.pulltorefreshdemo.adapter;

  2 

  3 

  4 import android.content.Context;

  5 import android.view.ViewGroup;

  6 import android.widget.ImageButton;

  7 import android.widget.LinearLayout;

  8 import android.widget.TextView;

  9 

 10 import com.nostra13.universalimageloader.core.DisplayImageOptions;

 11 import com.nostra13.universalimageloader.core.ImageLoader;

 12 import com.nostra13.universalimageloader.core.assist.ImageScaleType;

 13 import com.smyhvae.pulltorefreshdemo.R;

 14 import com.smyhvae.pulltorefreshdemo.entities.Video;

 15 import com.smyhvae.pulltorefreshdemo.utils.Constants;

 16 

 17 import java.util.List;

 18 

 19 /**

 20  * Created by smyhvae on 2015/5/5.

 21  */

 22 

 23 

 24 public class VideoListViewAdapter extends ListViewAdapter<Video> {

 25 

 26 

 27     DisplayImageOptions options;        // DisplayImageOptions是用于设置图片显示的类

 28 

 29 

 30     //MyAdapter需要一个Context,通过Context获得Layout.inflater,然后通过inflater加载item的布局

 31     public VideoListViewAdapter(Context context, List<Video> datas) {

 32         super(context, datas, R.layout.item_listview);

 33     }

 34 

 35 

 36 

 37   /*  @Override

 38     public void convert(ViewHolder holder, Bean bean) {

 39 

 40         ((TextView) holder.getView(R.id.titleTv)).setText(bean.getTitle());

 41         ((TextView) holder.getView(R.id.descTv)).setText(bean.getDesc());

 42         ((TextView) holder.getView(R.id.timeTv)).setText(bean.getTime());

 43         ((TextView) holder.getView(R.id.phoneTv)).setText(bean.getPhone());

 44 

 45 *//*

 46         TextView tv = holder.getView(R.id.titleTv);

 47         tv.setText(...);

 48 

 49        ImageView view = getView(viewId);

 50        Imageloader.getInstance().loadImag(view.url);

 51 /*//*

 52     }*/

 53 

 54     @Override

 55     public void convert(ViewHolder holder, final Video video) {

 56 

 57         //1、作者的头像

 58         ImageButton mVideoAvatarBtn = holder.getView(R.id.mVideoAvatarBtn);

 59         //如果用的是开源框架Picasso获取网络图片,那就按照下面注释掉这一行代码来做。

 60         // load方法里的参数是请求的图片的url。placeholder方法中的参数是说,加载图片成功之前默认显示的图片

 61         //Picasso.with(mContext).load(Constants.CONTENT_HOST + video.getUserAvatarUrl()).placeholder(R.mipmap.ic_launcher).into(mVideoAvatarBtn);

 62         String imageUrl = Constants.CONTENT_HOST + video.getUserAvatarUrl();

 63 

 64         /*

 65         下面的加载网络图片中,用到了Android-Universal-Image-Loader框架

 66          */

 67         //显示图片的配置

 68         // 使用DisplayImageOptions.Builder()创建DisplayImageOptions

 69         options = new DisplayImageOptions.Builder()

 70                 .showStubImage(R.mipmap.phone)            // 设置图片下载期间显示的图片

 71                 .showImageForEmptyUri(R.mipmap.ic_launcher)    // 设置图片Uri为空或是错误的时候显示的图片

 72                 .showImageOnFail(R.drawable.default_ptr_flip)        // 设置图片加载或解码过程中发生错误显示的图片

 73                 .cacheInMemory(true)                        // 设置下载的图片是否缓存在内存中

 74                 .cacheOnDisc(true)                            // 设置下载的图片是否缓存在SD卡中

 75                 .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)   //图片会缩放到目标大小完全。非常重要,也就是说,这个view有多大,图片就会缩放到多大

 76                 .build();

 77 

 78         ImageLoader.getInstance().displayImage(imageUrl, mVideoAvatarBtn, options);

 79 

 80         //2、作者的昵称

 81         TextView mVideoNicknameTv = holder.getView(R.id.mVideoNicknameTv);

 82         mVideoNicknameTv.setText(video.getUserNickName());

 83 

 84 

 85         //3、视频的缩略图

 86         ImageButton mVideoImgBtn = holder.getView(R.id.mVideoImgBtn);

 87 

 88        //让缩略图的宽度为手机屏幕的宽度,高度为手机屏幕宽度的一半。说白了,就是让 图片的尺寸为2:1

 89         LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(

 90                 ViewGroup.LayoutParams.MATCH_PARENT,

 91                 (int) (Constants.displayWidth * 0.5f + 0.5f));

 92         mVideoImgBtn.setLayoutParams(params);

 93 

 94         String PicUrl = Constants.CONTENT_HOST + video.getPicUrl();

 95 

 96 

 97         //Picasso.with(mContext).load(Constants.CONTENT_HOST + video.getPicUrl()).placeholder(R.mipmap.defaultimg).into(mVideoImgBtn);

 98         ImageLoader.getInstance().displayImage(PicUrl, mVideoImgBtn, options);

 99 

100 

101         System.out.println("---->" + video.getPicUrl());

102 

103 

104 

105         //跳转到具体是哪一个视频(即item的详情页)

106 /*        mVideoImgBtn.setOnClickListener(new View.OnClickListener() {

107             @Override

108             public void onClick(View v) {

109                 int id = video.getVideoUrl();

110                 mContext.startActivity(new Intent());

111             }

112         });*/

113     }

114 }

 

尤其要注意第75行的属性哦,这样可以让图片缩放到当前控件的大小。(如果没有这一行,图片大小就是包裹内容;如果加了这一行,图片大小就是匹配当前控件的大小,因为我在第88行设置了这个ImageButton的宽度是手机屏幕的宽度,高度是手机屏幕宽度的一半,这样的话,不管网络上的 图片是多大,都能够保证显示出来的图片比例是2:1)

(8)MainActivity.java:

  1 package com.smyhvae.pulltorefreshdemo;

  2 

  3 import android.app.Activity;

  4 import android.content.Context;

  5 import android.os.Bundle;

  6 import android.os.Handler;

  7 import android.os.Message;

  8 import android.util.DisplayMetrics;

  9 import android.util.Log;

 10 import android.widget.ListView;

 11 import android.widget.Toast;

 12 

 13 import com.google.gson.Gson;

 14 import com.google.gson.GsonBuilder;

 15 import com.google.gson.reflect.TypeToken;

 16 import com.handmark.pulltorefresh.library.PullToRefreshBase;

 17 import com.handmark.pulltorefresh.library.PullToRefreshListView;

 18 import com.lidroid.xutils.HttpUtils;

 19 import com.lidroid.xutils.exception.HttpException;

 20 import com.lidroid.xutils.http.RequestParams;

 21 import com.lidroid.xutils.http.ResponseInfo;

 22 import com.lidroid.xutils.http.callback.RequestCallBack;

 23 import com.lidroid.xutils.http.client.HttpRequest;

 24 import com.smyhvae.pulltorefreshdemo.adapter.VideoListViewAdapter;

 25 import com.smyhvae.pulltorefreshdemo.entities.ResponseObject;

 26 import com.smyhvae.pulltorefreshdemo.entities.Video;

 27 import com.smyhvae.pulltorefreshdemo.entities.VideoResponse;

 28 import com.smyhvae.pulltorefreshdemo.utils.Constants;

 29 

 30 import java.util.List;

 31 

 32 

 33 public class MainActivity extends Activity {

 34 

 35     private PullToRefreshListView lv;

 36     private Context mContext;

 37 

 38     private List<Video> videoList; //用来存放视频列表的集合

 39 

 40     private int page = 0;  //当前页码

 41     private int size = 10; //每页显示10个

 42     private int count = 0; //当前页面有多少个视频

 43 

 44     private VideoListViewAdapter videoListViewAdapter;

 45 

 46 

 47 

 48 

 49     @Override

 50     protected void onCreate(Bundle savedInstanceState) {

 51         super.onCreate(savedInstanceState);

 52         setContentView(R.layout.activity_main);

 53         //第一个Activity加载进来时,我们就获取屏幕的宽度和高度

 54         DisplayMetrics displayMetrics = new DisplayMetrics();

 55         getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);

 56         Constants.displayWidth = displayMetrics.widthPixels;

 57         Constants.displayHeight = displayMetrics.heightPixels;

 58 

 59 

 60 

 61         initView();

 62 

 63     }

 64 

 65     private void initView() {

 66         lv = (PullToRefreshListView) findViewById(R.id.lv);

 67 

 68         /*

 69         设置刷新的模式:

 70         可选值为:disabled(禁用下拉刷新),

 71         pullFromStart(仅支持下拉刷新),

 72         pullFromEnd(仅支持上拉刷新),

 73         both(二者都支持),

 74         manualOnly(只允许手动触发)

 75          */

 76         lv.setMode(PullToRefreshBase.Mode.BOTH);  //让这个Listview支持上拉加载更多,下拉刷新

 77         lv.setScrollingWhileRefreshingEnabled(true);//滚动的时候不允许刷新,要不然么会很乱

 78         //很重要,刷新时做回调

 79         lv.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener<ListView>() {

 80             @Override

 81             public void onRefresh(PullToRefreshBase<ListView> refreshView) {

 82                 //在这里做数据加载的操作

 83                 loadData(refreshView.getScrollY() < 0);

 84             }

 85         });

 86 

 87         //首次打开页面时,延时200ms后自动加载数据

 88        new Handler (new Handler.Callback(){

 89            @Override

 90             public boolean handleMessage(Message msg) {

 91                lv.setRefreshing();

 92                return true;

 93            }

 94        }).sendEmptyMessageDelayed(0,200);

 95     }

 96 

 97 

 98     //如果是true表示下拉刷新,false表示上拉加载更多(如果y值小于0,说明是下拉操作)

 99     private void loadData(final boolean direction) {

100         //http://172.24.1.49:8081/video/getVideos?apikey=  &typeid=1&page=1

101         RequestParams params = new RequestParams();

102 

103         if (direction) {  //如果是上拉,那应该将page变为第一页

104             page = 1;

105 

106         } else {

107             page++; //如果是下拉,就让page加1

108 

109         }

110 

111         params.addQueryStringParameter("page", String.valueOf(page)); //默认显示第一页

112         // params.addQueryStringParameter("size", "10"); //每页显示10个

113 

114         new HttpUtils().send(HttpRequest.HttpMethod.GET, Constants.VIDEO_LIST + "typeid=1&", params, new RequestCallBack<String>() {

115             @Override

116             public void onSuccess(ResponseInfo<String> responseInfo) {

117                 lv.onRefreshComplete();

118                 Log.d("json", "---video的json数据>" + responseInfo.result);

119 

120                 //解析服务器端的json数据

121                 Gson gson = new GsonBuilder().create();

122                 ResponseObject<VideoResponse> object = gson.fromJson(responseInfo.result, new TypeToken<ResponseObject<VideoResponse>>() {

123                 }.getType());

124 /*                ResponseObject<VideoResponse> object = new GsonBuilder().create().fromJson(responseInfo.result, new TypeToken<VideoResponse>() {

125                 }.getType());*/

126                 page = Integer.parseInt(object.getResult().getPage()); //获取服务器端返回来的当前页码

127                 count = object.getResult().getCnt(); //获取当前页面有多少个视频

128                 Log.d("json","---当前页面的item的个数>"+count);

129                 if (direction) { //下拉刷新

130                     videoList = object.getResult().getVideos();  //获取视频信息的集合,并存放

131 

132                     videoListViewAdapter = new VideoListViewAdapter(MainActivity.this,videoList);

133                     lv.setAdapter(videoListViewAdapter); //为这个listView绑定适配器

134 

135                 } else {//尾部加载更多

136                     videoList.addAll(object.getResult().getVideos());

137 

138                 }

139 

140                 if (count == 0) { //如果当前页面已经没有视频了,那就告诉客户端,不要再拉了,因为后面没有数据了。

141                     lv.setMode(PullToRefreshBase.Mode.PULL_FROM_START);

142                 }

143 

144             }

145 

146             @Override

147             public void onFailure(HttpException e, String s) {

148                 lv.onRefreshComplete();//不管是请求成功还是请求失败,我们都停止加载数据

149                 Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show();

150 

151             }

152         });

153 

154     }

155 

156 } 

这个MainActivity中讲到了xUtils怎样获取到网络上的json数据,并用Gson解析,然后用pull to refresh处理上拉下拉刷新的逻辑,好吧,确实是快速开发,用到的框架还挺多的好伐~

 

【工程文件】

 2015-05-08-PullToRefreshDemo.rar

 

你可能感兴趣的:(android)