์๋๋ก์ด๋ ๊ฐ๋ฐ์์ ๋ง์ ๋น์ค์ ์ฐจ์งํ๋ UIํจํด์ ListView์์ ์ฌ๋ฌ ์ด๋ฏธ์ง๋ฅผ ๋ณด์ฌ์ฃผ๋ Activity์ ๋๋ค. ์ ํ์ ์ธ ํ๋ฆ์ ์ ๋ฆฌํ๋ฉด ์๋์ ๊ฐ์ต๋๋ค.
โ1. ๋ชฉ๋ก์กฐํ APIํธ์ถ
โ2. API๋ฅผ ํ์ฑํ๊ณ ListView์ ๋ฐ์ดํฐ๋ฅผ ๋ณด์ฌ ์ค.
โ3. ๊ฐ ์์ดํ ๋ง๋ค์ ์ด๋ฏธ์ง ์ฃผ์๋ก ๋ค์ ์๋ฒ๋ฅผ ํธ์ถ
โ4. ์ด๋ฏธ์ง๋ฅผ ๋์ฝ๋ฉํ๊ณ ImageView์์ ๋ณด์ฌ์ค.
ํํ ํจํด์ด์ง๋ง, ๊ฐ์ข ์์ธ ์ํฉ๊น์ง ๊ฐ์ํด์ ์ด ํ๋ฆ์ ์ฒ๋ฆฌํ๋๋ฐ์๋ ๋ง์ ์ฝ๋๊ฐ ๋ค์ด๊ฐ๋๋ค. APIํธ์ถ์ ์ํ ์ฐ๋ ๋ํ ๊ด๋ฆฌ๋ APIํธ์ถ์ ํ ํ์ ํ๋ฉด ํ์ ๊ณผ ์ ํ์ด ์ผ์ด๋ฌ์ ๋์ ํธ์ถ ์ทจ์, Activity์ Null pointer ์ฒดํฌ, ImageView์ ์ฌํ์ฉ๊ณผ ์ด๋ฏธ์ง Cache๋ฑ ๊ณ ๋ คํด์ผํ ๊ฒ์ด ๋ง์ต๋๋ค. ์ด๋ ๊ฒ ์ ํ์ ์ธ UI์์๋ ๋ค์ํ ๋ฒ์ ์์, ๊ด์ฐฎ์ ์ฑ๋ฅ์ผ๋ก, ๋ชจ๋ ์ํฉ์์ ํฌ๋์ฌ์์ด ๋์๊ฐ๋๋ก ๋ง๋๋ ค๋ฉด ์ฑ๊ฒจ์ผํ ์์๊ฐ ๋ง์ต๋๋ค.
Google IO 2013 ์์๋ ์ด๋ฐ ํจํด์ ์ฒ๋ฆฌํ๊ธฐ์ ์ ํฉํ Volley๋ผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๊ณต๊ฐ๋์์ต๋๋ค. Volley๋ ๋ค๋ฅธ ์๋๋ก์ด๋์ฉ Http ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ ๊ณตํ๋ ๊ธฐ๋ฅ์ ๋๋ถ๋ถ ์ ๊ณตํ๋ฉด์๋ ์ฉ๋์ด ์์ต๋๋ค. (jarํ์ผ ๊ธฐ์ค์ผ๋ก 86,591 bytes) Spring RestTemplate + Robospice + Universal ImageLoader์ ํต์ฌ๊ธฐ๋ฅ์ ๋ค ์ ๊ณตํ๋ฉด์ ๊ฒฝ๋์ ๋๋ค. Google์ playstore์ฑ์์ ์ฌ์ฉ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ผ์ ์์ฉ์์ ๋ฐ๋ก ์ธ ์ ์๋ ์์ค์ด๋ผ๊ณ ํฉ๋๋ค. ๊ตญ๋ด์์๋ ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ๋ฅผ ํตํด์ ์ด๋ฏธ Volley๋ฅผ ์ฐ๊ณ ์๋ค๊ณ ๋ฐํ ๋ถ๋ค์ด ๋์ค๊ณ ์์ต๋๋ค.
Google I/O 2013์ ๋ฐํ์ ์ด ํ์ ์ธํฐ๋ท์ ์ฌ๋ผ์จ ์ ๋ณด๋ฅผ ์ ๋ฆฌํด๋ณด์์ต๋๋ค.
- ์์ฒญ์์ ํ + Thread pool์ ์ด์ฉํ ๋์ ์์ฒญ ์ง์.
- ์์ฒญ๋ณ ์ฐ์ ์์ : ๋ชฉ๋ก์กฐํ์ ์ด๋ฏธ์ง ๋ค์ด๋ก๋๋ฅผ ํ ๋ ๋ชฉ๋ก์กฐํ๊ฐ ์ฐ์ ์์๊ฐ ๋๊ฒ ์ค์ . ๋ค์ ํ์ด์ง์ ๋ชฉ๋ก์กฐํ๋ฅผ ์์ฒญํ๋ฉด ์ด์ ํ์ด์ง์ ์ด๋ฏธ์ง๋ก๋ฉ์ด ๋๋์ง ์์๋ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ์ํ.
- Transparent cache : ์์ฒญํ๋ ์ชฝ์์ Cache ์ ์ฉ์ฌ๋ถ๋ฅผ ์์ํ์ง ์์๋ ๋จ
- ์ด๋ฏธ์ง ๋ก๋ฉํด, NetworkImageVIew๋ผ๋ View ์ ๊ณต
- ์์ฒญ ์ทจ์ : ํน์ ์์ฒญ, ํด๋น Context์ ์์ฒญ ๋ชจ๋ ์ทจ์ํ ์ ์๊ณ , ์ทจ์ํ ๊ท์น๋ ์ง์ ๊ฐ๋ฅ
- ์ง์ ๋ธ๋ ๋ ์ด์ ์ HttpURLConnection์ ๋ฒ๊ทธ ๋ฌธ์ ํด๊ฒฐ : 2013๋ 5์ The platform์ ๊ธฐ๊ณ ํ Android์ HTTP ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ธฐ์ฌ์์ ๋ค๋ฃฌ ์ฌ๋ฌ ์คํ์์ค๊ฐ ๊ทธ๋ฌ๋ ๊ฒ์ฒ๋ผ ์ง์ ๋ธ๋ ๋ ์ด์์์๋ง java.net.HttpURLConnection์ ์ฐ๋ ๋ก์ง์ด ๋ค์ด๊ฐ ์์ต๋๋ค.
- retry, backoff policy ์ง์, ํ์ฅ ๊ธฐ๋ฅ
- SPDY ์ง์ : ๋ฐํ ๋น์์๋ Volley์ tranport stack์ผ๋ก OkHttp( http://square.github.io/okhttp/ ) ๋ฅผ ๋ฃ๋ ์์ ์ด ๋๊ตฐ๊ฐ๊ฐ ์งํํ๊ณ ์๋ค๊ณ ํ๋๋ฐ, ๊ธฐ์ฌ๋ฅผ ์์ฑํ ์ดํ์ ๋ฐ๋๋ฐ๋ํ๊ฒ ๊ณต๊ฐ ๋์์ต๋๋ค.
- JSON, XML, Image, protobuffer ๋ฑ ๋ค์ํ Responseํ์์ ์ฒ๋ฆฌํ๋๋ก ํ์ฅ ๊ฐ๋ฅ
ํนํ Google IO์ ๋ฐํ์์ ์ฑ๋ฅ์ ์์ ๊ฐ์ด ๋๋จํ์ต๋๋ค. Google + ํ์ด ๋ค์ํ Network ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค๊ณผ Benchmark๋ฅผ ํ์ ๋ Volley๊ฐ ๋ชจ๋ ๊ฒ์ ๋ค ์ด๊ฒผ๊ณ , ๋งค๋ฒ ๋นจ๋๊ณ , ์ด๋ค ๊ฒฝ์ฐ์๋ 10๋ฐฐ๊น์ง ๋นจ๋๋ค๊ณ ํฉ๋๋ค. ๊ตฌ๊ธ์์ ์ฑ์ ๊ฐ๋ฐํ๋ฉด์ ์ด๋ ต๊ฒ ์ป์ ๊ตํ์ ์ด๋์ ์ฝ๊ฒ ์ป์ ์ ์์๊ฒ์ด๊ณ , ์ค์ค๋ก ๊ฐ๋ฐํ๋๊ฒ๋ณด๋ค ํจ์ฌ ๋น ๋ฅผ ๊ฒ์ด๋ผ๊ณ ์์ ์๊ฒ ๋งํฉ๋๋ค.
Volley๋ ํ๋ก์๋ถํฐ ์ต์ ๋ฒ์ ๊น์ง ์ฌ์ฉํ ์ ์๊ณ , SDK manager๋ฅผ ํตํ ๋ค์ด๋ก๋ ๋ฑ์ ์์ง ๊ณํ๋ ๊ฒ์ ์๋ค๊ณ ํฉ๋๋ค.
ํ์ฌ๊น์ง๋ ๋ฉ๋ชจ๋ฆฌ Cache์ ๋ํ ๊ธฐ๋ณธ ๊ตฌํ์ฒด๊ฐ ์๋ค๋ ์ ์ด ์์ฝ์ต๋๋ค. Cache interface์ ๊ตฌํ๊ฐ์ฒด๊ฐ DiskBaseCache์ NoCache ํด๋์ค ๋ฐ์ ์์ต๋๋ค. ์ฑ์ ํน์ฑ์ ๋ง๊ฒ ์์์ ๊ตฌํํ๋ผ๋ ์๋ฏธ์ธ๋ฏํ๋ฐ, Cache ์ฉ๋ํ๊ณ๋ง ์ง์ ํ๋ฉด ๋ฐ๋ก ์ธ ์ ์๋ ๊ตฌํ์ฒด๊ฐ ๊ธฐ๋ณธ ์ ๊ณต๋๋ค๋ฉด ๋์ฑ ์ข์๋ฏํฉ๋๋ค.
์์ง ๋ณ๋์ release ํ๋ก์ธ์ค๊ฐ ์๊ธฐ ๋๋ฌธ์ ์๋์ ๊ฐ์ด git ์ ์ฅ์๋ฅผ ๋ณต์ฌํด์ผ ํฉ๋๋ค.
git clone https://android.googlesource.com/platform/frameworks/volley
Ant ๋น๋๋ฅผ ์คํ์์ผ์ jarํ์ผ์ ์์ฑํ ์ ์์ต๋๋ค.
cd volley
ant jar
๋ง์ฝ build.xml์ด ๊ฐ๋ฐ์ฅ๋น์ ์ค์น๋ Android์ SDK์ ๋ฒ์ ๊ณผ ์ ๋ง์ง ์๋๋ค๋ฉด 'android update project -p .'๋ฅผ ์คํ์์ผ์ ๋ค์ ์์ฑํฉ๋๋ค.
์๋๋ Maven ํ๋ก์ ํธ๊ฐ ์๋๊ธฐ ๋๋ฌธ์ pom.xml์ ์๋์ผ๋ก ์ถ๊ฐํ๊ณ , mvn install๋ก ์ค์นํด์ผ ํฉ๋๋ค.
- https://gist.github.com/f2prateek/5606337 (android.jar์ scope๋ provided๋ก ์์ )
- https://github.com/luigi-agosti/volley/blob/master/volley/pom.xml
- Ficusk์ LruBitmapCache : android.support.v4.util.LruCache๋ฅผ ์์ํด์ ๊ตฌํ. Google I/O 2013 ๋ฐํ์์ ๊ณต์ .
- howrobotswork์ DiskBitmapCache : Volley์ DiskBasedCache๋ฅผ ์์ํด์ ๊ตฌํ
- ์ ํ์ผ๋์ WeakImageCache : java.lang.WeakReference๋ฅผ ํ์ฉ.
Google IO 2013์์ Volley ์ธ์ ์ ๋ฐํ์์ธ Ficus Kirkpatrick๋ Google์ชฝ์์๋ soft reference๋ weak reference๋ฅผ ์ฐ์ง ์๋๋ค๊ณ ์ธ๊ธ์ ํ๊ธฐ๋ ํฉ๋๋ค.( And so we don't use soft references or weak references. They don't work well. We use hard references and set a strong budget. we are conservative in setting that budget by scaling down with the screen and really the number of pixels ) ๊ทธ๋๋ ๋จ์ํ ๊ตฌํ์ด๋ผ๋ ์ ์์ WeakImageCache ์ฐธ๊ณ ํ ๋งํฉ๋๋ค.
- Ficusk์ GsonRequest : Google Gson ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก json์ ํ์ฑํ๋ ๊ตฌํ. Google I/O 2013 ๋ฐํ์์ ๊ณต์ .
- njzk2์ DelegatingRequest : Request์ addHeader()๋ฉ์๋๋ก ํค๋ ์ค์ ๊ฐ๋ฅ. HTTP ์ธ์ฆ ๋๋ฌธ์ ๋ง๋ ํด๋์ค.
- Jake Wharton์ OkHttpStack : HttpURLConnection์ด๋ Apache HttpClient๋์ OkHttp๋ฅผ ์ฌ์ฉํ ์ ์๋ ๊ตฌํ
- benvd์ FadeInNetworkImageView : ์ด๋ฏธ์ง ๋ณด์ผ ๋ ํ์ด๋์ธ ์ ๋๋ฉ์ด์ ์ ์ถ๊ฐ
- njzkw์ ExtendedImageLoader : ๊ธฐ์กด ImageLoader๊ฐ ๋ด๋ถ์ ์ผ๋ก ImageRequest๋ฅผ ์ฌ์ฉํ๋๋ฐ, ์ด ํด๋์ค๋ Request ๊ตฌํ์ฒด๋ ์ฌ์ฉ ๊ฐ๋ฅ.
- http://www.kpbird.com/2013/05/volley-easy-fast-networking-for-android.html
- http://kvandroidapp.blogspot.kr/2013/05/example-using-volley-google-framework.html
- http://ogrelab.ikratko.com/android-volley-examples-samples-and-demos/\
- https://github.com/ogrebgr/android_volley_examples\
- http://blogs.captechconsulting.com/blog/raymond-robinson/google-io-2013-volley-image-cache-tutorial
- ๊ตฌ๊ธ HTTP ๋ง์คํฐ์ด์ ํ์ง OkHTTP ๊ฐ๋ฐ์์ธ Jesse Wilson๊ฐ ๋ง๋ ์์ : https://github.com/swankjesse/android-http-examples/tree/master/volley-app
- http://java.dzone.com/articles/android-%E2%80%93-volley-library
- https://github.com/adamrocker/volley
- http://www.technotalkative.com/android-volley-library-example/\
์์ ์ ์์์ ์ ๋ฆฌํ์ผ๋, ๋ณด๋ค ์์ธํ ๋ด์ฉ์ ์ํ์๋ ๋ถ๋ค์ ์ํด์ Google IO 2013์์ Ficus Kirkpatrick๊ฐ ํ๋ Volley์ ๋ํ ๋ฐํ ๋ด์ฉ ์ ์ฒด๋ฅผ ๊ธ๋ก ํ์ด๋ดค์ต๋๋ค.
Volley๋ ํ ๋์ค๋ ๋ฐ๋ฆฌ๋ณผ์ ๋ฐ๋ฆฌ๋ฅผ ์ฐ์ํ๊ฒ ํ๊ณ , ํด๋ผ์ด์ธํธ๊ฐ ๋ท ๋์ด๋ก ์๋ฒ์ ์์ฒญ์ ์๋ฉด ๊ทธ๊ฒ์ด ๋์์จ๋ค๋ ์์ ๊ฐ ๋๊ธฐ๋ ํฉ๋๋ค.( a client sends a request a server over the net. It comes back.) ๊ทธ๋ฌ๋ ์ ๊ฐ ์ด๋ฆ์ ์ง์ ๋๋ '์ผ์ ์ฌ๊ฒฉ'( A burst or emission of many things or a large amount at once.) ์ ๊ด๊ฒฝ์ ์๊ฐํ์ต๋๋ค.
( ์ด๋ฏธ์ง ์ถ์ฒ : http://www.kpbird.com/2013/05/volley-easy-fast-networking-for-android.html )
์ฑ์ UI๊ฐ ๋ฐ์ ํ๊ณ ์๋ฆ๋ค์์ง๋ฉด์ ๋ ๋ง์ ๋ฉํ๋ฐ์ดํฐ์ ์ด๋ฏธ์ง๊ฐ ์ฐ์ด๊ณ , ๋ ๋ง์ ๋คํธ์ํฌํธ์ถ์ด ํ์ํ๊ฒ ๋์์ต๋๋ค. ๊ทธ๋ฐ ์์ฒญ์ ๋ณ๋ ฌ๋ก ๋ ๋ ค์ ์ฑ์ ์ฑ๋ฅ์ ๋ ํฅ์์ํฌ๋งํ ์ฌ์ง๊ฐ ๋ ์ปค์ก์ต๋๋ค. Volley๋ ์ค๋ ๋ฉ์ด๋ ๋๊ธฐํ์ ๋ํด์ ์ค์ค๋ก ์๊ฐํ ํ์์์ด ๋ณํ์์ฒญ์ ์ฝ๊ฒ ํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ์ํ ๊ธฐ๋ฅ์ ๋น์ฅ ๋ฐ๋ก ์ ๊ณตํฉ๋๋ค. ์๋ฅผ ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- JSON API ์ ๊ทผ, ์ด๋ฏธ์ง ๋ก๋ฉ, Raw Text ์ฒ๋ฆฌ
- ๋ฉ๋ชจ๋ฆฌ์ ๋์คํฌ ์บ์ฌ
- ๊ฐ๋ ฅํ ์ปค์คํฐ๋ง์ด์ง ๋ฅ๋ ฅ : ์ฌ์๋์ ๋ฐฑ์คํ ์๊ณ ๋ฆฌ์ฆ, ์์ฒญ ์์ ๋ฑ์ ๋ํด์ ์ค์ค๋ก ์ ์ ๊ฐ๋ฅ.
- ๋๋ฒ๊น ๊ณผ ์ถ์ ๋๊ตฌ : ๋ฒ๊ทธ๋ฅผ ์ก๊ณ ํ๋กํ์ผ๋งํด์ ์ต์ ํ์ ๋์์ด ๋๋ ์ ๋ณด๋ฅผ ์ ๊ณต
์ด๋ฏธ ์๋๋ก์ด๋๋ Apache Http Client์ HttpURLConnection์ผ๋ก HTTPํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ ๊ณตํ๊ณ , ๊ทธ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ์ฌ๋๋ค์ ์ด๋ฏธ ๋ง์ ์ฑ์ ๋ง๋ค์์ต๋๋ค. ๊ทธ๋ฐ๋ฐ Foursquare, Twitter, Youtube, New and Weather ๊ฐ์ ์ฑ๋ค์ ๊ณตํต์ ์ผ๋ก ํ๊ณ ์๋ ์ผ์ด ๋ง์ต๋๋ค. ํ์ด์ง๋๋ ๋ชฉ๋ก์ ๋ณด์ฌ์ฃผ๊ณ , ์ธ๋ค์ผ ์ด๋ฏธ์ง๋ฅผ ListView์์ ๋ฃ์ต๋๋ค. ๊ทธ๋ฌํ ์ฑ๋ค์ ์๋ต cache, ์ฌ์๋, ๋ณ๋ ฌ ์์ฒญ ๋ฑ ๊ทผ๋ณธ์ ์ผ๋ก ๊ฐ์ ์ผ์ ํ๋ ๋ฐํด๋ฅผ ์ฌ๋ฐ๋ช ํ๊ณ ์์ต๋๋ค.
Volley๋ ์ด๋ฐ๊ฒ๋ค์ ๋ํ ๊ณตํต ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๊ณ , ๊ฐ๋ฐ์๊ฐ ์คํ๋ก์ง์ ๋ํด์ ๋ ์ ๊ฒฝ์ธ ์ ์๋๋ก ํด์ฃผ๊ณ , ๊ตฌ๊ธ์์ ๋ช๋ ๋์ ์์ฉ ์์ค์ ์ฑ์ ๋ง๋ค๋ฉด์ ์ป์ ๊ตํ์ ํฌ์ฅํด ๋์์ต๋๋ค.
Volley๋ UI์์์ ๋ฉํ ๋ฐ์ดํฐ์ ์ด๋ฏธ์ง๋ฅผ ๋ฃ๋ ์๋์ ์ผ๋ก ์ ์ ์ฉ๋์ RPC์คํ์ผ์ ๋คํธ์ํฌ ๋์์ ๊ฐ์ฅ ์ ๋ง์ต๋๋ค. UI์ ๋คํธ์ํฌ๊ฐ ๊ต์ฐจํ๋ ์ง์ ์์ ํ์ํฉ๋๋ค. ๋น์ทํ ํน์ฑ์ ์ง๋ ๋ฐฑ๊ทธ๋ผ์ด๋ RPC์์ ์๋ ๊ด์ฐฎ์ต๋๋ค. ๊ทธ๋ฌ๋ ์๋ต์ ์ ์ฒด๊ฐ ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ผ๊ฐ๊ธฐ ๋๋ฌธ์ ํฐ payload์๋ ์ ํฉํ์ง ์์ต๋๋ค. ์ฆ, Video๋ MP3 ๋ค์ด๋ก๋ ๊ฐ์ Streaming ๋์์๋ ์ ํฉํ์ง ์์ต๋๋ค. ๊ตฌ๊ธ์์๋ RPC์คํ์ผ์๋ Volley๋ฅผ ์ฐ๊ณ ์ค๋๊ฑธ๋ฆฌ๋ ํฐ ํ์ผ์ ๋ค์ด๋ก๋ ๋์์๋ DownloadManager ๊ฐ์๊ฒ์ ์ฐ๋ ๋ช๊ฐ์ ์ฑ์ด ์์ต๋๋ค. ๋ชจ๋ ์์ ์ Volley๋ฅผ ์ธ ํ์๋ ์์ต๋๋ค.
์ง๊ธ๊น์ง ๋งํ ๊ณตํต์ ์ธ ํจํด์ธ, ํ์ด์ง๋ณ ์กฐํ๊ฐ ๊ฐ๋ฅํ ๋ชฉ๋ก์ด ์๊ณ , ๊ทธ ๋ชฉ๋ก์์ ๊ฐ๊ฐ์ ํญ๋ชฉ์๋ ์ ๋ชฉ, ์ค๋ช , ์ธ๋ค์ผ์ด ๋ค์ด๊ฐ๋ ์ฑ์ ์์ ๋ก ๋ณด๊ฒ ์ต๋๋ค. ์๋ฒ์์๋ title, description, image_url ์ด ๋ค์ด๊ฐ ๊ฐ์ฒด๋ฅผ json ๋ฐฐ์ด๋ก ๋ฐํํ๋ ๋จ์ํ ํ๋กํ ์ฝ์ ์ ๊ณตํฉ๋๋ค. ํด๋ผ์ด์ธํธ ์ชฝ์ Activity, Adaptor, ListView๋ก ์ด๋ฃจ์ด์ง๋ ์ ํ์ ์ธ ๊ตฌ์กฐ์ ๋๋ค. Activity๋ Adaptor๋ฅผ ๊ฐ์ง๊ณ ์๊ณ , Adaptor๋ API์๋ฒ๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๊ณ View๋ฅผ ๋ง๋ค์ด๋ ๋๋ค.
์๋์ฝ๋๋ Adaptor์ ์ ํ์ ์ธ getView(..) ๋ฉ์๋์ ๊ตฌํ์ ๋๋ค.
@Override
public View getView(int position, View view, ViewGroup parent) {
// Load more if we're close to the end.
if(closeToEnd(position) && mLoading) {
loadMoreData()
}
}
์ฌ๊ธฐ์ ์ ์ฉ๋ ๋งํ ๋ณดํธ์ ์ธ ๊ธฐ๋ฒ์, ์ด๋ฏธ์ง๋ฅผ ๋ค์ด๋ก๋ํด์ผํ ๋ getView์์ ๋์ด์จ position ํ๋ผ๋ฏธํฐ๋ฅผ ์ ํธ๋ก ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ์๋ฅผ ๋ค๋ฉด ํ ํ์ด์ง์ 10๊ฐ์ ํญ๋ชฉ์ด ์์๋, 8๋ฒ์งธ position์ผ๋ก ์์ฒญ์ด ๋ค์ด์ค๋ฉด ๋ค์ ํ์ด์ง์ ๋ก๋ฉ์ ์์ํ๋ ์์ ๋๋ค.
loadMoreData()๋ ๋ณดํต AsyncTask๋ฅผ ํ์ฉํฉ๋๋ค. ์๋์ doInBackGround(..) ๋ฉ์๋ ๊ตฌํ์ด ์์ต๋๋ค.
protected JSONObject doInBackground(URL ... params) {
HttpURLConnection conn = (HttpURLConnection)
params[0].openConnection();
InputStream input = conn.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
copy(input, baos );
JSONObject jsonRoot = new JSONObject(baos.toString());
return jsonRoot;
}
๊ตฌํ์ ํ์ดํ์ง๋ง ์ฌ๊ธฐ์๋ ๋ฐ๋ณต์ ์ธ ์ฝ๋(boilerplate code)๊ฐ ๋ง์ด ๋ค์ด๊ฐ๋๋ค. ์์ ์ฝ๋์์๋ ์ฌ๋ผ์ด๋์ ๋ง์ถ๊ธฐ ์ํด ์๋ตํ์ง๋ง ํต์ ์คํจ Exception์ฒ๋ฆฌ, ํ์ฑ์คํจ Exception์ฒ๋ฆฌ์ Stream๋ซ๊ธฐ ๊ฐ์ ์ฝ๋๋ฅผ ํฌํจํ๋ฉด ์ฝ๋๊ฐ 2๋ฐฐ๋ ๋์ด๋ฉ๋๋ค.
๋ค์์๋ onPostExecute(..) ๋ฉ์๋๊ฐ ๋ฉ์ธ์ค๋ ๋์์ ์คํ๋๊ณ , JSON์ ํ์ฑํด์ ๊ฐ๊ฐ์ ์์ดํ ์ ๋ฝ์๋ด๊ณ , Adaptor์ ์ฐ๊ฒฐ๋๋ List์ ๋ฃ์ ํ์ ListView์ ๋ณด์ฌ์ง์ ์๋๋ก ์๋ฆฝ๋๋ค.
protected void onPostExecute(JSONObject jsonRoot){
List<Items> items = parseJson(jsonRoot);
appendItemsToList(item);
notifyDataSetChanged();
}
๋ฐ์ดํฐ์ ํจ๊ป getView๋ก ๋์์ ๋ณด๊ฒ ์ต๋๋ค. ์ด์ title๊ณผ description์ ๋ ํ ์คํธ ์์ฑ์ ๋ณด์ฌ์ค ์ ์์ต๋๋ค. ์ด๋ฏธ์ง URL๋ ์๊ธฐ ๋๋ฌธ์ ๋ก๋ฉ์ ์์ํด์ผ ํฉ๋๋ค. ์ฌ๊ธฐ์ ๋ค์ AsyncTask๋ฅผ ํ์ฉํฉ๋๋ค.
@Override
public View getView(int position, View view, ViewGroup parent) {
// Load more if needed, make ViewHolder, etc.
mTitleView.setText(item.title);
mDescriptionView.setText(item.description);
new LoadImageTask(holder.imageView).execute(new URL(BASE\_URL + item.imageURL));
}
์๋์ ์์งํ ๋ฐฉ์์ผ๋ก ์ด๋ฏธ์ง๋ฅผ ๋ก๋ฉํ๋ AsyncTask๊ตฌํ์ ๋ด ์๋ค.
// private class LoadImageTask extends AsyncTask<URL, Void, BitMap>
public LoadImageTask(ImageView imageView){
mImageVIew = imageView;
}
protected BitMap doInBackground(URL ... params) {
HttpURLConnection conn = (HttpURLCOnnection)
params[0].openConnection();
InputStream input = conn.getInputStream();
return BitmapFactory.decodeStream(input);
}
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitMap(result);
}
์์ฑ์๋ฅผ ํตํด ImageView๋ฅผ ์ ์ฅํด ๋๊ณ , ๋์ค์ ์ฃผ์ด์ง URL์ ์ด๋ฏธ์ง๋ฅผ ๊ทธ ์์ ์ฌ๋ฆฝ๋๋ค. ๋ฐฑ๊ทธ๋ผ์ด๋์์๋ HttpURLConnection์ ์ด์ด์ ์๋ต ์คํธ๋ง์ ์ป๊ณ , ๊ทธ๊ฒ์ BitmapFactory์ ๋๊ฒจ์ ๋์ฝ๋ฉํฉ๋๋ค. ์ฌ๊ธฐ์๋ try,catch๋ ๋ค ์๋ตํ์ต๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก ๋ฐ๋ณต๋๋ ์ฝ๋๊ฐ ๋ง์ต๋๋ค. onPostExecute๋ฅผ ํตํด ๋ค์ ๋ฉ์ธ์ค๋ ๋์์ ์์ฑ์๋ฅผ ํตํด ์ ์ฅํ๋ ImageView์ image๋ฅผ ์ง์ ํฉ๋๋ค.
์์ ์์ ์๋ ๋ช ๋ฐฑํ ๋ฒ๊ทธ๋ถํฐ ๊ทธ๋๋ก ๋๊ณ ์ถ์ํ๊ธฐ์๋ ๋๋ฌด ๋นํจ์จ์ ์ธ ์์ ๋ฑ ์ฌ๋ฌ๊ฐ์ง ๋ฌธ์ ์ ์ด ์์ต๋๋ค. ๊ทธ๋ฐ ๋ฌธ์ ๋ฅผ ์ดํด๋ณด๊ณ , ์ ํ์ ์ธ ์ ๊ทผ๋ฐฉ๋ฒ๊ณผ Volley์ ์ ๊ทผ๋ฐฉ์์ ๋น๊ตํด ๋ณด๊ฒ ์ต๋๋ค.
์์ ์ฝ๋์์๋ AsyscTask.execute()๋ฅผ ์ด์ฉํ๊ธฐ ๋๋ฌธ์ ๋ชจ๋ ๋คํธ์ํฌ ์์ฒญ์ด ์์ฐจ์ ์ผ๋ก ์คํ๋ฉ๋๋ค. ๊ทธ ์ฝ๋์์๋ AsyncTask.executeOnExecutor()๋ฅผ ์ฐ์ง ์์๊ณ AsyncTask์ THREAD_POOL_EXECUTOR๋ฅผ ๋๊ธฐ์ง๋ ์์์ต๋๋ค. ๋ฐ๋ผ์ ์์ฒญ์ ์๊ฒฉํ๊ฒ FIFO(First In First Out)๋ก ์ฒ๋ฆฌ๋์ด์, ์คํฌ๋กค์ ๋ด๋ ค์ ๋ค์ํ์ด์ง๋ฅผ ์ฝ์ผ๋ ค๊ณ ํด๋ ์ ํ์ด์ง์ ์ด๋ฏธ์ง ๋ก๋ฉ์ด ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ ค์ผ ํฉ๋๋ค.
Volley๋ ์ค๋ ๋ํ์ ํ์ฉํด์ ์๋์ผ๋ก ๋คํธ์ํฌ ์์ฒญ์ ์ค์ผ์ฅด๋งํฉ๋๋ค. ํ์ size๋ฅผ ์ง์ ํ๊ฑฐ๋ ๋ํดํธ ๊ฐ์ ์ธ ์๋ ์์ต๋๋ค. playstore์์ ํ ์คํธํ์ ๋, thread๊ฐ 4๊ฐ์ผ๋ ์ฐ๋ฆฌ๋ ์ต์์ ๊ฒฐ๊ณผ๋ฅผ ์ป์ต๋๋ค. Volley๋ ์์ฒญ ์ฐ์ ์์๋ ์ ๊ณตํฉ๋๋ค. ๊ทธ๋์ ๋ฉ์ธ๋ฉํ๋ฐ์ดํฐ์ ์ฐ์ ์์๋ฅผ ๋์ด๊ณ , ์ด๋ฏธ์ง๋ก๋ฉ์ ๋ฎ์ ์ฐ์ ์์๋ฅผ ์ค ์ ์์ต๋๋ค. ๋จ ํ๋์ ์ค๋ ๋์์ ์คํ๋๋ค๊ณ ํด๋ ์ ํ์ด์ง์ ์ด๋ฏธ์ง ๋ก๋ฉ์ ๊ธฐ๋ค๋ฆฐ๋ค๊ณ ๋ค์ ํ์ด์ง๋ฅผ ๋ชป ์ฝ๋ ์ผ์ ๋ฐ์ํ์ง ์์ต๋๋ค.
ํ๋ฉด์ ํ์ ์ํค๋ฉด Activity๊ฐ destroy๋ ํ์ ์ฌ์์ฑ๋๊ณ , ์ฒ์๋ถํฐ ๋ชจ๋ ์์ ์ ์์ํด์ผ ํฉ๋๋ค. ๋คํธ์ํฌ๋ก๋ถํฐ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๋ก๋ฉํด์ผํ๋ค๋ ์๋ฏธ์ ๋๋ค. ์ด๊ฒ์ ํฐ ์ํด์ ๋๋ค. ์ด๋ฏธ์ง๋ฅผ LRU Cache๋ HashMap์ ๋ฃ๊ณ Cache๋ฅผ ์ด์ฉํด์ ํด๊ฒฐํ ์๋ ์์ง๋ง, ๊ทธ๋ฐ ์ง๋ฃจํ ์์ ์ ์ค์ค๋กํด์ผ ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ Cache๊ฐ process์ lifetime๋์๋ง ์ด์๋จ๊ธฐ ๋๋ฌธ์ ๋ค์์ ์ฑ์ด ์์๋ ๋๋ ๋์์ด ์ ๋ฉ๋๋ค.
Volley๋ ์๋ต์ ๋ํด์ ๋ฉ๋ชจ๋ฆฌ์ Disk๋ฅผ ํ์ฉํ๋ ํฌ๋ช ํ Cache๋ฅผ ๊ธฐ๋ณธ์ ๊ณตํฉ๋๋ค.ํฌ๋ช ํ Cache๋ ํธ์ถํ๋์ชฝ์์ Cache์ ์กด์ฌ๋ฅผ ์ ๊ฒฝ์ฐ์ง ์์๋ ๋๋ค๋ ์๋ฏธ์ ๋๋ค. ์ฆ Cache๊ฐ ๋๋ฉด ์์ฒญ๋๊ฒ ๋น ๋ฅธ ๋คํธ์ํฌ ์๋ต์ฒ๋ผ ๋์ํฉ๋๋ค. Volley์์๋ ์ค์ค๋ก ๋ง๋ Cache ๊ตฌํ์ ์จ๋ ๋๊ณ ๊ธฐ๋ณธ ์ ๊ณตํ๋๊ฒ์ ์จ๋ ๋ฉ๋๋ค. ์ ๋ง ๋น ๋ฅด๊ณ 10~50k์ ๊ด๊ณ ์ด๋ฏธ์ง์ ์๋ต์๊ฐ์ด ๋ณดํต ์ millisecond๊ฐ ๊ฑธ๋ ธ์ต๋๋ค. Volley๋ Imageloading์ ๋ ๋์๊ฐ ๋๊ตฌ๋ฅผ ์ ๊ณตํ๋๋ฐ, ๋ค์์ ์ดํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
๋น์ทํ ์ฑ์ ๊ตฌํํด๋ณธ ์ฌ๋์ ์์ ์์ ์์ ๋ฒ๊ทธ๋ฅผ ๋ฐ๋ก ๋ฐ๊ฒฌํ์ จ์ ๊ฒ์ ๋๋ค. ์ด๋ฏธ์ง ๋ก๋ฉ ์์ฒญ์ ๋ ๋ฆฌ๊ณ ๊ทธ ์ฌ์ด์ ์ฌ์ฉ์๊ฐ ์คํฌ๋กค์ ๋ด๋ ธ์ ๋, View๋ฅผ ListView์์ ์ฌํ์ฉํ๋ ค๊ณ ํด๋ ์ ํ์ด์ง์์ ์์ฒญํ ์ด๋ฏธ์ง๊ฐ ๋ค๋ฆ๊ฒ ๋ํ๋ ๊ฐ๋ฅ์ฑ์ด ์์ต๋๋ค. ์ด๋ฏธ์ง๋ฅผ ๋ก๋ฉํ๋ AsyncTask๊ฐ ์ค์ ๋ก ๋๋๊ธฐ ์ ์ ์ ํ์ด์ง์ View๋ฅผ ๋ณด์ฌ์ฃผ๋ postExecute(..) ๋ฉ์๋๊ฐ ์คํ๋๋ค๋ฉด, ๋์ด์ ๊ทธ ์ ์ AsyncTask์์ ๊ฑด๋๋ ค์๋ ์ ๋๋ ImageVIew์ bitmap์ ์ง์ ํ๊ฒ ๋ฉ๋๋ค. ์ฌ๊ธฐ์ ViewHolder๋ฅผ ๋ง๋ค๊ณ , URL์ ์ ์ฅํด์ ImageView์ ์ง์ ํ๊ธฐ ์ ์ ์ด๋ฏธ์ง URL์ ํ์ธํด๋ณผ์๋ ์์ต๋๋ค. ์ด ๋ฐฉ์์ ๋ ์ด์ ์ธ๋ชจ๊ฐ ์๋ Request๊ฐ ๊ทธ๋๋ก ๋๋๊ฒ ๋ด๋ฒ๋ ค๋๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋ฅ ๋ฒ๋ฆฌ๊ธฐ ๋๋ฌธ์ ๋๋ฆฌ๊ณ ๋ญ๋น๊ฐ ์ฌํฉ๋๋ค.. AsyncTask๋ฅผ ์ถ์ ํด์, View๋ฅผ ์ฌ์ฌ์ฉํด์ผ ํ ๋๋ ์์ฒญ ์ทจ์๋ฅผ ํ ์๋ ์์ง๋ง, ๊ทธ๋ ๊ฒ ํ๋ ค๋ฉด ๊ฐ๋ฐ์๊ฐ ํ ์ผ์ด ๋ง์ต๋๋ค.
Volley๋ ์์ฒญ ์ทจ์ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ๋จ ํ๋์ Request๋, ํน์ ๋ฒ์๋ฅผ ์ง์ ํด์ ์ทจ์ํ ์ ์์ต๋๋ค. Volley์ toolbox์์ ์ ๊ณตํ๋ NetworkImageView๋ฅผ ์ฐ๋ฉด ์์ฒญ์ทจ์์ ๋ํ ๋ชจ๋ ๊ฒ์ ์์์ ๋ค ์ฒ๋ฆฌํด์ค๋๋ค.
์ง์ ๋ธ๋ ๋ ์ด์ ๊น์ง์ HttpURLConnection์ ๋ฒ๊ทธ๊ฐ ๋ง๊ณ ์ ๋ขฐํ๊ธฐ ์ด๋ ต์ต๋๋ค. ์ฌ๊ธฐ์ ์๋ ์ํ์ฝ๋๋ ํ๋ก์์ ๊ทธ ์ด์ ์์๋ ๋ฌธ์ ๊ฐ ์๊ธธ ์๋ ์์ต๋๋ค. Apache HTTP Client๋ฅผ ์ฌ์ฉํ ์๋ ์์ง๋ง, ์ญ์๋ ๋ฒ๊ทธ๊ฐ ๋ง๊ณ ๋ ์ด์ ์ง์๋์ง ์์ต๋๋ค.
Volley๋ ๋คํธ์ํฌ ์ ์ก์ ์ถ์ํํ์ต๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ํ๋ก์ ์ด์ ๋ฒ์ ์๋ Apache Http Client, ๊ทธ ์ดํ ๋ฒ์ ์์๋ Apache HTTP Client๋ฅผ ์๋๋ค. ์ด๋ฌํ ์ ๊ทผ๋ฒ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ๋ฟ๋ง ์๋๋ผ ๋ค๋ฅธ ๊ธฐํ๋ฅผ ์ ๊ณตํ๋๋ฐ, FourSquare์ OkHttp๋ฅผ ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด ์ ์ฒด ์ฝ๋๋ฅผ ๊ณ ์น ํ์์์ด ์ฑ์ ํ ๋ถ๋ถ๋ง ๋์ฒดํ๋ฉด ๋ฉ๋๋ค.
Volley์์ ์ฃผ๋ก ์ฌ์ฉ์๊ฐ ์ ํ๋ 2๊ฐ์ ํด๋์ค๋ RequestQueue์ Request์ ๋๋ค. RequestQueue๋ request๋ฅผ ๋คํธ์ํฌ์ ๋์ง๋ ์ธํฐํ์ด์ค์ ๋๋ค. RequestQueue๋ ํ์์ ๋ฐ๋ผ ๋ง๋ค์๋ ์์ง๋ง, ๋ณดํต singleton์ผ๋ก ์๋๋ค. mRequestQueue ์ ImageLoader๋ ์๋์ ๊ฐ์ด ์์ฑํฉ๋๋ค.
mRequestQueue = Volley.newRequestQueue(context);
mImageLoader = new ImageLoader(mRequestQueue, new BitmapLruCache());
๋ค์ ์ฝ๋๋ loadMoreData()์ Volley ๋ฒ์ ์ ๋๋ค.
mRequestQueue.add(new JsonObjectRequest(Method.GET, url, null,
new Listener<JSONObject>() {
public void onResponse(JSONObject jsonRoot) {
mNextPageToken = jsonGet(jsonRoot, "next", null);
List<Items> items = parseJson(jsonRoot);
appendItemsToList(item);
notifyDataSetChanged();
}
}
);
Volley toolbox์์ ์ ๊ณต๋๋ JsonObjectRequest๋ฅผ ์ฌ์ฉํด์ ํธ์ถ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ ์์ฒญํ์ ์ถ๊ฐํฉ๋๋ค. Request๊ฐ์ฒด์ ์์ฑ์์ ํ๋ผ๋ฏธํฐ๋ก ๋จ๊ธฐ๋ Listener๋ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๋ ํ์ค ์ฝ๋ฐฑ ์ธํฐํ์ด์ค์ ๋๋ค. Listener๋ AysncTask์ postExecute(..)์ ์ ์ฌํฉ๋๋ค. ์ฌ๊ธฐ์ ๊ฒฐ๊ณผ๋ฅผ ํ์ฑํ๊ณ View์ ๋ณด์ฌ์ค ์์ดํ ๋ชฉ๋ก์ ์ถ๊ฐํ๊ณ , ๋ฐ์ดํฐ์ ์ด ๋ณ๊ฒฝ๋์๋ค๋ ๊ฒ์ ํต์งํฉ๋๋ค. Boilerplate ์ฝ๋๊ฐ ์์ด์ก๊ณ , AsyncTask์ ๋น์ทํ ๊ตฌ์กฐ ๋๋ถ์ ๊ธฐ์กด์ ์ฑ์ ํฌํ ํ๊ธฐ๋ ์ฝ์ต๋๋ค.
์ด๋ฏธ์ง๋ฅผ ๊ฐ์ง๊ณ ์ค๋ ์์ ์ ๋ ํธํด์ก์ต๋๋ค.
// retreving images with ImageLoader
if (holder.imageRequest != null) {
holder.imageRequest.cancel();
}
holder.imageRequest = mImageLoader.get(BASE_URL + item.image_url,
holder.imageView, R.drawable.loading. R.drawable.error);
์ด๋ฏธ์ง ์์ฒญ์ view holder์ ์ ์ฅํด๋๊ณ , View๋ฅผ ์ฌํ์ฉํด์ผํ ๋๋ ์์ฒญ์ ์ทจ์ํฉ๋๋ค. Volley toolbox์ ์๋ ImageLoader๊ฐ ๋๋จธ์ง๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค. ๋ฉ๋ชจ๋ฆฌ ์บ์ฌ๋ฅผ ์ ๊ณตํ๊ณ , ๋ก๋ฉ ์ค์ผ๋, ์๋ฌ์ผ๋ ํ์๋ drawable ์์ ์ด๋ฏธ์ง๋ฅผ ์ง์ ํ ์๋ ์์ต๋๋ค.
๋ ๊ฐํธํ๊ฒ๋ ImageView์ subclass์ธ NetworkImageView ํด๋์ค๋ฅผ ํ์ฉํ๋ฉด ๋ฉ๋๋ค. Layout ์ค์ ํ์ผ์ ImageVIew ์ ์ธ๋์ NetworkImageView๋ฅผ ์ง์ ํ๊ณ ImageView ๊ฐ์ฒด์ ์ฃผ์๋ฅผ ์ง์ ํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค.
- \<ImageView
+ \<com.android.volley.NetworkImageView\>
mImageView.setImageUrl(BASE\_URL + item.image\_url, mImageLoader);
NetworkImageView๋ View ๊ณ์ธต ๊ตฌ์กฐ์์ detach๋ ๋ ๊ธฐ์กด์ ์์ฒญ์ ์์์ ์ทจ์ํด์ค๋๋ค.
์์ฒญ์ผ๊ด์ฒ๋ฆฌ(response-batching)๋ Volley์ ๋๋ค๋ฅธ ๋ฉ์ง ๊ธฐ๋ฅ์ ๋๋ค. ImageLoader๋ NetworkImageVIew๋ก ์ด๋ฏธ์ง ๋ก๋ฉํ ๋ ์๋ต์ ๋ฐ์์ ์ ์ ๊ฐ์ง๊ณ ์๋ค๊ฐ UI thread๋ก ํ๊บผ๋ฒ์ ๋ณด๋ ๋๋ค. ์ด ๋๋ถ์ ์ฌ๋ฌ ์ด๋ฏธ์ง๊ฐ UI์์ ๋์์ ๋ํ๋๋ ํจ๊ณผ๋ฅผ ๋ผ ์ ์์ต๋๋ค.
Volley๋ ์๋ก์ด ํ์์ ์์ฒญ์ ๋ง๋ค๊ธฐ์๋ ์ฝ์ต๋๋ค. GSON์ ๋ฆฌํ๋ ์ ์ ์ด์ฉํด์ JSONํํ์ ๋ฐ์ดํฐ๋ฅผ Java Model๋ก ๋ฃ์ด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ์๋์ Volley์์ GSON์ ์ด์ฉํ ์์ฒญ์ ์์ ์ฝ๋๊ฐ ์์ต๋๋ค.
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String json = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(gson.fromJson(json, clazz),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JsonSyntaxException e) {
return Response.error(new ParseError(e));
}
}
๋ถ๊ณผ 60์ค ์ ๋์ ์ฝ๋์ด๊ณ ์์์๋ ๊ทธ ์ผ๋ถ๋ง ๋์์ง๋ง https://gist.github.com/ficusk/5474673์ ์ ์ฒด ์ฝ๋๊ฐ ์ฌ๋ผ๊ฐ ์์ต๋๋ค.
JSON๋ฑ๋ต์ ๋ฌธ์์ด ํ์์ผ๋ก ๋ง๋ค๊ณ , Gson์ ์ด์ฉํด์ ์ํ๋ ๊ฐ์ฒด๋ก ๋ณํ์ํต๋๋ค. HTTP ์๋ตํค๋์ ์๋ charset์ด๋ cache๊ด๋ จ ๊ฐ๋ค์ ํด์ํ๊ธฐ ์ํด Volley์์ ์ ๊ณตํ๋ HttpHeaderParser๋ฅผ ํ์ฉํฉ๋๋ค.
์ด๋ ๊ฒ ๋ง๋ ์๋ก์ด Requestํ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ก๋ฉํ๋ ์ฝ๋๋ ์๋์ ๊ฐ์ต๋๋ค.
mRequestQueue.add(
new GsonRequest<ListResponse> (url, ListResponse.class, null ,
new Listener<ListResponse>(){
public void onResponse(ListResponse response) {
appendItemToList(response.items);
notifyDataSetChanged();
}
}
);
์์ ๋์จ๊ฒ์ฒ๋ผ ๋จ์ํ ์ฝ๋์ ๋๋ค. ์ด ์์ฒญ ๋ฐฉ์์์๋ ํ์ฑ์ด ๋ฉ์ธ์ค๋ ๋๊ฐ ์๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค๋ ๋์์ ์ผ์ด๋์ ๋ณํ์ฑ์ ๋ ํ์ฉํ๋ค๋ ์ ๋ ๋ฉ์ง๋๋ค.
(์ด๋ฏธ์ง ์ถ์ฒ : http://readme.skplanet.com/?p=5072 )
Volley์ ๋ด๋ถ ๊ตฌ์กฐ์ ๊ตฌํ์ด ์ด๋ป๊ฒ ๋์ด์๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค. Volley๋ ์ค๋ ๋ํ์ ์ ๊ณตํ๋๋ฐ, 'Cache dispatcher'์ 1๊ฐ์ ์ค๋ ๋, 'Network dispatcher'์ 1๊ฐ ์ด์์ ์ค๋ ๋๋ฅผ ํ ๋นํฉ๋๋ค.
'Cache Disatcher'๋ ์์ฒญ์ ๋ถ๋ฅํ๋ ์ผ์ ํฉ๋๋ค. ์์ฒญ์ Cache์์ ๋นผ์ผํ ์ง, Network๋ก ํธ์ถํด์ผํ ์ง๋ฅผ ๊ฒฐ์ ํฉ๋๋ค. cache miss๋ cache hit๋ expired ๋์์ ๋ ๋ถ๊ธฐ์ฒ๋ฆฌ๋ฅผ ํฉ๋๋ค. Expired cache์ผ๋๋ cache ์๋ต์ 'Network dispatcher'์ ๋๊ฒจ์ค ์ฑ ์๋ ์๋๋ฐ, ETag match๋ ํ์ฉํด์ ์๋ฒ๊ฐ 304 response code๋ฅผ ์ค ์๋ ์๊ฒํ๊ธฐ ์ํด์์ ๋๋ค. Network dispatcher๋ HTTP์์ฒญ์ ํ๊ณ , ๊ฒฐ๊ณผ๋ฅผ ํ์ฑํํ์ Main ์ค๋ ๋์ ์๋ต์ ์ ๋ฌํฉ๋๋ค.
๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ์๋ผ๋ฉด ์ด๋ฐ ๋ด๋ถ๊ตฌ์กฐ๋ฅผ ํฌ๊ฒ ์ ๊ฒฝ ์ธ ํ์๋ ์๊ณ , ๋ฉ์ธ ์ค๋ ๋์์ ์์ฒญ ํ์ ์ถ๊ฐํ๊ณ , ๋นผ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ ์กฐ๊ธ ๋ ์งํ์ํฉ์ ๊น์ด ๋ค์ฌ๋ค๋ณด๊ณ ์ถ๋ค๋ฉด ๋๋ฒ๊น ์ ๋ณด์ ํ์ฉํ๋ฉด ๋ฉ๋๋ค. ์์คํ ์์ฑ์ผ๋ก ๋๋ฒ๊น ์ ๋ณด๋ฅผ ๋ณด๊ฒ ๋ค๊ณ ์ค์ ์ ํ๋ฉด, ์คํ ์ฐ์ ์์, ์คํ ์ค๋ ๋, ๋จ๊ณ๋ง๋ค ๊ฑธ๋ฆฐ ์๊ฐ ๋ฑ Dispatch pipline์ ์์ธํ ์ ๋ณด๋ฅผ ํ์ธํ ์ ์์ต๋๋ค. ์ด๋ฐ ์ ๋ณด๋ฅผ ํตํด ์ดํ๋ฆฌ์ผ์ด์ ์ ๊ฐ์ ์ง์ ์ ์ฐพ์ต๋๋ค. PostResponse์ done์ฌ์ด์ ๋ง์ ์๊ฐ์ด ์ง์ฒด๋๊ณ ์๋ค๋ฉด ๋ฉ์ธ ์ค๋ ๋์์ ๊ฒฝ์์ด ์ผ์ด๋๊ณ ์๊ณ ๊ฑฐ๊ธฐ์ ๋๋ฌด ๋ง์ ์ผ์ ํ๊ณ ์๋ค๋ ์ ํธ์ด๊ณ , ๊ทธ ๋ถ๋ถ์ ๋ ๊น์ด ํ ์๋ ์์ต๋๋ค.
๋ง์ฝ ํ๋์ ์ค๋ ๋์์ ๋ชจ๋ ์์ ์ ํ๊ณ , ๋ค๋ฅธ Worker์ค๋ ๋์ ์๋ฌด๊ฒ๋ ๊ณต์ ํ์ง ์๋๋ค๋ฉด Locking์ ๋ํด์ ์ ๊ฒฝ์ธ ํ์์์ต๋๋ค. Locking์ ์ด๋ ต๊ธฐ ๋๋ฌธ์ ์๋ฌด๋ ๊ฑฐ๊ธฐ์ ๋ํด ๊ณ ๋ฏผํ๊ธฐ๋ฅผ ์ํ์ง ์์ต๋๋ค.
ํ๋์ ์๋ฅผ ๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
public void onPostExecute(Result r) {
if (getActivity() == null ) {
return;
}
}
๋ง์ ์ฌ๋๋ค์ ์์ ๊ฐ์ ์ฝ๋๋ฅผ ์๋๋ค. AsyncTask๊ฐ ๋๋ฌ์ ๋๋ Activity์์ ์ด๋ค ์ผ์ด ์ผ์ด๋ฌ๋์ง ํ์ ํ๊ธฐ์๋ ๋๋ฌด ๋ฆ์๊ธฐ ๋๋ฌธ์, NPE ์ฒดํฌ ์ฝ๋๋ฅผ ๋ฃ์ต๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด postExecute์์ AsyncTask๊ฐ ๋๋ฌ์๋ UI๊ฐ ์ฃฝ์ ์๋ ์์ต๋๋ค.๊ทธ๋ฌ๋ ์ด๋ฐ ์ฒ๋ฆฌ๋ ๋ฌด์ํ request๋ฅผ ํ์ฉํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ CPU ์ธ์ดํด, ๋ ธ๋ ฅ๊ณผ network bandwidth, ๋ฐฐํฐ๋ฆฌ ์๋ชจ ๋ฉด์์ ๋ญ๋น์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ ์ฒด ์ฝ๋์ ๋ณด๊ธฐ ์ซ์ ํ์ ์ ๋จ๊น๋๋ค. Volley๋ ๊ฐ๋ ฅํ ์ทจ์ API๋ฅผ ์ ๊ณตํฉ๋๋ค. Volley์์๋ ๋ชจ๋ ์์ฒญ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฉ์ธ์ค๋ ๋๋ก ์ ๋ฌ๋๋๋ฐ, ๋ง์ฝ ๋ฉ์ธ์ค๋ ๋์์ ์์ฒญ์ ์ทจ์ํ๋ค๋ฉด Volley๋ ๊ทธ ์๋ต์ด ์ ๋ฌ๋์ง ์๋๋ก ๋ณด์ฅํฉ๋๋ค.
์๋์ ๊ฐ์ด ์งํ ์ค์ธ ๋ชจ๋ ์์ฒญ๊ฑด์ ํ๋์ฉ ์ทจ์ํ๋ฉด Listener ๋ฑ์์ Null check๋ฅผ ํ ํ์๊ฐ ์์ต๋๋ค.\
@Override
public void onStop(){
for(Request<?> req : mInflightReqest) {
req.cancel();
}
}
๊ทธ๋ฌ๋ ์ฌ์ ํ AsyncTask๋ฅผ ์ธ ์๋ ์์ต๋๋ค. ๊ทธ๋ด ๊ฒฝ์ฐ๋ฅผ ๋๋นํด์ Volley์์๋ ์ทจ์ํ ์์ฒญ์ ๋ฒ์๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค. ํน์ Activity์ ์ํ ๋ชจ๋ ์์ฒญ์ ์๋์ ๊ฐ์ด ์ทจ์ํฉ๋๋ค.
public void onStop() {
mRequestQueue.cancelAll(this);
}
๋ฐ๋์ ๋ฒ์๋ฅผ Activity๋ก ์ง์ ํ ํ์๋ ์์ต๋๋ค. ํ๋์ ๋ทฐ์ ์๋ ์ธ๋ค์ผ๊ทธ๋ฃน ๊ฐ์ ๋ ์์ ๋ฒ์๋ก ์ ์ํด๋ ๋ฉ๋๋ค.
์๋์ ๊ฐ์ด RequestFilter๋ฅผ ๊ตฌํํด์ ์ทจ์ํ ์์ฒญ์ ์ ํํ ์ ์๋ ์ปค์คํ ํํฐ๋ฅผ ๋ง๋ค ์๋ ์์ต๋๋ค.
public void onStop() {
mRequestQueue.cancelAll (
new RequestFilter() {
...
}
);
}
์๋ฅผ ๋ค๋ฉด ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์ด๋ฃจ์ด์ง๋ POST ์์ฒญ์ ๊ทธ๋๋ก ๋๊ณ , ์ธ๋ค์์์ฒญ์ ์ทจ์ํ๋ ๋ฑ์ ๊ท์น์ ๊ตฌํํ ์ ์์ต๋๋ค.
Volley๋ก ์ฑ์ ๋ง๋ค๊ณ , ์๋ ์ฑ์ ํฌํ ํ๋ ๊ฒ์ ์ฝ์ต๋๋ค. Google IO 2013์ฑ์ Volley๋ก ํฌํ ํ๋๋ฐ ๋ฐ์ผ ๋ฐ์ ์ ๊ฑธ๋ ธ์ต๋๋ค.์ค์ค๋ก ๊ฐ๋ฐํ๋ ๊ฒ๋ณด๋ค ๋ ์์ ์ฝ๋๋ก ๋ ๋ง์ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
Volley๋ฅผ ํตํด ๊ตฌ๊ธ์์ ์ฑ์ ๊ฐ๋ฐํ๋ฉด์ ์ด๋ ต๊ฒ ์ป์ ๊ตํ์ ์ด๋์ ์ฝ๊ฒ ์ป์ ์ ์๊ณ , ์ค์ค๋ก ๊ฐ๋ฐํ๋๊ฒ๋ณด๋ค ํจ์ฌ ๋น ๋ฅผ ๊ฒ์ ๋๋ค. Google Plus ํ์ด ๋ค์ํ Network ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค๊ณผ Benchmark๋ฅผ ํ์ ๋ Volley๊ฐ ๋ชจ๋ ๊ฒ์ ๋ค ์ด๊ฒผ๊ณ , ๋งค๋ฒ ๋นจ๋๊ณ , ์ด๋ค ๊ฒฝ์ฐ์๋ 10๋ฐฐ๊น์ง ๋นจ๋์ต๋๋ค. ( It's easier than doing it yourself, and you get the benefit of all of those lessons we've learned the hard way in developing our apps at Google. But it's also faster than doing it in yourself. Google + Team did a bench mark last year, a bunch of networking libraries and Volley won every single one.)
1. ๋ฉ๋ชจ๋ฆฌ ์บ์ฌ์ ๋์คํฌ ์บ์ฌ์ ํฌ๊ธฐ๋? ์บ์ฌ hit์์ ๋์ฝ๋ฉ์ ์ด๋ ์ค๋ ๋์์ ์ผ์ด๋๋๊ฐ?
์บ์ฌ์ ์ฌ์ด์ฆ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ์๊ฐ ์ ์ ์ผ๋ก ์ค์ ํ ์ ์์ต๋๋ค. ๋์คํฌ ์บ์ฌ์ in memory ์บ์ฌ ํฌ๊ธฐ๋ฅผ ๋ฐ๋ก ์ง์ ํ ์ ์์ต๋๋ค.
๋ชจ๋ ๋ธ๋กํน IO๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค๋ ๋์์ ์คํํฉ๋๋ค. ๊ทธ๋ฌ๋ HttpStack์ ๋๋ฌํ๊ธฐ ์ ์ ๋ฉ์ธ Thread์์ ๋ฉ๋ชจ๋ฆฌ ์บ์ฌ๋ฅผ ์ฐ๋ ๊ฒ์ ์ค์ํฉ๋๋ค. BitMap์ ์์ ๋ ๋ฐ๋ก ์ธ์ํด์ ๋ณด์ฌ์ค์ ์๋ค๋ฉด,์ง์ฒด๋ฅผ ํ์ง ์๋ ํธ์ด ๋ ์ข์ ํ๋ฉด์์ง์(you get a little flicker.)์ ๋ณด์ด๊ธฐ ๋๋ฌธ์ ๋๋ค.
๋์คํฌ ์บ์ฌ๋ ์บ์ฌ ์ค๋ ๋์์ ์ฝ์ต๋๋ค. ์บ์ฌ ์ค๋ ๋๋ ์์ฐจ์ฑ์ด ์์ต๋๋ค. ๋ฐ๋ผ์ ์ด๋ ํ๋์ ์บ์ฌ๋ฅผ ์ฝ๊ณ ์์ผ๋ฉด ๋ค๋ฅธ ์บ์ฌ ์ฝ๊ธฐ๋ ๋ฌถ์ผ ์๋ ์์ต๋๋ค. ์ฐ๋ฆฌ๋ Cache worker๋ฅผ ์ชผ๊ฐ๊ฑฐ๋ ๋ค๋ฅธ ๊ณณ์ผ๋ก ๊ทธ ์ญํ ์ ๋๊ธธ์ง(defer the work somewhere else) ๊ณ ๋ฏผ๋ ํ์ต๋๋ค. ๊ทธ๋ฌ๋ ์ด๋ฏธ ์ถฉ๋ถํ ๋นจ๋๊ธฐ ๋๋ฌธ์ ๊ทธ๋ด ํ์๊ฐ ์์์ต๋๋ค.
3. Dynamic Cache๋ Static Cache, Cache์ ์์กด๊ธฐ๊ฐ ๋ฑ ๋ค์ํ ์บ์ฌ ์ฐ๊ฒฐ์ด Volley์์ ์ง์๋๋๋?
Cache TTL์ ๋ํ ์ง๋ฌธ์ผ๋ก ์ดํดํ์ต๋๋ค. Volley์ ๋์คํฌ ์บ์ฌ๋ Http์ Cache shutter๋ฅผ ์กด์คํฉ๋๋ค. ๋ฉ๋ชจ๋ฆฌ ์บ์ฌ์๋ TTL์ด ์์ต๋๋ค. ๊ฒฝํ์ ๋ฉ๋ชจ๋ฆฌ ์บ์ฌ๋ ์ ์ฅ๋ ๊ฐ์ ๋นจ๋ฆฌ ๋ฒ๋ฆฌ์ง๋ง, ์ํ๋ ๋์์ ์ค์ค๋ก ๊ตฌํํ ์๋ ์์ต๋๋ค.
4. Volley์ ๋น์ทํ๊ฒ ํด๊ฒฐํด๋ณด๋ ค๊ณ ํ๋๋ฐ, ์์ device์์ ํฐ ์ด๋ฏธ์ง์ OOM(Out Of Memory) ์์ธ ๋ฐ์์ด ๊ณตํต์ ์ธ ๋ฌธ์ ์๋ค. ๋ค๋ฅธ ์๋ฃจ์ ๊ณผ ๋น๊ตํด์ Volley์์ ์ํฉ์ด ๋ํ๋๋ ๋น๋๊ฐ ์ด๋ค์ง๋ ์ด๋ฐ ๋ฌธ์ ๋ฅผ ๋ค๋ฃจ๋ ํ์ ์๋ ค๋ฌ๋ผ.
์ฐ๋ฆฌ๋ OOM ์๋ฌ๊ณผ ๋ง์ด ์ธ์ ๊ณ , ์ด๋ ค์ด ๋ฌธ์ ์ ๋๋ค. ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋ง๋ค๋ฉด ์ฑ๋ฅ์ ๋น ๋ฅด๊ฒ ํ ์๋ ์์ต๋๋ค.
์ฐ๋ฆฌ๊ฐ ๋๋ฌํ๊ณ , ์ ๋์๋ ํด๊ฒฐ์ฑ ์ ๋ช๊ฐ์ง์ธ๋ฐ, ํ๋๋ CPU ์ฝ์ด์ ์ซ์๋ณด๋ค ๋ ๋ง์ด ๋์์ ๋์ฝ๋ฉ์ ํ์ง ์์์ ์ ๋๋ค. heap pressure๊ฐ ์ฆ๊ฐ์ ์ผ๋ก ์ค์ด๋๋ ๊ธ์ ์ ์ธ ํจ๊ณผ๊ฐ ๋ํ๋ฌ์ต๋๋ค.
๋ ํ๋ ํ๋ ์ผ์, ์บ์ฌ ๋ฉ๋ชจ๋ฆฌ์ฌ์ด์ฆ๋ฅผ ์คํฌ๋ฆฐ์ฌ์ด์ฆ์ ๋ฐ๋ผ์ ์ง์ ํ ๊ฒ์ ๋๋ค. ๋ณดํต์ 3๊ฐ์ ์คํฌ๋ฆฐ๋งํผ์ ๋ฐ์ดํฐ( three screees' worth of data) ๋ฅผ ์บ์ฌํ๊ธฐ๋ฅผ ์ํ๊ธฐ ๋๋ฌธ์ ์ ๋ง์ ๋จ์ด์ง๋๋ค. ๊ธฐ๊ธฐ๋ค์ ๋ณดํต ๊ทธ ๊ธฐ๊ธฐ๊ฐ ๊ฐ์ง ์คํฌ๋ฆฐ์ ์ฑ์ธ๋งํ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ง์ํฉ๋๋ค. ์ด๊ฒ์ Volley์ ๋ํ ๊ฒ๋ง์ด ์๋๊ณ , ์ด๋ป๊ฒ cache size๋ฅผ ์ ํํ ๊ฒ์ธ๊ฐ์ ๋ํ ๋ฌธ์ ์ ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ฐ๋ฆฌ๋ SoftReference๋ WeakRefernce๋ฅผ ์ฌ์ฉํ์ง ์์ต๋๋ค. ๊ทธ ๋ฐฉ๋ฒ์ ์ ๋จนํ์ง ์์์ต๋๋ค. ์ฐ๋ฆฌ๋ Hard Reference๋ฅผ ์ฌ์ฉํ๊ณ , ๊ณผ๊ฐํ๊ฒ ์์ ํ ๋น์ ํ์ต๋๋ค. ์ฐ๋ฆฌ๋ ์์๋์ ์ฐ์ ํ๋๋ฐ ๋ณด์์ ์ธ ๊ธฐ์ค์ ์ ์ฉํ๊ณ , ์คํฌ๋ฆฐ์ฌ์ด์ฆ์ ์ค์ ํฝ์ ์ ์๋ฅผ ๊ธฐ์ค์ผ๋ก ์ถ์ํด์ ์ก์์ต๋๋ค. ( And so we don't use soft references or weak references. They don't work well. We use hard references and set a strong budget. We are conservative in setting that budget by scaling down with the screen and really the number of pixels. )
SDK manager์ ์ธ์ ๋ค์ด๊ฐ์ง๋ ๋ชจ๋ฆ ๋๋ค. clone ํด์ ์ฐ๊ธฐ์ ์ถฉ๋ถํ ์ฝ์ต๋๋ค.
SPDY์ ๊ด์ฌ์ด ์๊ณ , ๊ทธ ์ง์์ ์ผ๋์ ๋๊ณ ์ค๊ณ๋์์ต๋๋ค. SPDY๋ OkHttp๋ฅผ ํตํด์ ์ฌ์ฉํ ์ ์์ต๋๋ค. Volley์ tranport stack์ผ๋ก OkHttp๋ฅผ ๋ฃ๋ ์์ ์ ๋๊ตฐ๊ฐ๊ฐ ์งํํ๊ณ ์์ต๋๋ค.
6. ๋ค์ Activity๋ก Transition ํ๊ธฐ ์ ์ API๋ฅผ ํธ์ถํ๊ณ ์ถ๋ค. Activity๋ก Boundary๋ฅผ ๋์ด์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ ์ ์๋๊ฐ?
์ข์ ๋๋ต์ ์๋๊ฒ ๊ฐ์ง๋ง static์ ์ ์ฅํ๋ ๊ฐ ํ์ธ์.
7. ์์ ๊ฐ json request์ response๋ฅผ ์ฌ์ฉํ๋ค. XML๊ฐ์ ๋ค๋ฅธ ํ๋กํ ์ฝ๋ ์ฌ์ฉ๊ฐ๋ฅํ๊ฐ? ์์ฒญ์ด ๋งํ ๊ฒฝ์ฐ 3๋ฒ ์ฌ์๋ ๊ฐ์ ๋์์ ํ๋๊ฐ?
playstore์์๋ protobuff๋ฅผ ์ฃผ๋ก ์ฌ์ฉํฉ๋๋ค. XML ๋ ์ฌ์ฉํ ์ ์๊ณ , pluginํ๊ธฐ๋ ์ฝ์ต๋๋ค. ์ฌ์๋ ์ฒ๋ฆฌ๊ฐ ๋ค์ด๊ฐ์๊ณ , custom retry policy, backoff alogorithm ์ ์ ๋ฑ ๋ชจ๋ ๊ฒ์ ํ ์ ์์ต๋๋ค.

