【声明】

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

生命壹号: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. 前端技巧:禁止浏览器static files缓存篇(转)

    前端技巧:禁止浏览器static files缓存篇 由于CSS/JS文件经常需要改动,前端调试时是不希望浏览器缓存这些文件的. 本文记录博主的经验. Meta法 目前在chrome调试还没有遇到问题, ...

  2. Android 手机卫士17--缓存清理

    清理单个应用缓存 通过反射调用方法 需要权限:android.permission.DELETE_CACHE_FILES. 以上权限为系统权限,手机卫士应用为用户应用,不能拿到此权限 换思路: 调用系 ...

  3. bootstrap glyphicon图标无法显示

    如果不注意bootstrap引入css和fonts的规范,则可能会导致bootstrap 在显示glyphicon图标时无法正常显示,显示为方框. 此时可搜索bootstrap.css中的.glyph ...

  4. [Xamarin.Android] 自定义控件

    [Xamarin.Android] 自定义控件 前言 软件项目开发的过程中,免不了遇到一些无法使用内建控件就能满足的客户需求,例如:时速表.折线图...等等.这时开发人员可以透过自定义控件的方式,为项 ...

  5. [js开源组件开发]js手机端浮层控件,并有多种弹出小提示,兼容pc端浏览器

    js dialog组件,包含alert和confirm的实现 本组件所有的资源均在github上可以查看源代码 GitHub 本dialog的组件的例子请在这里查看 demo dialog js di ...

  6. mysql实时同步到mssql的解决方案

    数据库在应用程序中是必不可少的部分,mysql是开源的,所以很多人它,mssql是微软的,用在windows平台上是非常方便的,所以也有很多人用它.现在问题来了,如何将这两个数据库同步,即数据内容保持 ...

  7. 我的GTD中收集的书单

    在几年的GTD过程中,收集了一些想读的书目,没有系统地整理,每当读完一本之后,就翻翻书单,寻找下一本感兴趣的书,书是不可能读完的,只能找有兴趣的.符合自己目标方向的.有些书记录了豆瓣上的评分,虽然不是 ...

  8. Spring(三)Bean继续入门

    一.Aware相关接口 对于应用程序来说,应该尽量减少对Sping Api的耦合程度,然而有些时候为了运用Spring所提供的一些功能,有必要让Bean了解Spring容器对其进行管理的细节信息,如让 ...

  9. 使用JDBC对数据库进行查询的前期准备工作,以及简单的JDBC访问MySQL数据库(Mac)

    首先JDBC的前期数据库数据准备: 1,打开链接好MySQL的Workbench软件,新建一个数据库: 2.然后打开数据库对应的代码编辑窗口,建立表和插入数据记录: 3.然后是打开关于javaWeb编 ...

  10. js检测浏览器型号

    公司要求做内部统计,要求监控客服玩游戏使用的浏览器的型号,是火狐的.谷歌的.还是IE的等等. [code lang="javascript"] /**** * 目前识别范围 * M ...