本文實例講述了android listview異步加載圖片方法。分享給大家供大家參考,具體如下:
先說說這篇文章的優點把,開啟線程異步加載圖片,然后刷新ui顯示圖片,而且通過弱引用緩存網絡加載的圖片,節省了再次連接網絡的開銷。
這樣做無疑是非常可取的方法,但是加載圖片時仍然會感覺到輕微的卡屏現象,特別是listview里的item在進行快速滑動的時候。
我找了一下原因,可能是在listview快速滑動屏幕的時候劃過的item太多 而且每次調用getview方法后就會異步的在過去某個時間內用handler刷新一下ui,
如果在同一時間調用handler刷新ui次數多了就會造成這樣的卡屏現象。
后來又一想,其實我們完全沒有必要在listview正在滑動的時候去后臺加載圖片(不管這是圖片是在緩存里還是在網絡上),這樣無疑造成了很大的資源浪費。
我們只需要在listview滑動停止之后再去加載listview里面顯示的幾個item里面的圖片就好了。
根據以上想法,我做了一些設計改造:
1.在adapter 的 getview方法里面啟動加載圖片的thread,如果listview在滑動則wait
2.監聽listview滑動停止事件,獲得listview顯示的item的最上面和最下面的序號,并喚醒所有加載圖片的thread,判斷加載圖片的序號是否是在范圍內,如果是則繼續加載,如果不是則結束thread
部分代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
@override public view getview( int position, view convertview, viewgroup parent) { if (convertview == null ){ convertview = minflater.inflate(r.layout.book_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); 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: debugutil.debug( "scroll_state_fling" ); syncimageloader.lock(); break ; case abslistview.onscrolllistener.scroll_state_idle: debugutil.debug( "scroll_state_idle" ); loadimage(); //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 } }; |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
package cindy.android.test.synclistview; 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) { final onimageloadlistener mlistener = listener; final string mimageurl = imageurl; final integer mt = t; new thread( new runnable() { @override public void run() { if (!mallowload){ debugutil.debug( "prepare to load" ); synchronized (lock) { try { lock.wait(); } catch (interruptedexception e) { // todo auto-generated catch block e.printstacktrace(); } } } if (mallowload && firstload){ loadimage(mimageurl, mt, mlistener); } if (mallowload && mt <= mstoploadlimit && mt >= mstartloadlimit){ loadimage(mimageurl, mt, mlistener); } } }).start(); } private void loadimage( final string mimageurl, final integer mt, final onimageloadlistener mlistener){ if (imagecache.containskey(mimageurl)) { 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); 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) throws ioexception { debugutil.debug(url); if (environment.getexternalstoragestate().equals(environment.media_mounted)){ file f = new file(environment.getexternalstoragedirectory()+ "/testsynclistview/" +md5.getmd5(url)); if (f.exists()){ fileinputstream fis = new fileinputstream(f); drawable d = drawable.createfromstream(fis, "src" ); return d; } 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); } else { url m = new url(url); inputstream i = (inputstream) m.getcontent(); drawable d = drawable.createfromstream(i, "src" ); return d; } } } |
除了本身已有的弱引用緩存圖片,我還添加了本地sd卡緩存圖片(這兩種緩存方法各有好處,如果圖片經常變化建議內存緩存圖片,如果是不經常修改的圖片建議sd卡緩存)
希望本文所述對大家android程序設計有所幫助。