一步一步实现ListView加载网络数据,下滑底部加载,顶部下拉刷新。并配有双缓存
来源:互联网 发布:淘宝客推广流程 编辑:程序博客网 时间:2024/04/18 20:15
随便扯扯1,我比较喜欢把判断写成 常量在前,变量在后的形式,主要是由于这样可以规避粗心引起的错误。
例如 0 == mLength ,可以规避不小心写成mLength = 0;因为书写成 0= mLength会报错,而mLength = 0 不会报错。
若引起阅读不便,请包涵。
今天我们计划要实现一个装满数据的ListView,并且在顶部下拉可以刷新,下滑到底部可以加载更多。分析需求,第一件事就是要将ListView装满数据,那么这个数据从哪里来?从网络来,所以第一件事就是将网络数据下载下来。因此先添加权限:
<uses-permission android:name="android.permission.INTERNET"/>
<!-- 硬盘缓存--><!-- 在SDCard中创建与删除文件权限 --><uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /><!-- 往SDCard写入数据权限 --><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><!-- 从SDCard读取数据权限 --><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
把后面三个也一起添加了吧,因为本例最终的效果要实现双缓存,所以对SD的读写权限也是必须的。
然后进入正题:加载网络数据:
package com.example.asynctaskdemo;import android.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.TextView;import android.widget.Toast;import com.example.asynctaskdemo.NewsAdapter.IRefereshListener;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<NewsBean> mNewsDatas = null; private RefreshListView mListView ; private TextView mNoDatas; //下拉数据刷新 改写数组为集合 //public static String[] urls; public static List<String> 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" : "http://img.my.csdn.net/uploads/201407/26/1406383291_6518.jpg";*/ //执行更新 end } private void showList(List<NewsBean> 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<NewsBean>>{ @Override protected List<NewsBean> doInBackground(String... params) { Log.i(TAG,"NewTask:doInBackground"); return getDataByUrl(params[0]); } @Override protected void onPostExecute(List<NewsBean> newsBeens) { super.onPostExecute(newsBeens); //fix bug if first nodata //更新了几条数据 if(null!=newsBeens){ newDataslength = newsBeens.size(); if(null==mNewsDatas ){ mNewsDatas = new ArrayList<NewsBean>(); } 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<NewsBean>> { @Override protected List<NewsBean> doInBackground(String... params) { return getDataByUrl(params[0]); } @Override protected void onPostExecute(List<NewsBean> 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<NewsBean> datas = mNewsAdapter.getDatas(); datas.add(-1,bean);*/ mNewsAdapter.setData(-1,bean); mNewsAdapter.notifyDataSetChanged(); } //加载更多end private void setHintVisibility(List<NewsBean> result) { mNoDatas.setVisibility(result==null? View.VISIBLE:View.GONE); } public List<NewsBean> getDataByUrl(String url) { List<NewsBean> 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<NewsBean> parseJson(String jsonString) { try { JSONObject jsonObject = new JSONObject(jsonString); JSONArray jsonArray = jsonObject.getJSONArray("data"); JSONObject data = null; List<NewsBean> datas = new ArrayList<NewsBean>(); NewsBean bean = null; //处理下拉刷新加入 if(null==urls){ urls = new ArrayList<String>(); } List<String> tempUrls = new ArrayList<String>(); //处理下拉刷新加入 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<NewsBean> mDatas; private LayoutInflater mInflater; private RefreshListView mListView; private Context mContext; // 网络图片加载 public List<NewsBean> getDatas() { return mDatas; } public void setDatas(List<NewsBean> 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<NewsBean> 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<NewsBean> 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<NewsImageAsyncTask>(); } //抽象成单例 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); //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<NewsImageAsyncTask> 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); } } //加载大图 mImageLoader.loadBigBitmap(urlBig,mBigImageView,mProgressBar); } private void initView() { mBigImageView = (ImageView) findViewById(R.id.iv_bigimage); mProgressBar = (ProgressBar) findViewById(R.id.pb); }}
7 0
- 一步一步实现ListView加载网络数据,下滑底部加载,顶部下拉刷新。并配有双缓存
- PullToRefreshListView上拉加载,下拉刷新 刷新网络数据 简单实现ListView显示网络数据
- ListView下拉刷新SwipeRefreshLayout + 底部加载
- listView下拉刷新加载数据
- listView下拉刷新加载数据
- listview 下拉刷新加载数据
- listView下拉刷新加载数据
- PullToRefresh 上拉刷新,下拉加载网络数据 ListView
- ListView实现下拉刷新-2-将顶部布局加载到ListView中
- SwipeRefreshLayout完美实现ListView网络数据上拉加载以及下拉刷新
- React Native ListView上拉刷新,下拉加载刷新,并添加网络无数据时的缺省图
- 自定义ListView 实现上拉刷新 下拉加载数据
- 超级ListView,包括下拉刷新,自动翻页加载数据,异步下载、加载图片缓存等
- 一步一步搞定下拉刷新上滑加载ListView
- 自定义继承ListView控件实现下拉刷新底部加载的实现
- ListView下拉刷新加载
- listView下拉刷新加载数据详解
- DropDownListView下拉刷新及滑动到底部加载更多ListView
- iOS 之多线程CoreData
- Hadoop Hive sql语法详解3--DML 操作:元数据存储(3)
- 文件读写(以登录注册为例)
- php 获取远程图片的一个方法
- JavaScript输出各色系随机颜色【红绿蓝青黄紫、黑白、全彩】
- 一步一步实现ListView加载网络数据,下滑底部加载,顶部下拉刷新。并配有双缓存
- iOS——四种即时通讯协议
- 推荐一款设计很赞的装修家居类APP
- 谈谈对Spring IOC的理解
- 图像检索----迭代量化(Iterative Quantization)理解
- Hadoop Hive sql语法详解--DQL 操作:数据查询SQL(4)
- Java拓扑图开发-带宽示例
- 前端开发入门:框架篇-ExpressJS入门学习
- ioutils.ReadAll()会清空对应的reader