您的位置:首页 > 其它

解决ListView滑动时卡的问题,实现异步加载图片解决

2014-08-12 18:02 411 查看
ListView是最为常见的空间之一,现在的应用的呈现形式大多数都需要用到ListView来呈现,以列表的方式最直观最便于操作。

那么在使用的过程中大家一定使用adapter适配器来匹配这个ListView,问题就来了,如果直接使用sampleAdapter的话,会出现诸多的问题,诸如滚动的时候很卡,特别是每一行都有头像啊什么的,再加上数据量一大,兼职就卡的不行,那么先来说说解决卡的问题的简单的实现方法吧。

首先需要自己来写一个myAdapter继承与BaseAdapter。

然后最关键的是在getView方法中做到以下几点判断convertView是否为空,这样可以避免每次滚动都去新建,可以节约大量资源,同时对于图片采用开启线程以异步加载的方式来加载它,又可以节约一部分资源,同时,将加载下来的图片缓存到本地,当下一次的时候首先读取本地图片,第一可以节约流量,其次速度非常快(不过服务器图片更新了这个要想好解决方案,不然你本地的图片不会被替换掉)。最后就是在滚动时间的时候让异步加载暂停,等手放开的时候再加载,这样可以保证滚动的超级流畅,不过同时会出现滚动比较大的时候图片都还是空的没有加载的现象,反正自己斟酌优劣吧,代码都有哈!接下来上代码了

首先是主activity

[java] view
plaincopy

package com.challen;

import java.util.Vector;

import cindy.android.test.synclistview.R;

import android.app.Activity;

import android.content.Context;

import android.graphics.drawable.Drawable;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.AbsListView;

import android.widget.AdapterView;

import android.widget.BaseAdapter;

import android.widget.ImageView;

import android.widget.ListView;

import android.widget.TextView;

public class TestListViewActivity extends Activity implements

AdapterView.OnItemClickListener {

ListView viewBookList;

BookItemAdapter adapter;

@Override

protected void onCreate(Bundle savedInstanceState) {

// TODO Auto-generated method stub

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

viewBookList = (ListView) findViewById(R.id.viewBookList);

adapter = new BookItemAdapter(this, viewBookList);

viewBookList.setAdapter(adapter);

viewBookList.setOnItemClickListener(this);

reload();

}

private void reload() {

adapter.clean();

// loadStateView.startLoad();

new Thread(new Runnable() {

@Override

public void run() {

try {

Thread.sleep(2 * 1000);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

loadDate();

sendMessage(REFRESH_LIST);

}

}).start();

}

public void loadDate() {

for (int i = 0; i < 100; i++) {

adapter.addBook("我是challen的测试异步加" + i, "1",

"http://ww1.sinaimg.cn/thumbnail/80ab1ad3gw1dx8tfjvbgdj.jpg");

adapter.addBook("小美" + i, "2",

"http://ww2.sinaimg.cn/thumbnail/7f9fd9a9jw1dtyrqrh4mjj.jpg");

adapter.addBook("金总" + i, "3",

"http://ww3.sinaimg.cn/thumbnail/9d57e8e4jw1dx6topumz5j.jpg");

adapter.addBook("创意铺子" + i, "4",

"http://www.pfwx.com/files/article/image/3/3237/3237s.jpg");

adapter.addBook("人名日报" + i, "5",

"http://ww2.sinaimg.cn/thumbnail/9263d293jw1dx8snx58s7j.jpg");

adapter.addBook("名字是乱明的" + i, "6",

"http://tp1.sinaimg.cn/1660452532/50/5646449168/0");

adapter.addBook("帅哥即将出现" + i, "7",

"http://p1.qhimg.com/t01a869bb64c7f3d8c6.png");

adapter.addBook("注意了哦" + i, "8",

"http://www.baidu.com/img/baidu_jgylogo3.gif");

adapter.addBook("来拉" + i, "9",

"http://tp4.sinaimg.cn/2190322767/50/5605436918/1");

adapter.addBook("这个就是我啦" + i, "10",

"http://avatar.csdn.net/E/7/2/3_jkingcl.jpg");

}

}

private static final int REFRESH_LIST = 0x10001;

public static final int SHOW_STR_TOAST = 0;

public static final int SHOW_RES_TOAST = 1;

private Handler pichandler = new Handler() {

@Override

public void handleMessage(Message msg) {

if (!Thread.currentThread().isInterrupted()) {

handleOtherMessage(msg.what);

}

}

};

public void sendMessage(int flag) {

pichandler.sendEmptyMessage(flag);

}

protected void handleOtherMessage(int flag) {

switch (flag) {

case REFRESH_LIST:

adapter.notifyDataSetChanged();

default:

break;

}

}

@Override

public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {

// TODO Auto-generated method stub

}

public class BookItemAdapter extends BaseAdapter {

public class BookModel {

public String book_id;

public String out_book_url;

public String author;

public String book_state_s;

public String leading_role;

public String update_time;

public String book_name;

public String out_book_pic;

public String sort_id;

public String last_update_section_title;

public String last_update_section_url;

public String introduction;

}

private LayoutInflater mInflater;

private Vector<BookModel> mModels = new Vector<BookModel>();

private ListView mListView;

SyncImageLoader syncImageLoader;

public BookItemAdapter(Context context, ListView listView) {

mInflater = LayoutInflater.from(context);

syncImageLoader = new SyncImageLoader();

mListView = listView;

/*

*

* 这一句话取消掉注释的话,那么能更加的节省资源,不过体验稍微有点,

* 你滑动的时候不会读取图片,当手放开后才开始度图片速度更快,你们可以试一试

* */

// mListView.setOnScrollListener(onScrollListener);

}

public void addBook(String book_name, String author, String out_book_pic) {

BookModel model = new BookModel();

model.book_name = book_name;

model.author = author;

model.out_book_pic = out_book_pic;

mModels.add(model);

}

public void clean() {

mModels.clear();

}

@Override

public int getCount() {

// TODO Auto-generated method stub

return mModels.size();

}

@Override

public Object getItem(int position) {

if (position >= getCount()) {

return null;

}

return mModels.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) {

if (convertView == null) {

convertView = mInflater.inflate(R.layout.item_adapter,

null);

}

BookModel model = mModels.get(position);

convertView.setTag(position);

ImageView iv = (ImageView) convertView.findViewById(R.id.sItemIcon);

TextView sItemTitle = (TextView) convertView

.findViewById(R.id.sItemTitle);

TextView sItemInfo = (TextView) convertView

.findViewById(R.id.sItemInfo);

sItemTitle.setText(model.book_name);

sItemInfo.setText(model.out_book_url);

// 添加�?��背景在滑动的时�?就会显示背景而不是其他的缓存的照片,用户体验更好

iv.setBackgroundResource(R.drawable.rc_item_bg);

syncImageLoader.loadImage(position, model.out_book_pic,

imageLoadListener, model.author);

return convertView;

}

SyncImageLoader.OnImageLoadListener imageLoadListener = new SyncImageLoader.OnImageLoadListener() {

@Override

public void onImageLoad(Integer t, Drawable drawable) {

// BookModel model = (BookModel) getItem(t);

View view = mListView.findViewWithTag(t);

if (view != null) {

ImageView iv = (ImageView) view

.findViewById(R.id.sItemIcon);

iv.setBackgroundDrawable(drawable);

}

}

@Override

public void onError(Integer t) {

BookModel model = (BookModel) getItem(t);

View view = mListView.findViewWithTag(model);

if (view != null) {

ImageView iv = (ImageView) view

.findViewById(R.id.sItemIcon);

iv.setBackgroundResource(R.drawable.rc_item_bg);

}

}

};

public void loadImage() {

int start = mListView.getFirstVisiblePosition();

int end = mListView.getLastVisiblePosition();

if (end >= getCount()) {

end = getCount() - 1;

}

syncImageLoader.setLoadLimit(start, end);

syncImageLoader.unlock();

}

AbsListView.OnScrollListener onScrollListener = new AbsListView.OnScrollListener() {

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

switch (scrollState) {

case AbsListView.OnScrollListener.SCROLL_STATE_FLING:

syncImageLoader.lock();

break;

case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:

loadImage();

break;

case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:

syncImageLoader.lock();

break;

default:

break;

}

}

@Override

public void onScroll(AbsListView view, int firstVisibleItem,

int visibleItemCount, int totalItemCount) {

// TODO Auto-generated method stub

}

};

}

}

其次是实现异步加载和缓存图片的功能代码loader.java

[java] view
plaincopy

package com.challen;

import java.io.DataInputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.lang.ref.SoftReference;

import java.net.URL;

import java.util.HashMap;

import android.graphics.drawable.Drawable;

import android.os.Environment;

import android.os.Handler;

public class SyncImageLoader {

private Object lock = new Object();

private boolean mAllowLoad = true;

private boolean firstLoad = true;

private int mStartLoadLimit = 0;

private int mStopLoadLimit = 0;

final Handler handler = new Handler();

private HashMap<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();

public interface OnImageLoadListener {

public void onImageLoad(Integer t, Drawable drawable);

public void onError(Integer t);

}

public void setLoadLimit(int startLoadLimit,int stopLoadLimit){

if(startLoadLimit > stopLoadLimit){

return;

}

mStartLoadLimit = startLoadLimit;

mStopLoadLimit = stopLoadLimit;

}

public void restore(){

mAllowLoad = true;

firstLoad = true;

}

public void lock(){

mAllowLoad = false;

firstLoad = false;

}

public void unlock(){

mAllowLoad = true;

synchronized (lock) {

lock.notifyAll();

}

}

public void loadImage(Integer t, String imageUrl,

OnImageLoadListener listener,String author1) {

final OnImageLoadListener mListener = listener;

final String mImageUrl = imageUrl;

final Integer mt = t;

final String author = author1;

new Thread(new Runnable() {

@Override

public void run() {

if(!mAllowLoad){

synchronized (lock) {

try {

lock.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

if(mAllowLoad && firstLoad){

loadImage(mImageUrl, mt, mListener,author);

}

if(mAllowLoad && mt <= mStopLoadLimit && mt >= mStartLoadLimit){

loadImage(mImageUrl, mt, mListener,author);

}

}

}).start();

}

private void loadImage(final String mImageUrl,final Integer mt,final OnImageLoadListener mListener,final String author){

if (imageCache.containsKey(mImageUrl)) {

System.out.println("drawable");

SoftReference<Drawable> softReference = imageCache.get(mImageUrl);

final Drawable d = softReference.get();

if (d != null) {

handler.post(new Runnable() {

@Override

public void run() {

if(mAllowLoad){

mListener.onImageLoad(mt, d);

}

}

});

return;

}

}

try {

final Drawable d = loadImageFromUrl(mImageUrl,author);

if(d != null){

imageCache.put(mImageUrl, new SoftReference<Drawable>(d));

}

handler.post(new Runnable() {

@Override

public void run() {

if(mAllowLoad){

mListener.onImageLoad(mt, d);

}

}

});

} catch (IOException e) {

handler.post(new Runnable() {

@Override

public void run() {

mListener.onError(mt);

}

});

e.printStackTrace();

}

}

public static Drawable loadImageFromUrl(String url,String author) throws IOException {

//是否SD卡可用

if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){

//检查是或有保存图片的文件夹,没有就穿件一个

String FileUrl = Environment.getExternalStorageDirectory()+"/TestSyncListView/";

File folder = new File(FileUrl);

if(!folder.exists()){

folder.mkdir();

}

File f = new File(FileUrl+author+".jpg");

//SD卡中是否有该文件,有则直接读取返回

if(f.exists()){

FileInputStream fis = new FileInputStream(f);

Drawable d = Drawable.createFromStream(fis, "src");

return d;

}

//没有的话则去连接下载,并写入到SD卡中

URL m = new URL(url);

InputStream i = (InputStream) m.getContent();

DataInputStream in = new DataInputStream(i);

FileOutputStream out = new FileOutputStream(f);

byte[] buffer = new byte[1024];

int byteread=0;

while ((byteread = in.read(buffer)) != -1) {

out.write(buffer, 0, byteread);

}

in.close();

out.close();

Drawable d = Drawable.createFromStream(i, "src");

return loadImageFromUrl(url,author);

}

//SD卡不可用则直接加载使用

else{

URL m = new URL(url);

InputStream i = (InputStream) m.getContent();

Drawable d = Drawable.createFromStream(i, "src");

return d;

}

}

}

最后附上整个测试demo的下载地址,各位可以去下载,然后根据自己的需求加入到自己的项目中,希望可以帮助到大家,大家多多交流哦!

http://download.csdn.net/detail/jkingcl/4726519
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: