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

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

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

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

  • 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中,一个是头像,一个是文本,一个是图片(包裹内容),其布局效果如下:

(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的实体:

这个其实就是下面的这些实体:

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

(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处理上拉下拉刷新的逻辑,好吧,确实是快速开发,用到的框架还挺多的好伐~

 

时间: 2024-08-01 09:53:43

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

Android网络之数据解析----使用Google Gson解析Json数据

[正文] 文章回顾: Android网络之数据解析----SAX方式解析XML数据 一.Json数据的介绍                                                                                                                 Json(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于JS的一个子集. Json采用完全独立于语言的文本格式,这使得Jso

Android 经典笔记之八:网络请求数据基础介绍

关于网络请求数据总结 目录介绍 1.Http请求与响应 1.1 Http请求包的结构 1.2 HTTP响应包结构 2.Http请求方式 3.Get和Post的比较 3.1 get请求 3.2 post请求 3.3 其他区别 3.4 网络心声 4.Http响应方式 5.同步和异步 6.Http缓存机制讲解 6.1 request请求字段含义 6.2 response响应字段含义 6.3 缓存机制逻辑图 0.本人写的综合案例 案例 说明及截图 模块:新闻,音乐,视频,图片,唐诗宋词,快递,天气,记事

android-请教一个Android的从网络上获取数据的问题

问题描述 请教一个Android的从网络上获取数据的问题 Android 从网络上获取数据 跟安卓系统有关系吗,,,,用Android5.0以上的系统的手机请求到的数据跟5.0以下系统的手机请求到的数据不一样.(get请求) Android5,0以上的系统请求到的数据:{ "wegInstLt": [ { "billTypeCode": "0", "channelId": 530, "channelKind"

Android实现从网络获取图片显示并保存到SD卡的方法_Android

本文实例讲述了Android实现从网络获取图片显示并保存到SD卡的方法.分享给大家供大家参考,具体如下: 问题: 如何不断获取图片并显示出来,达到视频的效果? 代码: public class GetPictureFromInternetActivity extends Activity { private ImageView imageView; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInst

android universal image loader 缓冲原理详解

1. 功能介绍 1.1 Android Universal Image Loader Android Universal Image Loader 是一个强大的.可高度定制的图片缓存,本文简称为UIL. 简单的说 UIL 就做了一件事--获取图片并显示在相应的控件上. 1.2 基本使用 1.2.1 初始化 添加完依赖后在Application或Activity中初始化ImageLoader,如下: public class YourApplication extends Application

开源项目Universal Image Loader for Android

In the previous article, we've initialized the ImageLoader with configuration; and now, it is ready for immediate use according to its intended purpose.  在之前的章节,我们已经通过配置初始化了ImageLoader,现在,我们来介绍一下怎么使用ImageLoader For this, it has four overloaded method

【译】UNIVERSAL IMAGE LOADER. PART 3---ImageLoader详解

在之前的文章,我们重点讲了Android-Universal-Image-Loader的三个主要组件,现在我们终于可以开始使用它了. Android-Universal-Image-Loader有四个重载方法 void displayImage(String url, ImageView view) void displayImage(String url, ImageView view, DisplayImageOptions options) void displayImage(String

Android使用PullToRefresh完成ListView下拉刷新和左滑删除功能_Android

ListView下刷新刷功能相信从事Android开发的猿友们并不陌生,包括现在Google亲儿子SwipeRefreshLayout实现效果在一些APP上也能看见(不过个人不喜欢官方的刷新效果).本文就带领一些刚入门android的朋友或者一起爱分享的朋友来简单的实现ListView的下拉刷新和左滑删除效果. 一.本文主要内容: 使用PullToRefresh完成ListView下拉.上拉刷新: 扩展PullToRefresh完美的实现ListView左滑删除效果: 注意:本文中的PullTo

Android使用PullToRefresh实现上拉加载和下拉刷新效果的代码_Android

在没给大家介绍正文之前,先给大家介绍展示下运行图,如果大家感觉还不错,请继续往下阅读: 相关阅读:分享Android中pullToRefresh的使用心得 项目已同步至:https://github.com/nanchen2251/pullToRefreshDemo 简单使用详情: 1)studio可以直接在app的module设置中直接进行搜索,但是有-的必须添上,而不能用空格代替,为了更加了解这个东西,我还是推荐大家去这里看看,奉上网址: https://github.com/chrisba