转载请注明出处:http://blog.csdn.net/qq_34819586
使用xlistview来进行 上拉加载更多、下拉刷新列表以及实现列表中图片的异步加载
参考文章:http://blog.csdn.net/afanbaby/article/details/55804850
http://blog.csdn.net/carterjin/article/details/7995935
附上:xListView的实现原理与解析http://blog.csdn.net/zhaokaiqiang1992/article/details/42392731
新手,首次写博客若有侵权请告知立刻删除文章。若有错误请多多指教。
效果图:网络差时会先用app内置图片
网络差时会先用app内置图片
MainActivity:
public class MainActivity extends Activity implements XListView.IXListViewListener {
private XListView mListView;
private Handler mHandler;
private MyAdapter myAdapter;
List<ImageEntry> mList;
//要显示的参数及图片地址
public String[] urls = new String[]{"http://img4.imgtn.bdimg.com/it/u=294550341,4259963231&fm=27&gp=0.jpg","http://img4.imgtn.bdimg.com/it/u=1037574783,2132354437&fm=27&gp=0.jpg"};
public String[] time = new String[]{"2017.08.01 11.11","2017.08.10 11.2"};
public Long[] id =new Long[]{3L,4L};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (XListView) findViewById(R.id.xlistview);
//mainAdapter = new MainAdapter(this);//实例化一个适配器对象
//实例化一个图片数组列表对象
mList = new ArrayList<ImageEntry>();
//datas = new ArrayList<>();
mHandler = new Handler();
//设置数据
geneItems();
//为xListView设置一些配置和适配器
mListView.setPullLoadEnable(true);
mListView.setAdapter(myAdapter);
mListView.setXListViewListener(this);
//设置item的点击事件
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
//这里的i-1,是因为头视图占了一个position
//Toast.makeText(MainActivity.this, "i:" + (i - 1), Toast.LENGTH_SHORT).show();
//这里我修改为显示items的id,在MyAdapter的getItemId处修改
Toast.makeText(MainActivity.this, "你点击的item的id是:" +l, Toast.LENGTH_SHORT).show();
}
});
//设置长按事件
mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(MainActivity.this, "长按事件 i:" + (i-1), Toast.LENGTH_SHORT).show();
return false;
}
});
/*
//添加头布局
View view = getLayoutInflater().inflate(R.layout.head_view, null);
mListView.addHeaderView(view);
//添加尾视图
View view2 = getLayoutInflater().inflate(R.layout.head_view, null);
mListView.addFooterView(view2);
*/
//设置禁止上拉
//mListView.setPullLoadEnable(false);
//设置禁止下拉
//mListView.setPullRefreshEnable(false);
}
//为图片数组列表设置值并为适配器传递数组列表即传递数据,且还实例化了一个myAdapt对象
private void geneItems() {
for(int i=0; i<2; i++){
ImageEntry entry = new ImageEntry();
entry.seturl(urls[i]);//为ImageEntry中url赋值
entry.settime(time[i]);
entry.setid(id[i]);
mList.add(entry);
}
myAdapter = new MyAdapter(this,mList);
//为MyAdapter中xlist_v赋值
myAdapter.SetXListView(mListView);
}
//下拉刷新
@Override
public void onRefresh() {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mList.clear();//清空数组列表变量
geneItems();
mListView.setAdapter(myAdapter);
onLoad();
}
}, 2000);
}
//上拉加载
@Override
public void onLoadMore() {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
geneItems();
//mainAdapter.notifyDataSetChanged();
myAdapter.notifyDataSetChanged();
onLoad();
}
}, 2000);
}
//停止更新和加载并重置头尾部view。获取时间。
private void onLoad() {
mListView.stopRefresh();
mListView.stopLoadMore();
//获取当前时间
Date curDate = new Date(System.currentTimeMillis());
//格式化
SimpleDateFormat formatter = new SimpleDateFormat();
String time = formatter.format(curDate);
mListView.setRefreshTime(time);
}
}
AsyncImageLoader :
/**
* 异步加载图片类,内部有缓存,可以通过后台线程获取网络图片。首先生成一个实例,并调用loadDrawableByTag方法来获取一个Drawable对象
*/
public class AsyncImageLoader {
/**
* 使用软引用SoftReference,可以由系统在恰当的时候更容易的回收
*/
private HashMap<String, SoftReference<Drawable>> imageCache;
public AsyncImageLoader(){
imageCache = new HashMap<String, SoftReference<Drawable>>();
}
/**
* 通过传入的TagInfo来获取一个网络上的图片
* @param tag TagInfo对象,保存了position、url和一个待获取的Drawable对象
* @param callback ImageCallBack对象,用于在获取到图片后供调用侧进行下一步的处理
* @return drawable 从网络或缓存中得到的Drawable对象,可为null,调用侧需判断
*/
public Drawable loadDrawableByTag(final TagInfo tag, final ImageCallBack callback){
Drawable drawable;
/**
* 先在缓存中找,如果通过URL地址可以找到,则直接返回该对象
*/
if(imageCache.containsKey(tag.getUrl())){
drawable = imageCache.get(tag.getUrl()).get();
if(null!=drawable){
return drawable;
}
}
/**
* 用于在获取到网络图片后,保存图片到缓存,并触发调用侧的处理
*/
final Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
TagInfo info = (TagInfo)msg.obj;
imageCache.put(info.url, new SoftReference<Drawable>(info.drawable));
callback.obtainImage(info);
super.handleMessage(msg);
}
};
/**
* 如果在缓存中没有找到,则开启一个线程来进行网络请求
*/
new Thread(new Runnable() {
@Override
public void run() {
TagInfo info = getDrawableIntoTag(tag);
Message msg = new Message();
msg.what = 0;
msg.obj = info;
handler.sendMessage(msg);
}
}).start();
return null;
}
/**
* 通过传入的TagInfo对象,利用其URL属性,到网络请求图片,获取到图片后保存在TagInfo的Drawable属性中,并返回该TagInfo
* @param info TagInfo对象,需要利用里面的url属性
* @return TagInfo 传入的TagInfo对象,增加了Drawable属性后返回
*/
public TagInfo getDrawableIntoTag(TagInfo info){
URL request;
InputStream input;
Drawable drawable = null;
try{
request = new URL(info.getUrl());
input = (InputStream)request.getContent();
drawable = Drawable.createFromStream(input, "src"); // 第二个属性可为空,为DEBUG下使用,网上的说明
}
catch(Exception e){
e.printStackTrace();
}
info.drawable = drawable;
return info;
}
/**
* 获取图片的回调接口,里面的obtainImage方法在获取到图片后进行调用
*/
//interface类是让别的类继承的,如果没有类继承就没意义了,所以你不能用private(私有的)、protected(受保护的)来修饰它。如果修饰了别的类都没法继承它啦,就没意义啦interface类是让别的类继承的,如果没有类继承就没意义了,所以你不能用private(私有的)、protected(受保护的)来修饰它。如果修饰了别的类都没法继承它啦,就没意义啦
interface ImageCallBack{
/**
* 获取到图片后在调用侧执行具体的细节
* @param info TagInfo对象,传入的info经过处理,增加Drawable属性,并返回给传入者
*/
public void obtainImage(TagInfo info);
}
}
ImageEntry:
/**
* 一个ImageEntry代表了一个带有图片地址url等其他属性的实例,为提高可扩展性,封装了一个对象。
*/
public class ImageEntry{
String url;
String name;
String time;
String title;
Long id;
public String getUrl(){
return this.url;
}
public String getName(){
return this.name;
}
public String getTime(){
return this.time;
}
public String getTitle(){
return this.title;
}
public Long getId(){
return this.id;
}
public void setid(Long id){
this.id = id;
}
public void seturl(String url){
this.url = url;
}
public void settime(String time){
this.time = time;
}
public void settitle(String title){
this.title = title;
}
}
MyAdapter:
/**
* 重写的Adapter
*/
public class MyAdapter extends BaseAdapter {
Context context;
List<ImageEntry> mList;
XListView xlist_lv;
HashMap<String, Drawable> imgCache; // 图片缓存
HashMap<Integer, TagInfo> tag_map; // TagInfo缓存
AsyncImageLoader loader; // 异步加载图片类
/**
* 构造函数
* @param context 上下文
* @param list 包含了所有要显示的图片的ImageEntry对象的列表
*/
public MyAdapter(Context context, List<ImageEntry> list){
this.context = context;
this.mList = list;
imgCache = new HashMap<String, Drawable>();
loader = new AsyncImageLoader();
tag_map = new HashMap<Integer, TagInfo>();
}
//获取当前items项的大小,也可以看成是数据源的大小
//getCount决定了listview一共有多少个item
@Override
public int getCount() {
// TODO Auto-generated method stub
return mList.size();
}
//根据item的下标获取到View对象
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return mList.get(position);
}
//获取到items的id,对应onItemClick中long的na参数
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return mList.get(position).getId();
// return 0;
}
//根据传入item的下标,获取到view对象
/*
* int position, 表示item所在listView中的下标,也是在数据源中下标所对应的数据
* View convertView, 缓存机制,当一些item项滑出屏幕的时候,会创建新的View对象,这样会使得内存资源占据,
* 所以使用convertView判断是否为空,如果为空的说明item没有滑出,需要创建新的view对象
* 如果不为空,说明已经滑出类屏幕所以使用convertView ,view = convertView,
* 可以把convert 理解为滑出的view对象
* ViewGroup parent 视图组对象,即 表示当前绘制的items项所属的ListView对象。
* */
//getView返回了每个item项所显示的view
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder = null;
if(null==convertView){
convertView = LayoutInflater.from(context).inflate(R.layout.item, null, false);
holder = new ViewHolder();
holder.img = (ImageView) convertView.findViewById(R.id.logo);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
String imgurl = mList.get(position).getUrl(); // 得到该项所代表的url地址
Drawable drawable = imgCache.get(imgurl); // 先去缓存中找
TagInfo tag = new TagInfo();
tag.setPosition(position); // 保存了当前在adapter中的位置
tag.setUrl(imgurl); // 保存当前项所要加载的url
holder.img.setTag(tag); // 为ImageView设置Tag,为以后再获取图片后好能找到它
tag_map.put(position, tag); // 把该TagInfo对应position放入Tag缓存中
//为列表的文本赋值
//TextView ItemName = (TextView) convertView.findViewById(R.id.name);
//ItemName.setText(mList.get(position).getName());
TextView ItemTime = (TextView) convertView.findViewById(R.id.time);
ItemTime.setText(mList.get(position).getTime());
//TextView ItemTitle = (TextView) convertView.findViewById(R.id.title);
//ItemTitle.setText(mList.get(position).getTitle());
if(null!=drawable){ // 找到了直接设置为图像
holder.img.setImageDrawable(drawable);
}else{ // 没找到则开启异步线程
drawable = loader.loadDrawableByTag(tag, new ImageCallBack() {
@Override
public void obtainImage(TagInfo ret_info) {
imgCache.put(ret_info.getUrl(), ret_info.getDrawable()); // 首先把获取的图片放入到缓存中
// 通过返回的TagInfo去Tag缓存中找,然后再通过找到的Tag来获取到所对应的ImageView
ImageView tag_view = (ImageView) xlist_lv.findViewWithTag(tag_map.get(ret_info.getPosition()));
Log.i("carter", "tag_view: " + tag_view + " position: " + ret_info.getPosition());
if(null!=tag_view)
{
tag_view.setImageDrawable(ret_info.getDrawable());
notifyDataSetChanged();//这样可以在fragement中实现 异步更新图片
}
}
});
if(null==drawable){ // 如果获取的图片为空,则默认显示一个图片
holder.img.setImageResource(R.drawable.nv);
}
}
return convertView;
}
class ViewHolder{
ImageView img;
}
public void SetXListView(XListView XListView){
this.xlist_lv=XListView;
}
}
TagInfo
public class TagInfo {
String url;
int position;
Drawable drawable;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
public Drawable getDrawable() {
return drawable;
}
public void setDrawable(Drawable drawable) {
this.drawable = drawable;
}
}
view中的3个java可以去github下载我项目中没有修改过:
https://github.com/Maxwin-z/XListView-Android
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.what.xlistview.MainActivity">
<com.example.what.xlistview.view.XListView
android:id="@+id/xlistview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cacheColorHint="#00000000"
android:scrollbars="none" />
</RelativeLayout>
item.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/box1"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/box2"
android:layout_width="match_parent"
android:layout_height="120dp"
>
<LinearLayout
android:id="@+id/textbox"
android:layout_width="280dp"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/photo"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="10dp"
/>
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:textSize="16dp"
/>
<TextView
android:id="@+id/time"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginLeft="10dp"
android:textSize="12dp"
android:layout_marginTop="5dp"
android:textColor="#999"
/>
</LinearLayout>
<LinearLayout
android:layout_width="280dp"
android:layout_height="wrap_content"
android:layout_below="@+id/textbox"
android:layout_marginTop="15dp"
>
<TextView
android:id="@+id/title"
android:layout_width="230dp"
android:layout_height="60dp"
android:layout_marginLeft="10dp"
/>
</LinearLayout>
<ImageView
android:id="@+id/logo"
android:layout_width="100dp"
android:layout_height="80dp"
android:layout_marginTop="20dp"
android:layout_marginRight="10dp"
android:layout_alignParentRight="true"
/>
</RelativeLayout>
</RelativeLayout>
head_view.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="@drawable/headiv" />
</LinearLayout>
xlistview_footer.xml和xlistview_header.xml,strings.xml也是github中的
权限方面只要有 <uses-permissionandroid:name="android.permission.INTERNET"/>
项目下载地址:http://download.csdn.net/download/qq_34819586/9961558