Android异步加载的总结。除了LruCache,我们还可以使用DiskLruCache这个第三方的类来实现“二级缓存”。异步加载不仅仅是获取网络资源,我们可以加所有耗时的操作都看成异步加载,所有通过耗时的操作获取的结果我们都可以通过缓存来提高效率,比如我们可以利用这里的LruCache和DiskLruCache(这个缓存一般是用于缓存从网络获取的图片,视频等大的资源,这个时候我们一般和LruCache结合使用),使用Cache有个缺点,就是我们不能保证我们的数据是实时的,所以在realtime需求高的应用中,我们不应该使用缓存。而对于本地资源,我们很少用缓存的,就算是操作SQLite数据库,我们也很少会用到LruCache,但是也有使用的。
listview的优化
1. 复用convertView,减少item view 的加载次数
2.使用holder,减少获取item中子控件的次数
3.使用异步加载,防止阻塞主线程
4.使用google提供的LruCache类,将图片缓存到内存中,减少从网络获取图片的次数
加快速度,节省流量。lru 算法
5. 防止图面缓存引起的错位问题,给每个imageView添加一个tag,用URL做标识,加载图片时
只有当前的URL和要加载图片的imageView的tag中的URL相同时,才加载.
6.监听listView的滚动状态。滚动时停止记载,记录当前可见item的起始和结束位置,并记录他们的url,滚动结束后载再加载。 防止滑动中加载数据造成卡顿,和不必要的流量浪费.
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.util.LruCache;
import android.widget.ImageView;
import android.widget.ListView;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
/**
* Created by Aldrich_jia on 2016-5-9.
*/
public class ImageLoader {
private ImageView mImageView;
private String iconUrl;
//创建cache
private LruCache<String, Bitmap> mCaches;
private ListView mListView;
private Set<NewsIconAsyncTask> mTask;
public ImageLoader(ListView mListView) {
this.mListView = mListView;
mTask = new HashSet<>();
//获取最大可用内存
int maxMemory = (int) Runtime.getRuntime().maxMemory();
//设置换成大小值
int cacheSize = maxMemory / 4;
mCaches = new LruCache<String, Bitmap>(cacheSize) {
//告诉系统,每次存入缓存多大
@Override
protected int sizeOf(String key, Bitmap value) {
//每次存入缓存时调用
return value.getByteCount();
}
};
}
//从缓存中获取数据
public Bitmap getBitmapfromCache(String url) {
return mCaches.get(url);
}
//增加到缓存
private void addBitmaptoCache(String url, Bitmap bitmap) {
if (getBitmapfromCache(url) == null) {
mCaches.put(url, bitmap);
}
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (mImageView.getTag().equals(iconUrl)) {
mImageView.setImageBitmap((Bitmap) msg.obj);
}
}
};
public void showImageByThread(ImageView imageView, final String urlString) {
this.mImageView = imageView;
this.iconUrl = urlString;
new Thread(new Runnable() {
@Override
public void run() {
Bitmap mbitamp = getBitmapForURL(urlString);
Message message = Message.obtain();
message.obj = mbitamp;
mHandler.sendMessage(message);
}
}).start();
}
private Bitmap getBitmapForURL(String urlString) {
Bitmap mbitmap;
InputStream is = null;
try {
URL url = new URL(urlString);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
is = new BufferedInputStream(urlConnection.getInputStream());
mbitmap = BitmapFactory.decodeStream(is);
urlConnection.disconnect();
return mbitmap;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
public void showImageByAsync(ImageView imageView, String mUrl) {
//从缓存中取出对应的图片
Bitmap bitmap = getBitmapfromCache(mUrl);
//如果缓存中没有,必须去下载
if (bitmap == null) {
imageView.setImageResource(R.mipmap.ic_launcher);
// new NewsIconAsyncTask(imageView, mUrl).execute(mUrl);
} else {
imageView.setImageBitmap(bitmap);
}
}
/**
* 显示从start到end中的图片
*
* @param start
* @param end
*/
public void loadImages(int start, int end) {
for (int i = start; i < end; i++) {
String url = NewsAdapter.URLS[i];
//从缓存中取出对应的图片
Bitmap bitmap = getBitmapfromCache(url);
//如果缓存中没有,必须去下载
if (bitmap == null) {
NewsIconAsyncTask asyncTask = new NewsIconAsyncTask(url);
asyncTask.execute(url);
mTask.add(asyncTask);
} else {
ImageView imageView = (ImageView) mListView.findViewWithTag(url);
imageView.setImageBitmap(bitmap);
}
}
}
public void cancelAllTask() {
if (mTask != null) {
for (NewsIconAsyncTask task : mTask) {
task.cancel(false);
}
}
}
private class NewsIconAsyncTask extends AsyncTask<String, Void, Bitmap> {
// private ImageView mImageView;
private String mUrl;
public NewsIconAsyncTask(String mUrl) {
// this.mImageView = mImageView;
this.mUrl = mUrl;
}
@Override
protected Bitmap doInBackground(String... strings) {
String url = strings[0];
//从网络上获取图片
Bitmap bitmap = getBitmapForURL(url);
if (bitmap != null) {
//将不在缓存的图片加入缓存
addBitmaptoCache(url, bitmap);
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
ImageView imageView = (ImageView) mListView.findViewWithTag(mUrl);
if (imageView != null && bitmap != null) {
imageView.setImageBitmap(bitmap);
}
mTask.remove(this);
// if (mImageView.getTag().equals(mUrl)) {
// mImageView.setImageBitmap(bitmap);
//
// }
}
}
}
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import java.util.List;
/**
* Created by Aldrich_jia on 2016-5-9.
*/
public class NewsAdapter extends BaseAdapter implements AbsListView.OnScrollListener {
private List<NewsBean> mList;
private LayoutInflater mLayoutInflater;
private ImageLoader mImageLoader;
private int mStart, mEnd;
public static String[] URLS;
private boolean mFirstIn;
public NewsAdapter(Context context, List<NewsBean> mList, ListView listView) {
mLayoutInflater = LayoutInflater.from(context);
this.mList = mList;
mImageLoader = new ImageLoader(listView);
URLS = new String[mList.size()];
for (int i = 0; i < mList.size(); i++) {
URLS[i] = mList.get(i).newsIconUrl;
}
listView.setOnScrollListener(this);
mFirstIn = true;
}
@Override
public int getCount() {
return mList.size();
}
@Override
public Object getItem(int i) {
return mList.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHoloder viewHoloder = null;
if (view == null) {
viewHoloder = new ViewHoloder();
view = mLayoutInflater.inflate(R.layout.item_layout, null);
viewHoloder.ivIcon = (ImageView) view.findViewById(R.id.iv_icon);
viewHoloder.tvTitle = (TextView) view.findViewById(R.id.tv_title);
viewHoloder.tvContent = (TextView) view.findViewById(R.id.tv_content);
view.setTag(viewHoloder);
} else {
viewHoloder = (ViewHoloder) view.getTag();
}
String iconUrl = mList.get(i).newsIconUrl;
viewHoloder.ivIcon.setTag(iconUrl);
viewHoloder.ivIcon.setImageResource(R.mipmap.ic_launcher);
// new ImageLoader().showImageByThread(viewHoloder.ivIcon,iconUrl);
mImageLoader.showImageByAsync(viewHoloder.ivIcon, iconUrl);
viewHoloder.tvTitle.setText(mList.get(i).newsTitle);
viewHoloder.tvContent.setText(mList.get(i).newsContent);
return view;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_IDLE) {
//加载可见项
mImageLoader.loadImages(mStart, mEnd);
} else {
//停止任务
mImageLoader.cancelAllTask();
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
mStart = firstVisibleItem;
mEnd = firstVisibleItem + visibleItemCount;
//第一次显示的时候调用
if (mFirstIn && visibleItemCount > 0) {
mImageLoader.loadImages(mStart, mEnd);
mFirstIn = false;
}
}
class ViewHoloder {
private TextView tvTitle, tvContent;
private ImageView ivIcon;
}
}
时间: 2024-11-05 14:57:16