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


     【声明】 

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

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

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

    联系方式:smyhvae@163.com 

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

    【工程文件】

     2015-05-08-PullToRefreshDemo.rar

  • 相关阅读:
    day36 08-Hibernate抓取策略:批量抓取
    day36 07-Hibernate抓取策略:many-to-one上的抓取策略
    day36 06-Hibernate抓取策略:set集合上的抓取策略
    day36 05-Hibernate检索方式:离线条件查询
    day36 04-Hibernate检索方式:多表连接查询
    day36 03-Hibernate检索方式:排序、参数绑定、投影查询
    【收集】11款Linux数据恢复工具
    【收集】11款Linux数据恢复工具
    7个免费的Linux FTP客户端工具
    7个免费的Linux FTP客户端工具
  • 原文地址:https://www.cnblogs.com/qianguyihao/p/4488049.html
Copyright © 2020-2023  润新知