一步一步实现ListView加载网络数据,下滑底部加载,顶部下拉刷新

本文详细介绍了如何在Android应用中实现ListView的下拉刷新和加载更多功能,通过网络请求获取数据并更新列表。主要涉及网络请求、JSON解析、数据适配器和ListView滚动监听等技术。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import org.json.JSONArray;

import org.json.JSONException;

import org.json.JSONObject;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.UnsupportedEncodingException;

import java.net.MalformedURLException;

import java.net.URL;

import java.util.ArrayList;

import java.util.List;

public class MainActivity extends Activity {

private final static String TAG = “zxt/MainActivity”;

private final String Url = “http://www.imooc.com/api/teacher?type=4&num=30”;

List mNewsDatas = null;

private RefreshListView mListView ;

private TextView mNoDatas;

//下拉数据刷新 改写数组为集合

//public static String[] urls; public static List urls;

//下拉数据刷新

private NewsAdapter mNewsAdapter;

//

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mListView = (RefreshListView) findViewById(R.id.listView1);

mNoDatas = (TextView) findViewById(R.id.tv_nodatas);

new NewTask().execute(Url);

}

//下拉刷新数据

/* public interface IRefreshCompleteListener{

public void onRefreshComplete(); } private IRefreshCompleteListener mRefreshComplete; public void IRefreshCompleteListener(IRefreshCompleteListener listener){ mRefreshComplete = listener; }*/ public void refreshData(RefreshListView listview){

//获取最新数据

setReflashData();

//֪ͨ������ʾ

//mRefreshComplete.onRefreshComplete();

}

//下拉刷新

private int newDataslength ;

private void setReflashData() {

new DownPullTask().execute(Url);

//执行更新 start

/*NewsBean bean = new NewsBean(); bean.NewsNo = “31”; bean.NewsName = “new Name”; bean.NewsDescription = “new Des”; bean.NewsPicResUrl = Math.random()>0.5? “https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png” : “https://img-my.youkuaiyun.com/uploads/201407/26/1406383291_6518.jpg”;*/

//执行更新 end

}

private void showList(List apk_list) {

//NewsAdapter adapter = (NewsAdapter) mListView.getAdapter();

/*if (adapter == null) { listview = (ReFlashListView) findViewById(R.id.listview); listview.setInterface(this); adapter = new MyAdapter(this, apk_list); listview.setAdapter(adapter); } else {*/ if(mNewsAdapter!=null)

mNewsAdapter.onDateChange(apk_list);

//}

}

private class DownPullTask extends AsyncTask<String,Void,List>{

@Override

protected List doInBackground(String… params) {

Log.i(TAG,“NewTask:doInBackground”);

return getDataByUrl(params[0]);

}

@Override

protected void onPostExecute(List newsBeens) {

super.onPostExecute(newsBeens);

//fix bug if first nodata

//更新了几条数据 if(null!=newsBeens){

newDataslength = newsBeens.size();

if(null==mNewsDatas ){

mNewsDatas = new ArrayList();

}

mNewsDatas.addAll(0,newsBeens);

showList(mNewsDatas);

//֪ͨlistview ˢ�������ϣ�

}else{

newDataslength = 0;

}

mNewsAdapter.refreshComplete(newDataslength);

setHintVisibility(newsBeens);

Log.i(TAG,“NewTask:onPostExecute:”+newDataslength);

Toast.makeText(MainActivity.this,“成功更新”+newDataslength+“条新闻”,Toast.LENGTH_SHORT).show();

}

}

//下拉刷新 end

class NewTask extends AsyncTask<String, Void, List> {

@Override

protected List doInBackground(String… params) {

return getDataByUrl(params[0]);

}

@Override

protected void onPostExecute(List result) {

super.onPostExecute(result);

//下拉刷新

mNewsAdapter= new NewsAdapter(MainActivity.this, result,mListView);

//下拉刷新

mListView.setAdapter(mNewsAdapter);

mListView.setOnScrollListener(mNewsAdapter);

// 处理下拉刷新

mListView.setOnTouchListener(mNewsAdapter);

mNewsDatas = result;

// 处理下拉刷新

//刷新回调 mNewsAdapter.setIRefereshListener(new IRefereshListener() {

@Override

public void onRefresh() {

mListView.postDelayed(new Runnable() {

@Override

public void run() {

refreshData(mListView);

}

}, 1000);

}

});

//刷新回调

setHintVisibility(result);

//加载更多begin

mNewsAdapter.setIOnScrollBottomListener(new NewsAdapter.IOnScrollBottomListener() {

@Override

public void onScrollBottom() {

mListView.postDelayed(new Runnable() {

@Override

public void run() {

//加载数据

loadMoreData();

mNewsAdapter.bottomDataLoadComplete();

}

}, 3000);

}

});

//加载更多end

}

}

//加载更多begin

private int index =100;

private void loadMoreData(){

NewsBean bean = new NewsBean();

bean.NewsNo = “”+index++;

bean.NewsPicResUrl = “https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png”;

/*List datas = mNewsAdapter.getDatas();

datas.add(-1,bean);*/ mNewsAdapter.setData(-1,bean);

mNewsAdapter.notifyDataSetChanged();

}

//加载更多end

private void setHintVisibility(List result) {

mNoDatas.setVisibility(result==null? View.VISIBLE:View.GONE);

}

public List getDataByUrl(String url) {

List datas = null;

try {

String jsonString = readStream(new URL(url).openStream());

datas = parseJson(jsonString);

//Log.i(“zxt”, “jsonString:”+jsonString);

} catch (MalformedURLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

return datas;

}

private List parseJson(String jsonString) {

try {

JSONObject jsonObject = new JSONObject(jsonString);

JSONArray jsonArray = jsonObject.getJSONArray(“data”);

JSONObject data = null;

List datas = new ArrayList();

NewsBean bean = null;

//处理下拉刷新加入

if(null==urls){

urls = new ArrayList();

}

List tempUrls = new ArrayList();

//处理下拉刷新加入

for (int i = 0; i < jsonArray.length(); i++) {

data = (JSONObject) jsonArray.get(i);

bean = new NewsBean();

bean.NewsPicResUrl = data.getString(“picSmall”);

//处理下拉刷新加入

tempUrls.add(bean.NewsPicResUrl);

//处理下拉刷新加入

bean.NewsName = data.getString(“name”);

bean.NewsDescription = data.getString(“description”);

bean.NewsNo = data.getString(“id”);

//加载大图加入

bean.NewsPicBigResUrl = data.getString(“picBig”);

//加载大图加入

datas.add(bean);

}

//处理下拉刷新加入 将新的url 加入到最上方

urls.addAll(0,tempUrls);

//处理下拉刷新加入

return datas;

} catch (JSONException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

return null;

}

private String readStream(InputStream is) {

StringBuilder jsonString = new StringBuilder();

try {

String line = “”;

InputStreamReader isr = new InputStreamReader(is, “utf-8”);

BufferedReader br = new BufferedReader(isr);

if (null != (line = br.readLine())) {

jsonString.append(line);

}

} catch (UnsupportedEncodingException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

return jsonString.toString();

}

}

package com.example.asynctaskdemo;

import android.animation.Animator;

import android.animation.AnimatorListenerAdapter;

import android.animation.ValueAnimator;

import android.animation.ValueAnimator.AnimatorUpdateListener;

import android.content.Context;

import android.content.Intent;

import android.graphics.Bitmap;

import android.util.Log;

import android.view.LayoutInflater;

import android.view.MotionEvent;

import android.view.View;

import android.view.View.OnClickListener;

import android.view.View.OnTouchListener;

import android.view.ViewGroup;

import android.widget.AbsListView;

import android.widget.AbsListView.OnScrollListener;

import android.widget.BaseAdapter;

import android.widget.ImageView;

import android.widget.ProgressBar;

import android.widget.TextView;

import android.widget.Toast;

import java.util.List;

public class NewsAdapter extends BaseAdapter implements OnScrollListener,

OnTouchListener {

private static final String TAG = “zxt/NewsAdapter”;

private volatile List mDatas;

private LayoutInflater mInflater;

private RefreshListView mListView;

private Context mContext;

// 网络图片加载

public List getDatas() {

return mDatas;

}

public void setDatas(List mDatas) {

this.mDatas = mDatas;

}

public void setData(int pos, NewsBean bean) {

if (-1 != pos) {

mDatas.add(pos, bean);

MainActivity.urls.add(pos, bean.NewsPicResUrl);

} else {

mDatas.add(bean);

MainActivity.urls.add(bean.NewsPicResUrl);

}

}

private ImageLoader mImageLoader;

public NewsAdapter(Context context, List mDatas, RefreshListView listView) {

super();

mContext = context;

this.mDatas = mDatas;

this.mInflater = LayoutInflater.from(context);

//抽象成单例后改写 begin

//mImageLoader = new ImageLoader(listView); mImageLoader = ImageLoader.getInstance(context);

mImageLoader.setmListView(listView);

//抽象成单例后改写 end

mListView = listView;

initHeaderView();

initFooterView();

}

private void initFooterView() {

mFooterView = mListView.getFooterView();

}

//下拉刷新数据

public void onDateChange(List mDatas) {

this.mDatas = mDatas;

this.notifyDataSetChanged();

}

//下拉刷新数据

private void initHeaderView() {

headerView = mListView.findViewById(R.id.headerview);

// 获取View高度

headerHeight = mListView.getHeaderHeight();

mTipView = (TextView) headerView.findViewById(R.id.tip);

mTimeView = (TextView) headerView.findViewById(R.id.lastupdate_time);

mArrowView = (ImageView) headerView.findViewById(R.id.arrow);

mBar = (ProgressBar) headerView.findViewById(R.id.progress);

}

@Override

public int getCount() {

if (mDatas != null)

return mDatas.size();

return 0;

}

@Override

public Object getItem(int position) {

// TODO Auto-generated method stub

return mDatas.get(position);

}

@Override

public long getItemId(int position) {

// TODO Auto-generated method stub

return position;

}

@Override

public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder holder = null;

if (convertView == null) {

//Log.i(TAG, “getView->缓存为空:” + position);

holder = new ViewHolder();

convertView = mInflater.inflate(R.layout.item, parent, false);

holder.pic = (ImageView) convertView.findViewById(R.id.iv_pic);

holder.no = (TextView) convertView.findViewById(R.id.tv_no);

holder.name = (TextView) convertView.findViewById(R.id.tv_name);

holder.description = (TextView) convertView

.findViewById(R.id.tv_description);

convertView.setTag(holder);

} else {

//Log.i(TAG, “getView->缓存过:” + position);

holder = (ViewHolder) convertView.getTag();

}

NewsBean bean = mDatas.get(position);

// 加载网络图片

holder.pic.setTag(bean.NewsPicResUrl);

// mImageLoader.getImageByAsyncTask(holder.pic, bean.NewsPicResUrl);

holder.pic.setImageResource(R.drawable.ic_launcher);

// 滑动优化 如果有缓存,则加载 否则不加载

final Bitmap pBitmap = mImageLoader.setDefaultBitmap(holder.pic, bean.NewsPicResUrl);

// /滑动优化

holder.name.setText(bean.NewsName);

holder.description.setText(bean.NewsDescription);

holder.no.setText(bean.NewsNo);

//添加事件点击 2015 12 24

final String urlBig = bean.NewsPicBigResUrl;

final String urlSmall = bean.NewsPicResUrl;

holder.pic.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

Toast.makeText(v.getContext(), “bean.NewsNo:” + urlBig, Toast.LENGTH_SHORT).show();

Intent intent = new Intent(mContext, BigImageActivity.class);

intent.putExtra(“urlBig”, urlBig);

intent.putExtra(“urlSmall”, urlSmall);

mContext.startActivity(intent);

}

});

//

return convertView;

}

class ViewHolder {

public ImageView pic;

public TextView name;

public TextView description;

public TextView no;

}

// 滚动时的优化 begin

private int mStart, mEnd;

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

if (scrollState == SCROLL_STATE_IDLE) {

Log.i(TAG, “scrollState:” + mStart + “-” + mEnd);

loadImages();

} else {

Log.i(TAG, “scrollState cancel:”);

mImageLoader.cancelAllTasks();

}

}

private void loadImages() {

if (null != mDatas && mDatas.size() > 0) {

//修复bug 滑动时边缘不加载 begin

int start = mStart != 0 ? mStart - 1 : 0;

int end = mEnd != mDatas.size() ? mEnd + 1 : mEnd;

//修复bug 滑动时边缘不加载 end

mImageLoader.loadImages(start, end);

}

}

private boolean isInit = true;

//加载更多 begin

private boolean isLoading = false;

private View mFooterView;

public interface IOnScrollBottomListener {

void onScrollBottom();

}

private IOnScrollBottomListener mIOnScrollBottomListener;

public void setIOnScrollBottomListener(IOnScrollBottomListener onScrollBottomListener) {

mIOnScrollBottomListener = onScrollBottomListener;

}

public void bottomDataLoadComplete() {

//隐藏view 加载数据 改变flag

mFooterView.setVisibility(View.GONE);

isLoading = false;

}

//加载更多 end

@Override

public void onScroll(AbsListView view, int firstVisibleItem,

int visibleItemCount, int totalItemCount) {

Log.i(TAG, “onScroll():totalItemCount” + totalItemCount + " ,isLoading:" + isLoading + “, firstVisibleItem:”

+ firstVisibleItem + " ,visibleItemCount:" + visibleItemCount + “, totalItemCount:” + totalItemCount);

mStart = firstVisibleItem;

//其实现在的listview看不到那么多 应该-1 否则最后会空指针 2015 12 24 (因为我们add了一个headerview进去) 20151228 add 了 footview 所以再-1

mEnd = mStart + visibleItemCount - 1 - 1;

if (visibleItemCount != 0 && isInit) {

isInit = false;

loadImages();

}

//处理滑动加载更多: 2 != totalItemCount 防止没有数据一直在加载更多

if (2 != totalItemCount && firstVisibleItem + visibleItemCount == totalItemCount && !isLoading) {

isLoading = true;

mFooterView.setVisibility(View.VISIBLE);

//执行加载更多操作

if (null != mIOnScrollBottomListener) {

mIOnScrollBottomListener.onScrollBottom();

}

}

}

// 滚动时的优化 end

// 处理下拉刷新 private int lastY;

private View headerView;

private TextView mTipView;

private TextView mTimeView;

private ImageView mArrowView;

private ProgressBar mBar;

private int headerHeight;

private int gap;

public interface IRefereshListener {

public void onRefresh();

}

private IRefereshListener mRefereshListener;

public void setIRefereshListener(IRefereshListener listener) {

this.mRefereshListener = listener;

}

//监听执行完毕 继续滚动

public void refreshComplete(int length) {

Log.i(TAG, “refreshComplete()”);

//其实这里的mStarat =0的

mImageLoader.loadImages(mStart, mStart + length);

rollToInit(1);

}

@Override

public boolean onTouch(View v, MotionEvent event) {

if (mStart == 0 && isMoveEnable) {

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

lastY = (int) event.getY();

//初始化 几个view的状态显示

mTipView.setText(“下拉可以刷新”);

mArrowView.setVisibility(View.VISIBLE);

mBar.setVisibility(View.GONE);

//初始化 几个view的状态显示

break;

case MotionEvent.ACTION_MOVE:

gap = (int) (event.getY() - lastY);

Log.i(TAG, " ACTION_MOVE gap:" + gap);

//移动View

setPaddingTop(-headerHeight + gap);

//下拉可以刷新(超过宽度)-》松开可以刷新-》

if (gap > headerHeight) {

mTipView.setText(“松开可以刷新”);

}

//下拉可以刷新(超过宽度)-》松开可以刷新-》

break;

case MotionEvent.ACTION_UP:

//松开-》滑动到View宽度-》

if (gap > headerHeight) {

rollToInit(0);

//正在刷新-》

mTipView.setText(“正在刷新”);

mArrowView.setVisibility(View.GONE);

mBar.setVisibility(View.VISIBLE);

//执行刷新操作

if (mRefereshListener != null) {

mRefereshListener.onRefresh();

}

//执行刷新操作

//松开-》滑动到View宽度-》 } else {

//恢复初始。

rollToInit(1);

}

break;

default:

break;

}

Log.i(TAG, “lastY:” + lastY + “headerHeight:” + headerHeight);

}

return false;

}

private boolean isMoveEnable = true;

private void rollToInit(int endTop) {

//回去的动画://使用ObjectAnimator 不好实现, 打算用ValueAnimator

/*ObjectAnimator animator = ObjectAnimator.ofFloat(mListView, “Y”,-(headerView.getPaddingTop()+headerHeight)); animator.setDuration(500).start();*/ isMoveEnable = false;

int top = headerView.getPaddingTop();

//解决 拖动不超过headerheight 不会滑动回去的bug

int end = top > 0 ? -(top + headerHeight) : -(top + headerHeight + headerHeight);

Log.i(TAG, “rollToInit:” + endTop + " ,top:" + top + ", -(top+headerHeight) " + (-(top + headerHeight)));

ValueAnimator animator = ValueAnimator.ofInt(top, endTop == 1 ? end : endTop);

animator.addUpdateListener(new AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

Integer paddingTop = (Integer) animation.getAnimatedValue();

setPaddingTop(paddingTop);

}

});

//添加动画完成监听器

animator.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationEnd(Animator animation) {

super.onAnimationEnd(animation);

isMoveEnable = true;

}

});

//添加动画完成监听器

animator.setDuration(500).start();

}

private void setPaddingTop(int top) {

if (null != headerView) {

headerView.setPadding(headerView.getPaddingLeft(), top, headerView.getPaddingRight(), headerView.getPaddingBottom());

}

}

}

package com.example.asynctaskdemo;

public class NewsBean {

public String NewsPicResUrl;

public String NewsPicBigResUrl;

public String NewsName;

public String NewsDescription;

public String NewsNo;

}

package com.example.asynctaskdemo;

import android.content.Context;

import android.util.AttributeSet;

import android.util.Log;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

public class RefreshListView extends android.widget.ListView {

private final static String TAG =“zxt/refreshListView”;

private View headerView ;

private View footerView;

public View getFooterView() {

return footerView;

}

/*public void bottomDataLoadComplete(){

//隐藏view 加载数据 改变flag footerView.setVisibility(View.GONE); }*/

private int headerHeight;

public int getHeaderHeight() {

return headerHeight;

}

public RefreshListView(Context context) {

this(context, null);

}

public RefreshListView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

initView(context);

}

private void initView(Context context) {

headerView = LayoutInflater.from(context).inflate(R.layout.header,null);

this.addHeaderView(headerView);

// 测量View

headerView.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);

// 获取View高度

headerHeight = headerView.getMeasuredHeight();

Log.d(TAG, “headerHeight:”+headerHeight);

//设置默认隐藏

setPaddingTop(-headerHeight);

//上啦刷新

View footerView = LayoutInflater.from(context).inflate(R.layout.footer_layout,this,false);

this.addFooterView(footerView);

this.footerView = footerView.findViewById(R.id.load_layout);

this.footerView.setVisibility(View.GONE);

}

private void setPaddingTop(int top){

if(null!=headerView){

headerView.setPadding(headerView.getPaddingLeft(), top, headerView.getPaddingRight(), headerView.getPaddingBottom());

}

}

}

package com.example.asynctaskdemo;

import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.os.AsyncTask;

import android.support.annotation.Nullable;

import android.support.v4.util.LruCache;

import android.util.Log;

import android.view.View;

import android.widget.ImageView;

import android.widget.ListView;

import android.widget.ProgressBar;

import com.example.asynctaskdemo.com.mcxtzhang.utils.FileUtils;

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.File;

import java.io.FileDescriptor;

i

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

mport java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.HttpURLConnection;

import java.net.MalformedURLException;

import java.net.URL;

import java.util.HashSet;

import java.util.Set;

import libcore.io.DiskLruCache;

public class ImageLoader {

private static final String TAG = “zxt/ImageLoader”;

//抽象成单例 begin

private static class ImageLoaderHolder {

private static final ImageLoader mImageLoader = new ImageLoader();

}

private static Context mContext;

public static ImageLoader getInstance(Context context){

mContext = context.getApplicationContext();

return ImageLoaderHolder.mImageLoader;

}

private ImageLoader() {

super();

Log.i(“TAG”,“ImageLoader”);

int maxMemory = (int) Runtime.getRuntime().maxMemory();

mCache = new LruCache<String, Bitmap>(maxMemory / 20) {

@Override

protected int sizeOf(String key, Bitmap value) {

return value.getByteCount();

}

};

//硬盘缓存 begin

//初始化工作 File cacheDir = FileUtils.getFileCache(mContext, “disk_caches”);

if (!cacheDir.exists()) {

cacheDir.mkdirs();

}

try {

mDiskCache = DiskLruCache.open(cacheDir, 1, 1, 10 * 1024 * 1024);

} catch (IOException e) {

e.printStackTrace();

}

//硬盘缓存 end

mSets = new HashSet();

}

//抽象成单例 end

//图片缓存 start private LruCache<String,Bitmap> mCache;

//硬盘缓存

private DiskLruCache mDiskCache;

public Bitmap getBitmapFromCache(String url){

Log.i(TAG, “getBitmapFromCache”);

return mCache.get(url);

}

public void putBitmapToCache(String url,Bitmap bitmap){

Log.i(TAG, “putBitmapToCache”);

if(null == getBitmapFromCache(url)){

mCache.put(url, bitmap);

}

}

//图片缓存 end

public void getImageByAsyncTask(ImageView imageView,String url){

//图片缓存 start

Bitmap bitmap = getBitmapFromCache(url);

if(null == bitmap)

{

new NewsImageAsyncTask(/*imageView,*/url).execute();

}

else{

imageView.setImageBitmap(bitmap);

}

//图片缓存 end

}

//每次加载一张图片

private class NewsImageAsyncTask extends AsyncTask<Void,Void,Bitmap>{

//private ImageView mImageView ;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值