你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

一步一步实现ListView加载网络数据,下滑底部加载,顶部下拉刷新,安卓面试项目源码

2021/12/6 6:36:16

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;

import 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 ;

private String mUrl;

public NewsImageAsyncTask(/*ImageView mImageView,*/String url) {

super();

//this.mImageView = mImageView;

mUrl = url;

}

@Override

protected Bitmap doInBackground(Void… params) {

//硬盘缓存

// 用了二级缓存 所以要改写获取图片的流程: /*Bitmap result = getBitmapByUrl(mUrl); Log.i(TAG, “isCancelled:”+isCancelled()); //内存缓存 start putBitmapToCache(mUrl, result); //内存缓存end*/ return getBitmapAndSaveToCacheByUrl(mUrl);

}

@Override

protected void onPostExecute(Bitmap result) {

super.onPostExecute(result);

//设置图片 防止错位

/*if(mUrl.equals(mImageView.getTag())){ mImageView.setImageBitmap(result); }*/ //滑动优化 ImageView imageView = (ImageView) mListView.findViewWithTag(mUrl);

if(imageView!=null && null != result)

{

imageView.setImageBitmap(result);

}

mSets.remove(this);

//滑动优化

}

}

public Bitmap getBitmapByUrl(String string) {

InputStream is1=null/*,is2 = null*/;

Bitmap result = null;

try {

HttpURLConnection conn = (HttpURLConnection) new URL(string).openConnection();

is1 = new BufferedInputStream(conn.getInputStream());

//优化图片加载 begin

/*ByteArrayOutputStream out = new ByteArrayOutputStream(); ImageUtils.copy(is1,out); is2 = new ByteArrayInputStream(out.toByteArray());*/

result = BitmapFactory.decodeStream(is1);

//result = ImageUtils.decodeSuitableBitmap(is,60,60);

//result = ImageUtils.decodeSuitableBitmap(string,1,1);

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

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

//Log.i(TAG,“resutl size:”+result.getByteCount());

//result = ImageUtils.decodeSampledBitmapFromInputStream(is1,is2,1,1); Log.i(TAG,“resutl size:”+(result !=null?result.getByteCount():“null”));

/*if (result==null){

Log.i(TAG,“result==null”); }*/ //Log.i(TAG,“result=”+result); //优化图片加载 end

conn.disconnect();

} catch (MalformedURLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally{

try {

if(is1!=null){

is1.close();

}

/*if(is2!=null){

is2.close(); }*/ } catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

return result;

}

//滚动时的优化 begin

private static Set mSets ;

private ListView mListView;

public ListView getmListView() {

return mListView;

}

public void setmListView(ListView mListView) {

this.mListView = mListView;

}

public void loadImages(int mStart, int mEnd) {

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

for (int i = mStart; i < mEnd; i++) {

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

String url = MainActivity.urls.get(i);

Bitmap bm = getBitmapFromCache(url);

ImageView mImageView = (ImageView)mListView.findViewWithTag(url);

if(null!=bm && null!= mImageView){

mImageView.setImageBitmap(bm);

}

else{//重新下载

NewsImageAsyncTask task = new NewsImageAsyncTask(url);

mSets.add(task);

task.execute();

}

}

}

public void cancelAllTasks() {

if(mSets!=null){

for (NewsImageAsyncTask task : mSets) {

task.cancel(false);

}

}

}

//看缓存中是否有 有则设置 没有则默认图片不管

public Bitmap setDefaultBitmap(ImageView pic, String newsPicResUrl) {

Bitmap bm = getBitmapFromCache(newsPicResUrl);

if(null!=bm){

pic.setImageBitmap(bm);

}

return bm;

}

//滚动时的优化 end

//硬盘缓存 加载图片方法(不返回bitmap,为了通用,不仅仅保存图片) 并写入硬缓存 begin private static boolean getBitmapUrlToStream(String urlString, OutputStream outputStream) {

HttpURLConnection urlConnection = null;

BufferedOutputStream out = null;

BufferedInputStream in = null;

try {

final URL url = new URL(urlString);

urlConnection = (HttpURLConnection) url.openConnection();

in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);

out = new BufferedOutputStream(outputStream, 8 * 1024);

int b;

while ((b = in.read()) != -1) {

out.write(b);

}

return true;

} catch (final IOException e) {

e.printStackTrace();

} finally {

if (urlConnection != null) {

urlConnection.disconnect();

}

try {

if (out != null) {

out.close();

}

if (in != null) {

in.close();

}

} catch (final IOException e) {

e.printStackTrace();

}

}

return false;

}

//硬盘缓存 加载图片方法 end

//硬盘缓存 下载图片 存入缓存(SD ,内存都存入)方法 begin

@Nullable

private Bitmap getBitmapAndSaveToCacheByUrl(String mUrl) {

String key = FileUtils.toMD5String(mUrl);

FileDescriptor fileDescriptor = null;

FileInputStream fileInputStream = null;

DiskLruCache.Snapshot snapShot = null;

try {

//尝试获取硬缓存里的数据

snapShot = mDiskCache.get(key);

//如果没有缓存

if (snapShot == null) {

//尝试读从网络取并写入

DiskLruCache.Editor editor = mDiskCache.edit(key);

if (editor != null) {

OutputStream outputStream = editor.newOutputStream(0);

if (getBitmapUrlToStream(mUrl, outputStream)) {

editor.commit();

} else {

editor.abort();

}

}

//再次读取

snapShot = mDiskCache.get(key);

}

if (snapShot != null) {

fileInputStream = (FileInputStream) snapShot.getInputStream(0);

fileDescriptor = fileInputStream.getFD();

}

//利用读取的硬盘数据,生成bitmap

Bitmap bitmap = null;

if (fileDescriptor != null) {

bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);

}

//利用bitmap 存入内存缓存

if (bitmap != null) {

putBitmapToCache(mUrl, bitmap);

}

//返回bitmap

return bitmap;

} catch (IOException e) {

e.printStackTrace();

} finally {

if (fileDescriptor == null && fileInputStream != null) {

try {

fileInputStream.close();

} catch (IOException e) {

}

}

}

return null;

}

//end

//加载大图

public void loadBigBitmap(String url, ImageView imageView, ProgressBar mProgressBar){

if(imageView!=null && null!= url){

new BigImageAsyncTask(imageView,mProgressBar).execute(url);

}

}

private class BigImageAsyncTask extends AsyncTask<String,Void,Bitmap> {

private ImageView mImageView;

private ProgressBar mProgressBar;

public BigImageAsyncTask(ImageView imageView, ProgressBar progressBar) {

mImageView = imageView;

mProgressBar = progressBar;

}

@Override

protected Bitmap doInBackground(String… params) {

return getBitmapByUrl(params[0]);

}

@Override

protected void onPostExecute(Bitmap bitmap) {

super.onPostExecute(bitmap);

if(bitmap!=null)

mImageView.setImageBitmap(bitmap);

if(null!=mProgressBar){

mProgressBar.setVisibility(View.GONE);

}

}

}

}

package com.example.asynctaskdemo;

import android.app.Activity;

import android.content.Intent;

import android.graphics.Bitmap;

import android.os.Bundle;

import android.util.Log;

import android.widget.ImageView;

import android.widget.ProgressBar;

/**

* Created by zhangxutong on 2015/12/25. */

public class BigImageActivity extends Activity{

private ImageView mBigImageView;

private ProgressBar mProgressBar;

private ImageLoader mImageLoader;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_bigimage);

initView();

mImageLoader = ImageLoader.getInstance(BigImageActivity.this);

Intent intent = getIntent() ;

String urlBig = intent.getStringExtra(“urlBig”);

String urlSmall = intent.getStringExtra(“urlSmall”);

//设置初始值

if(null!=urlSmall) {

Bitmap bitmap = mImageLoader.getBitmapFromCache(urlSmall);

Log.i(“TAG”,“urlSmall:”+urlSmall+", bitmap:"+bitmap);

if(null!=bitmap){

mBigImageView.setImageBitmap(bitmap);

}

}