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,可小鹿不懂怎麼發,時間也不多了,希望大家檢視此文章後能一起交流技術,此文章有不足之處請大家點評。。。。小鹿要睡覺了。。。希望能和大家一起交流。。。午安