【声明】

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

生命壹号: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的布局)

 <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"> <com.handmark.pulltorefresh.library.PullToRefreshListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent"> </com.handmark.pulltorefresh.library.PullToRefreshListView>
</RelativeLayout>

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

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

 <LinearLayout 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:orientation="vertical"
> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="28dp"> <!--作者头像-->
<ImageButton
android:id="@+id/mVideoAvatarBtn"
android:layout_width="56dp"
android:layout_height="56dp"
android:background="@mipmap/defaultimg"/> <!--昵称-->
<TextView
android:id="@+id/mVideoNicknameTv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="13dp"
android:layout_toRightOf="@+id/mVideoAvatarIv"
android:singleLine="true"
android:text="张三"
android:textSize="16sp"/> </LinearLayout> <!--视频缩略图-->
<ImageButton
android:id="@+id/mVideoImgBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content" /> </LinearLayout>

单个item中,一个是头像,一个是文本,一个是图片(包裹内容),其布局效果如下:

(3)MyApplication.java:

 package com.smyhvae.pulltorefreshdemo;

 import android.app.Application;

 import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; /**
* Created by smyhvae on 2015/5/8.
*/
public class MyApplication extends Application { @Override
public void onCreate() {
super.onCreate(); //创建默认的ImageLoader配置参数
ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(this)
.writeDebugLogs() //打印log信息
.build(); //Initialize ImageLoader with configuration.
ImageLoader.getInstance().init(configuration);
} }

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

(4)JavaBean的实体:

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

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

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

 package com.smyhvae.pulltorefreshdemo.adapter;

 import android.content.Context;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup; /**
* Created by smyhvae on 2015/5/4.
* 通用的viewHolder类
*/
public class ViewHolder { private SparseArray<View> mViews;
private int mPosition;
private View mConvertView; public ViewHolder(Context context, ViewGroup parent, int layoutId, int position) {
this.mPosition = position;
this.mViews = new SparseArray<View>(); mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false); mConvertView.setTag(this); } public static ViewHolder get(Context context, View convertView, ViewGroup parent, int layoutId, int position) {
if (convertView == null) {
return new ViewHolder(context, parent, layoutId, position);
} else {
ViewHolder holder = (ViewHolder) convertView.getTag();
holder.mPosition = position; //即时ViewHolder是复用的,但是position记得更新一下
return holder;
}
} /*
通过viewId获取控件
*/
//使用的是泛型T,返回的是View的子类
public <T extends View> T getView(int viewId) {
View view = mViews.get(viewId); if (view == null) {
view = mConvertView.findViewById(viewId);
mViews.put(viewId, view);
} return (T) view;
} public View getConvertView() {
return mConvertView;
} }

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

 package com.smyhvae.pulltorefreshdemo.adapter;

 import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter; import java.util.List; /**
* Created by smyhvae on 2015/5/4.
* 通用的ListView的BaseAdapter,所有的ListView的自定义adapter都可以继承这个类哦
*/
public abstract class ListViewAdapter<T> extends BaseAdapter { //为了让子类访问,于是将属性设置为protected
protected Context mContext;
protected List<T> mDatas;
protected LayoutInflater mInflater;
private int layoutId; //不同的ListView的item布局肯能不同,所以要把布局单独提取出来 public ListViewAdapter(Context context, List<T> datas, int layoutId) {
this.mContext = context;
mInflater = LayoutInflater.from(context);
this.mDatas = datas;
this.layoutId = layoutId;
} @Override
public int getCount() {
return mDatas.size();
} @Override
public T getItem(int position) {
return mDatas.get(position);
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
//初始化ViewHolder,使用通用的ViewHolder,一样代码就搞定ViewHolder的初始化咯
ViewHolder holder = ViewHolder.get(mContext, convertView, parent, layoutId, position);//layoutId就是单个item的布局 convert(holder, getItem(position));
return holder.getConvertView(); //这一行的代码要注意了
} //将convert方法公布出去
public abstract void convert(ViewHolder holder, T t); }

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

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

 package com.smyhvae.pulltorefreshdemo.adapter;

 import android.content.Context;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView; import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.smyhvae.pulltorefreshdemo.R;
import com.smyhvae.pulltorefreshdemo.entities.Video;
import com.smyhvae.pulltorefreshdemo.utils.Constants; import java.util.List; /**
* Created by smyhvae on 2015/5/5.
*/ public class VideoListViewAdapter extends ListViewAdapter<Video> { DisplayImageOptions options; // DisplayImageOptions是用于设置图片显示的类 //MyAdapter需要一个Context,通过Context获得Layout.inflater,然后通过inflater加载item的布局
public VideoListViewAdapter(Context context, List<Video> datas) {
super(context, datas, R.layout.item_listview);
} /* @Override
public void convert(ViewHolder holder, Bean bean) { ((TextView) holder.getView(R.id.titleTv)).setText(bean.getTitle());
((TextView) holder.getView(R.id.descTv)).setText(bean.getDesc());
((TextView) holder.getView(R.id.timeTv)).setText(bean.getTime());
((TextView) holder.getView(R.id.phoneTv)).setText(bean.getPhone()); *//*
TextView tv = holder.getView(R.id.titleTv);
tv.setText(...); ImageView view = getView(viewId);
Imageloader.getInstance().loadImag(view.url);
/*//*
}*/ @Override
public void convert(ViewHolder holder, final Video video) { //1、作者的头像
ImageButton mVideoAvatarBtn = holder.getView(R.id.mVideoAvatarBtn);
//如果用的是开源框架Picasso获取网络图片,那就按照下面注释掉这一行代码来做。
// load方法里的参数是请求的图片的url。placeholder方法中的参数是说,加载图片成功之前默认显示的图片
//Picasso.with(mContext).load(Constants.CONTENT_HOST + video.getUserAvatarUrl()).placeholder(R.mipmap.ic_launcher).into(mVideoAvatarBtn);
String imageUrl = Constants.CONTENT_HOST + video.getUserAvatarUrl(); /*
下面的加载网络图片中,用到了Android-Universal-Image-Loader框架
*/
//显示图片的配置
// 使用DisplayImageOptions.Builder()创建DisplayImageOptions
options = new DisplayImageOptions.Builder()
.showStubImage(R.mipmap.phone) // 设置图片下载期间显示的图片
.showImageForEmptyUri(R.mipmap.ic_launcher) // 设置图片Uri为空或是错误的时候显示的图片
.showImageOnFail(R.drawable.default_ptr_flip) // 设置图片加载或解码过程中发生错误显示的图片
.cacheInMemory(true) // 设置下载的图片是否缓存在内存中
.cacheOnDisc(true) // 设置下载的图片是否缓存在SD卡中
.imageScaleType(ImageScaleType.EXACTLY_STRETCHED) //图片会缩放到目标大小完全。非常重要,也就是说,这个view有多大,图片就会缩放到多大
.build(); ImageLoader.getInstance().displayImage(imageUrl, mVideoAvatarBtn, options); //2、作者的昵称
TextView mVideoNicknameTv = holder.getView(R.id.mVideoNicknameTv);
mVideoNicknameTv.setText(video.getUserNickName()); //3、视频的缩略图
ImageButton mVideoImgBtn = holder.getView(R.id.mVideoImgBtn); //让缩略图的宽度为手机屏幕的宽度,高度为手机屏幕宽度的一半。说白了,就是让 图片的尺寸为2:1
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
(int) (Constants.displayWidth * 0.5f + 0.5f));
mVideoImgBtn.setLayoutParams(params); String PicUrl = Constants.CONTENT_HOST + video.getPicUrl(); //Picasso.with(mContext).load(Constants.CONTENT_HOST + video.getPicUrl()).placeholder(R.mipmap.defaultimg).into(mVideoImgBtn);
ImageLoader.getInstance().displayImage(PicUrl, mVideoImgBtn, options); System.out.println("---->" + video.getPicUrl()); //跳转到具体是哪一个视频(即item的详情页)
/* mVideoImgBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int id = video.getVideoUrl();
mContext.startActivity(new Intent());
}
});*/
}
}

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

(8)MainActivity.java:

 package com.smyhvae.pulltorefreshdemo;

 import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
import android.widget.ListView;
import android.widget.Toast; import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.handmark.pulltorefresh.library.PullToRefreshBase;
import com.handmark.pulltorefresh.library.PullToRefreshListView;
import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.RequestParams;
import com.lidroid.xutils.http.ResponseInfo;
import com.lidroid.xutils.http.callback.RequestCallBack;
import com.lidroid.xutils.http.client.HttpRequest;
import com.smyhvae.pulltorefreshdemo.adapter.VideoListViewAdapter;
import com.smyhvae.pulltorefreshdemo.entities.ResponseObject;
import com.smyhvae.pulltorefreshdemo.entities.Video;
import com.smyhvae.pulltorefreshdemo.entities.VideoResponse;
import com.smyhvae.pulltorefreshdemo.utils.Constants; import java.util.List; public class MainActivity extends Activity { private PullToRefreshListView lv;
private Context mContext; private List<Video> videoList; //用来存放视频列表的集合 private int page = 0; //当前页码
private int size = 10; //每页显示10个
private int count = 0; //当前页面有多少个视频 private VideoListViewAdapter videoListViewAdapter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//第一个Activity加载进来时,我们就获取屏幕的宽度和高度
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
Constants.displayWidth = displayMetrics.widthPixels;
Constants.displayHeight = displayMetrics.heightPixels; initView(); } private void initView() {
lv = (PullToRefreshListView) findViewById(R.id.lv); /*
设置刷新的模式:
可选值为:disabled(禁用下拉刷新),
pullFromStart(仅支持下拉刷新),
pullFromEnd(仅支持上拉刷新),
both(二者都支持),
manualOnly(只允许手动触发)
*/
lv.setMode(PullToRefreshBase.Mode.BOTH); //让这个Listview支持上拉加载更多,下拉刷新
lv.setScrollingWhileRefreshingEnabled(true);//滚动的时候不允许刷新,要不然么会很乱
//很重要,刷新时做回调
lv.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener<ListView>() {
@Override
public void onRefresh(PullToRefreshBase<ListView> refreshView) {
//在这里做数据加载的操作
loadData(refreshView.getScrollY() < 0);
}
}); //首次打开页面时,延时200ms后自动加载数据
new Handler (new Handler.Callback(){
@Override
public boolean handleMessage(Message msg) {
lv.setRefreshing();
return true;
}
}).sendEmptyMessageDelayed(0,200);
} //如果是true表示下拉刷新,false表示上拉加载更多(如果y值小于0,说明是下拉操作)
private void loadData(final boolean direction) {
//http://172.24.1.49:8081/video/getVideos?apikey= &typeid=1&page=1
RequestParams params = new RequestParams(); if (direction) { //如果是上拉,那应该将page变为第一页
page = 1; } else {
page++; //如果是下拉,就让page加1 } params.addQueryStringParameter("page", String.valueOf(page)); //默认显示第一页
// params.addQueryStringParameter("size", "10"); //每页显示10个 new HttpUtils().send(HttpRequest.HttpMethod.GET, Constants.VIDEO_LIST + "typeid=1&", params, new RequestCallBack<String>() {
@Override
public void onSuccess(ResponseInfo<String> responseInfo) {
lv.onRefreshComplete();
Log.d("json", "---video的json数据>" + responseInfo.result); //解析服务器端的json数据
Gson gson = new GsonBuilder().create();
ResponseObject<VideoResponse> object = gson.fromJson(responseInfo.result, new TypeToken<ResponseObject<VideoResponse>>() {
}.getType());
/* ResponseObject<VideoResponse> object = new GsonBuilder().create().fromJson(responseInfo.result, new TypeToken<VideoResponse>() {
}.getType());*/
page = Integer.parseInt(object.getResult().getPage()); //获取服务器端返回来的当前页码
count = object.getResult().getCnt(); //获取当前页面有多少个视频
Log.d("json","---当前页面的item的个数>"+count);
if (direction) { //下拉刷新
videoList = object.getResult().getVideos(); //获取视频信息的集合,并存放 videoListViewAdapter = new VideoListViewAdapter(MainActivity.this,videoList);
lv.setAdapter(videoListViewAdapter); //为这个listView绑定适配器 } else {//尾部加载更多
videoList.addAll(object.getResult().getVideos()); } if (count == 0) { //如果当前页面已经没有视频了,那就告诉客户端,不要再拉了,因为后面没有数据了。
lv.setMode(PullToRefreshBase.Mode.PULL_FROM_START);
} } @Override
public void onFailure(HttpException e, String s) {
lv.onRefreshComplete();//不管是请求成功还是请求失败,我们都停止加载数据
Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show(); }
}); } } 

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

【工程文件】

2015-05-08-PullToRefreshDemo.rar

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

  1. Android开源库--Universal Image Loader通用图片加载器

    如果说我比别人看得更远些,那是因为我站在了巨人的肩上.   github地址:https://github.com/nostra13/Android-Universal-Image-Loader 介绍 ...

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

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  3. Android Volley 库通过网络获取 JSON 数据

    本文内容 什么是 Volley 库 Volley 能做什么 Volley 架构 环境 演示 Volley 库通过网络获取 JSON 数据 参考资料 Android 关于网络操作一般都会介绍 HttpC ...

  4. Android中Universal Image Loader开源框架的简单使用

    UIL (Universal Image Loader)aims to provide a powerful, flexible and highly customizable instrument ...

  5. 【Android应用开发】 Universal Image Loader ( 使用简介 | 示例代码解析 )

    作者 : 韩曙亮 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/50824912 相关地址介绍 : -- Universal I ...

  6. android universal image loader 缓冲原理详解

    1. 功能介绍 1.1 Android Universal Image Loader Android Universal Image Loader 是一个强大的.可高度定制的图片缓存,本文简称为UIL ...

  7. 开源项目Universal Image Loader for Android 说明文档 (1) 简介

     When developing applications for Android, one often facesthe problem of displaying some graphical ...

  8. 开源项目Universal Image Loader for Android 说明文档 (1) 简单介绍

     When developing applications for Android, one often facesthe problem of displaying some graphical ...

  9. universal image loader在listview/gridview中滚动时重复加载图片的问题及解决方法

    在listview/gridview中使用UIL来display每个item的图片,当图片数量较多需要滑动滚动时会出现卡顿,而且加载过的图片再次上翻后依然会重复加载(显示设置好的加载中图片) 最近在使 ...

随机推荐

  1. ahjesus sql2005+游标示例

    DECLARE @TypeId INT, @Price1 FLOAT, @Original FLOAT DECLARE my_cursor CURSOR SCROLL FOR SELECT TypeI ...

  2. 阿里云主机上安装jdk

    今天继续安装jdk到阿里云服务上,大家要看一下阿里云是32位还是64位的,如果是32位下载32位的包,如果是64位的下载64位的包 我的就是64位的,开始我还不知道是怎么区分32/64位的,原来X64 ...

  3. 优化磁盘I/O

    管理I/O,避免过度地寻道可以让硬盘更快.顺序I/O和随机I/O之间的性能差异随便就可以达到40:1,可能更多.这在数据库服务器中尤其重要,因为数据库的日志是以顺序格式写的.选择合适的硬件,合理地配置 ...

  4. 我为什么要做富文本编辑器【wangEditor5个月总结】

    请访问wangEditor官网:www.wangEditor.com ----------------------------------------------------------------- ...

  5. js 中{},[]中括号,大括号

    1. { } 大括号,表示定义一个对象,大部分情况下要有成对的属性和值,或是函数. 如: var LangShen = {"Name":"Langshen",& ...

  6. 如何利用ArcGIS Engine接口实现打开Raster Catalog中的某一幅指定的影像?

    将IRasterCatalog转化为ITable,然后通过ITable.GetRow返回指定索引的IRow,将IRow转为IRasterCatalogItem,进而获取IRasterCatalogIt ...

  7. 安卓第十三天笔记-服务(Service)

    安卓第十三天笔记-服务(Service) Servcie服务 1.服务概念 服务 windows 服务没有界面,一直运行在后台, 运行在独立的一个进程里面 android 服务没有界面,一直运行在后台 ...

  8. 【原】iOSCoreAnimation动画系列教程(一):CABasicAnimation【包会】

    本文的最新版本已经发布在简书[编程小翁]上,强烈建议到上查看简书,[点击这里跳转]. 在iOS中,图形可分为以下几个层次: 越上层,封装程度越高,动画实现越简洁越简单,但是自由度越低:反之亦然.本文着 ...

  9. OpenGL ES学习笔记(三)——纹理

    首先申明下,本文为笔者学习<OpenGL ES应用开发实践指南(Android卷)>的笔记,涉及的代码均出自原书,如有需要,请到原书指定源码地址下载. <OpenGL ES学习笔记( ...

  10. iOS之 PJSIP静态库编译(三)

    dada哪个所有静态库编译完成后还是不能运行那个demo,提示你找不到arm**.a 你lipo后要记得吧合并成.a  名字更改成你最后编译版本生成的.a名字....... 或者吧所有库add到你的工 ...