Android开发之listview优化+图片异步加载+避免图片显示闪烁(修改版)

小鹿路过此地。。心热之下写写Android开发中的listview运用(闲的没事干,改动了一点代码,但实现功能不变)

小鹿学Android开发已有两年多了,总算有一点点小收获,虽算不上大牛大神级人物,但有些东西可以和一家一起分享一起交流一起学习一起进步...。还有,望查看此文章的废话不多说,直接主题

(注:此内容适合有点Android开发基础的)

学习过Android开发的人都知道listview这个控件了吧,意思就是说listview对我们这些Android开发人员来说并不陌生了。Android开发中使用listview说简单并不简单,说难也不是难,总之...看你怎么开发和使用它了

此内容讲解listview的优化+图片异步加载+避免图片显示闪烁等问题,由于小鹿第一次写这个博客,文章格式不懂怎么排布,乱点请不要喷,仅供大家一起交流学习。

说明实现原理:

大家学过listview图片异步加载等知识都知道,网上有很多很好的博客文章,实现原理大家也知道得差不多了

小鹿的这篇博客文章的listview也跟网上那些大同小异。知识上的一些细节有稍微的改动。

1、getview中的view重用,用使用viewholder。

2、listview中图片显示为当前界面图片显示。

3、滑动时停止加载,停止滑动时加载图片显示与listview界面。

4、给图片设置标签,判断并实现避免闪烁功能

5、异步加载过程就不用多说了....

看代码:(建议大家拷贝到项目中,这样会好看得多····)

显示信息源码:FerrariMessage.java

public class FerrariMessage {
	public static String[] Names = { "法拉利1", "法拉利2", "法拉利3", "法拉利4", "法拉利5",
			"法拉利6", "法拉利7", "法拉利8", "法拉利9", "法拉利10", "法拉利11", "法拉利12", "法拉利13",
			"法拉利14", "法拉利15", "法拉利16", "法拉利17", "法拉利18", "法拉利19", "法拉利20"};
	public static String[] Pics = { "901万", "902万", "903万", "904万", "905万",
			"906万", "907万", "908万", "909万", "910万", "911万", "912万", "913万",
			"914万", "915万", "916万", "917万", "918万", "919万", "920万" };
	public static String[] Urls = {
			"http://pic7.nipic.com/20100518/3409334_031036043513_2.jpg",
			"http://pic7.nipic.com/20100521/1383578_011117510279_2.jpg",
			"http://pic7.nipic.com/20100515/1383578_012657947151_2.jpg",
			"http://xm.05927.com/UploadFiles/pic_2008121110263688.jpg",
			"http://pic5.nipic.com/20100129/1295091_171443267500_2.jpg",
			"http://pic4.nipic.com/20090925/3054494_105159945284_2.jpg",
			"http://s9.knowsky.com/bizhi/l/35001-45000/200952904410415637552.jpg",
			"http://picm.bbzhi.com/qichebizhi/gaoqingqichebizhixinshang/gaoqingqichebizhixinshang_423950_m.jpg",
			"http://pic7.nipic.com/20100524/1383578_033343366370_2.jpg",
			"http://www.lyt.com.cn/lytongger/uploads/201104/1302940767MbGrMW2F.jpg",
			"http://img1.100ye.com/img1/4/996/468/10494468/msgpic/51043248.jpg",
			"http://pic3.nipic.com/20090709/2082016_175148046_2.jpg",
			"http://file-ps.sioe.cn/201006/5/B6132219150.jpg",
			"http://home.tongyi.com/attachment/201001/23/332350_1264213529hJj2.jpg",
			"http://f.hiphotos.bdimg.com/album/w%3D2048/sign=4e37a00c14ce36d3a20484300ecb3887/3801213fb80e7bec41655f372e2eb9389a506bac.jpg",
			"http://gi1.md.alicdn.com/bao/uploaded/i1/TB1jFUUFVXXXXaRXXXXXXXXXXXX_!!0-item_pic.jpg_430x430q90.jpg",
			"http://gd4.alicdn.com/bao/uploaded/i4/TB13YjTFVXXXXXVaXXXXXXXXXXX_!!0-item_pic.jpg_400x400.jpg",
			"http://gd3.alicdn.com/bao/uploaded/i3/TB1iI9pGpXXXXXwXXXXXXXXXXXX_!!0-item_pic.jpg_400x400.jpg",
			"http://gd3.alicdn.com/bao/uploaded/i3/TB1UqnNGXXXXXaFXFXXXXXXXXXX_!!0-item_pic.jpg_400x400.jpg",
			"http://gd3.alicdn.com/bao/uploaded/i3/TB1lNP7FVXXXXXnXXXXXXXXXXXX_!!0-item_pic.jpg_400x400.jpg" };
}

主界面源代码:MainActivity.java

public class MainActivity extends Activity {

	private ListView mListView = null;
	private List<HashMap<String, Object>> mList = new ArrayList<HashMap<String, Object>>();
	private ViewHolder_ListViewAdapter adapter = null;
	private HashMap<String, Object> hashMap=null;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		initFile();
		setContentView(R.layout.activity_main);
		mListView = (ListView) findViewById(R.id.mListView);
		adapter = new ViewHolder_ListViewAdapter(mList, mListView,
				getApplicationContext());
		mListView.setAdapter(adapter);
		 mList.clear();
			for (int i = 0; i < FerrariMessage.Urls.length; i++) {
				hashMap = new HashMap<String, Object>();
				hashMap.put("name", FerrariMessage.Names[i]);
				hashMap.put("pic",FerrariMessage.Pics[i]);
				hashMap.put("url", FerrariMessage.Urls[i]);
				mList.add(hashMap);
			}
			adapter.notifyDataSetChanged();
	}

	private void initFile() {
		File file2 = new File(Environment.getExternalStorageDirectory()
				+ "/test/");
		if (!file2.exists()) {
			file2.mkdirs();
		}
	}

	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		File file = new File(Environment.getExternalStorageDirectory()
				+ "/test");
		deleteFile(file);
	}

	// 将SD卡文件删除
	private void deleteFile(File file) {
		if (Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED)) {
			if (file.exists()) {
				if (file.isFile()) {
					file.delete();
				}
				// 如果它是一个目录
				else if (file.isDirectory()) {
					// 声明目录下所有的文件 files[];
					File files[] = file.listFiles();
					for (int i = 0; i < files.length; i++) { // 遍历目录下所有的文件
						deleteFile(files[i]); // 把每个文件 用这个方法进行迭代
					}
				}
				file.delete();
			}
		}
	}

}

适配器:ViewHolder_ListViewAdapter.java

public class ViewHolder_ListViewAdapter extends BaseAdapter {
	private List<HashMap<String, Object>> mList;
	private LayoutInflater inflater = null;
	private ImageRegister imageRegister=null;
	private ListView mListView=null;

	public ViewHolder_ListViewAdapter(List<HashMap<String, Object>> list,
			ListView listView, Context context) {
		this.mList = list;
		this.imageRegister = new ImageRegister();
		this.mListView = listView;
		this.mListView.setOnScrollListener(onScrollListener);
		inflater = LayoutInflater.from(context);
	}

	@Override
	public int getCount() {
		return mList.size();
	}

	@Override
	public Object getItem(int position) {
		return mList.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public View getView(final int position, View v, ViewGroup parent) {
		ViewHolder vh = null;
		if (v == null) {
			vh = new ViewHolder();
			v = inflater.inflate(R.layout.item_listview, null);
			vh.title1 = (TextView) v.findViewById(R.id.title1);
			vh.title2 = (TextView) v.findViewById(R.id.title2);
			vh.imageView = (ImageView) v.findViewById(R.id.imageView);
			v.setTag(vh);
		} else {
			vh = (ViewHolder) v.getTag();
		}
		mListView.setTag(mList.get(position).get("url"));
		vh.title1.setText(mList.get(position).get("name").toString());
		vh.title2.setText(mList.get(position).get("pic").toString());
		vh.imageView.setBackgroundResource(R.drawable.ic_launcher);
		vh.imageView.setTag(mList.get(position).get("url").toString());
		imageRegister.loadImage(position, vh.imageView, mList.get(position)
				.get("url").toString(), "test");
		return v;
	}

	private class ViewHolder {
		TextView title1;
		TextView title2;
		ImageView imageView;
	}

	AbsListView.OnScrollListener onScrollListener = new OnScrollListener() {

		@Override
		public void onScrollStateChanged(AbsListView view, int scrollState) {
			// TODO Auto-generated method stub
			switch (scrollState) {
			case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
				imageRegister.Lock();
				break;
			case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
				loadImage();
				break;
			case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
				imageRegister.Lock();
				break;
			}
		}

		@Override
		public void onScroll(AbsListView view, int firstVisibleItem,
				int visibleItemCount, int totalItemCount) {
		}
	};

	protected void loadImage() {
		// TODO Auto-generated method stub
		int start = mListView.getFirstVisiblePosition();
		int end = mListView.getLastVisiblePosition();
		if (end >= getCount()) {
			end = getCount() - 1;
		}
		imageRegister.setLoadLimit(start, end);
		imageRegister.unLock();
	}
}

异步加载类:ImageRegister.java

public class ImageRegister {

	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 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(final Integer position, final ImageView imageView,
			final String imageUrl, final String fileName) {
		new Thread(new Runnable() {

			@Override
			public void run() {
				if (!mAllowLoad) {
					synchronized (lock) {
						try {
							lock.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}

				if (mAllowLoad && firstLoad) {
					loadImage2(position,imageUrl, imageView, fileName);
				}
				if (mAllowLoad && position<= mStopLoadLimit && position >= mStartLoadLimit) {
					loadImage2(position,imageUrl, imageView, fileName);
				}
			}
		}).start();
	}

	private void loadImage2(final Integer position,final String mImageUrl, final ImageView imageView,
			final String fileName) {
		if (imageCache.containsKey(mImageUrl)) {
			SoftReference<Drawable> softReference = imageCache.get(mImageUrl);
			final Drawable d = softReference.get();
			if (d != null) {
				handler.post(new Runnable() {
					@SuppressLint("NewApi") @Override
					public void run() {
						if (mAllowLoad) {
							if (imageView.getTag().equals(mImageUrl)) {
								imageView.setBackground(d);
							}
						}
					}
				});
				return;
			}
		}
		try {
			final Drawable d = loadImageFromUrl(position,imageView,mImageUrl, fileName);
			if (d != null) {
				imageCache.put(mImageUrl, new SoftReference<Drawable>(d));
				handler.post(new Runnable() {
					@SuppressLint("NewApi") @Override
					public void run() {
						if (mAllowLoad) {
							if (imageView.getTag().equals(mImageUrl)) {
								imageView.setBackground(d);
							}
						}
					}
				});
			}
		} catch (IOException e) {
			handler.post(new Runnable() {
				@Override
				public void run() {
					imageView.setBackgroundResource(R.drawable.ic_launcher);
				}
			});
			e.printStackTrace();
		}
	}

	@SuppressLint("NewApi") 
	public Drawable loadImageFromUrl(Integer position,ImageView imageView,String url, String fileName)
			throws IOException {
		if (Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED)) {
			String imageName = url.substring(url.lastIndexOf("/"));
			String pathName = (Environment.getExternalStorageDirectory() + "/"
					+ fileName + imageName);
			File f = new File(pathName);
			if (f.exists()) {
				Bitmap bitmap = compressImageFromFile(pathName);
				@SuppressWarnings("deprecation")
				BitmapDrawable d = new BitmapDrawable(bitmap);
				System.out.println("加载了第:"+position);
				return d;
			}else{
			System.out.println("下载了第:"+position);
			URL m = new URL(url);
			InputStream inputStream = (InputStream) m.getContent();
			DataInputStream in = new DataInputStream(inputStream);
			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();
			return loadImageFromUrl(position,imageView,url, fileName);
			}
		} else {
			URL m = new URL(url);
			InputStream inputStream = (InputStream) m.getContent();
			Drawable drawable = Drawable.createFromStream(inputStream, null);
			inputStream.close();
			return drawable;
		}
		    
	}

	private Bitmap compressImageFromFile(String srcPath) {
		BitmapFactory.Options newOpts = new BitmapFactory.Options();
		newOpts.inJustDecodeBounds = true;
		Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
		newOpts.inJustDecodeBounds = false;
		int w = newOpts.outWidth;
		int h = newOpts.outHeight;
		float hh = 100f;
		float ww = 120f;
		int be = 1;
		if (w > h && w > ww) {
			be = (int) (newOpts.outWidth / ww);
		} else if (w < h && h > hh) {
			be = (int) (newOpts.outHeight / hh);
		}
		if (be <= 0)
			be = 1;
		newOpts.inSampleSize = be;
		newOpts.inPreferredConfig = Config.ARGB_8888;
		newOpts.inPurgeable = true;
		newOpts.inInputShareable = true;
		bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
		return bitmap;
	}

}

mainactivity界面的布局文件activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
     <ListView
        android:id="@+id/mListView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:cacheColorHint="#00000000"
        android:dividerHeight="1.0dip"
        android:listSelector="#00000000" />
</LinearLayout>

listview条目的布局文件item_listview.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:orientation="horizontal" >
     
    <ImageView 
        android:id="@+id/imageView"
        android:layout_width="0dp"
        android:layout_height="80dp"
        android:layout_weight="1.0"
        />
    
    <TextView
        android:id="@+id/title1"
        android:layout_width="0dp"
        android:layout_height="fill_parent"
        android:layout_weight="1.0"
        android:gravity="center"
        android:text="" />

    <TextView
        android:id="@+id/title2"
        android:layout_width="0dp"
        android:layout_height="fill_parent"
        android:layout_weight="1.0"
        android:gravity="center"
        android:text="" />

    <TextView
        android:id="@+id/title3"
        android:layout_width="0dp"
        android:layout_height="fill_parent"
        android:layout_weight="1.0"
        android:gravity="center"
        android:text="" />


    <TextView
        android:id="@+id/title4"
        android:layout_width="0dp"
        android:layout_height="fill_parent"
        android:layout_weight="1.0"
        android:gravity="center"
        android:text="" />

</LinearLayout>

最后,在androidmanifest.xml中添加权限

  

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.RESTART_PACKAGES" />

点评:此项目又优点也有缺点,我直接说缺点好了:①当网速不好的时候,下载图片速度慢,显示在listview界面有时图片不全(暂时没有解决方案,希望大家一起交流)。②界面太简单(这靠大家设计UI了,小鹿能力有限)。

代码已奉上完了,小鹿第一次用博客写文章,本来想给大家发上demo,可小鹿不懂怎么发,时间也不多了,希望大家查看此文章后能一起交流技术,此文章有不足之处请大家点评。。。。小鹿要睡觉了。。。希望能和大家一起交流。。。午安



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值