LRUCacheã§ã¡ã¢ãªã管çãã
ã¢ããªã±ãŒã·ã§ã³ã§ã¯æ§ã
ãªããŒã¿ãæ±ãã
æè¿ã®äžè¬çãªã¢ãã€ã«ã¢ããªã¯ãããã¯ãŒã¯ãä»ããŠããŒã¿ããããšãããå Žåãå€ãããå
šãŠã®ããŒã¿ãé次çã«åãã«ããä»çµã¿ã ãšãããŒã¿ååŸã®éãŠãŒã¶ã«åŸ
ã¡ç¶æ
ãçºçããŠããŸãã
äžåã®ãããšãã§ååŸããããŒã¿éãå°ãªãå Žåã¯ãå€ãã®å Žåããã§åé¡ãçºçããããšã¯å°ãªãããã¢ããªå
ã§å€§éã®ããŒã¿ã䜿çšãããããµã€ãºã®å€§ããããŒã¿ãæ±ãå Žåã«ã¯æ³šæãå¿
èŠã§ããã
ãã®åé¡ã解決ããæ¹æ³ã®äžã€ãšããŠãããŒã¿ãã¡ã¢ãªå
ã«ä¿æãããããã¯ãŒã¯ãä»ããã«ããŒã¿ã衚瀺ããæ¹æ³ã§ããã
ãã®ããšèªäœããã£ãã·ã¥ãããšèšã£ãããã¡ã¢ãªã«ä¿æããããŒã¿ããã£ãã·ã¥ãšæãããšãããã
ãã®ãã£ãã·ã¥ãã©ã®ããã«ç®¡çããããšããè°è«ã¯é¥ãæãããªãããŠãããè²ã
ãªã¢ã«ãŽãªãºã ãååšããã
Androidã§ã¯ããã®åé¡ã«å¯Ÿããäžã€ã®è§£æ±ºçãšããŠLRUCacheãšãããã®ãæ¢ã«æäŸããŠããã
ä»åã¯æ§ã
ãããã£ãã·ã¥æ¹æ³ã®äžã§ããã®LRUCacheã«ã€ããŠæžããã
LRUCacheã«ã€ããŠ
LRUCacheã¯ãLeast Recently Usedã®ç¥ã
ã©ããã£ãä»çµã¿ããç°¡åã«èª¬æãããšãæè¿ã¢ã¯ã»ã¹ãããã®ã»ã©åªå
床ãé«ãä¿æããã¢ã«ãŽãªãºã ã§ããã
ãã®ãããªç»åããŒã¿ãã¡ã¢ãªäžã«ããå ŽåãLRUCacheã®ã¢ã«ãŽãªãºã ãé©çšãããšãå³ã«ãããã®ã»ã©æè¿äœ¿çšããç»åããŒã¿ã§ããããšãåããã
ãã®æãå³ãã3çªç®ã®ç»åã«ã¢ã¯ã»ã¹ãããšã©ããªããã
ããã3çªç®ã®ç»åãä»åºŠã¯1çªå³ã«ãããšããèš³ã§ããã
LRUCacheã¯åãã«æ倧ä¿æãµã€ãºã決ããã®ã§ã端æ«å
šäœã®ã¡ã¢ãªãå§è¿«ããããšããªãã
æ倧ä¿æãµã€ãºã決ãŸã£ãŠãããšããããšã¯ãæ°ããããŒã¿ãã¡ã¢ãªã«è¿œå ãããæãæ¢ã«ã¡ã¢ãªãäžæ¯ã§ããã°ããã§ã«ä¿æãããŠããããŒã¿ã®ã©ãããåé€ããªããã°ãããªãã
ã§ã¯ãã©ã®ããŒã¿ãåé€ããããšãããšãåçŽæå¿«ã§ãLRUCacheã§ä¿æãããŠããããŒã¿ã®äžã§ãå€ãããŒã¿ã»ã©åå©çšãããå¯èœæ§ãäœããããããã®ããã€ããåé€ãããèš³ã§ããã
ããã§æ³šæããŠããããã®ã¯ãåé€ãããããŒã¿ã¯å¿
ãããäžã€ã§ã¯ãªããšããããšã§ããã
LRUCacheã«ã€ããŠç°¡åã«ç解ã§ããã®ã§ãAndroidã§ã¯ã©ã®ããã«ããŠäœ¿çšãããèŠãŠããã
Androidã§ã®LRUCacheã®å®è£
Androidã§ã¯ã android.util.LruCache
ã androidx.collection.LruCache
ãçšæãããŠããã
ããããã®ããã¥ã¡ã³ããèªããšã androidx.collection.LruCache
ã¯API level 12æªæºåãã®ããã§ããã
ä»å㯠android.util.LruCache
ãå®éã«äœ¿ã£ãŠã¿ãããšæãã
ããŒã«ã«ã«ç»åã®URLãæããããã®URLã«ã¢ã¯ã»ã¹ããŠç»åãååŸãããã®ç»åã RecyclerView
ã«è¡šç€ºãããšããã衚瀺ããç°¡åãªã¢ããªãäœã£ãŠã¿ãã
äœæãã RecyclerView
ã® Adapter
ã¯æ¬¡ã®éãã
class LruCacheRecyclerAdapter(maxCacheSize: Int) : RecyclerView.Adapter<LruCacheRecyclerAdapter.ViewHolder>() { private val shuffledImageUrlList: MutableList<String> = mutableListOf() // ç»åURLãkeyãšãããBitmapã®LruCache private val cache: LruCache<String, Bitmap> = lruCache(maxCacheSize / 8, { _, value -> value.byteCount }) init { val imageUrlList: List<String> = listOf( // ç»åURL ) for (index in 0 until imageUrlList.size * 100) { if (index % imageUrlList.size == 0) { // imageUrlListã®äžèº«ãã·ã£ããã«ããŠãshuffledImageUrlListã«çªã£èŸŒã shuffledImageUrlList.addAll(imageUrlList.shuffled()) } } } override fun getItemCount(): Int = shuffledImageUrlList.size override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val binding = DataBindingUtil.inflate<ItemMainRecyclerBinding>( LayoutInflater.from(parent.context), R.layout.item_main_recycler, parent, false ) return ViewHolder(binding) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.onBind(shuffledImageUrlList[position]) } inner class ViewHolder(private val binding: ItemMainRecyclerBinding) : RecyclerView.ViewHolder(binding.root) { fun onBind(imageUrl: String) { val bitmap = cache.get(imageUrl) if (bitmap != null) { // ãã£ãã·ã¥ã«ç»åããŒã¿ãããã°ããããåã£ãŠããŠè¡šç€ºãã binding.artworkImageView.setImageBitmap(bitmap) } else { Glide.with(binding.root.context) .asBitmap() .load(imageUrl) .skipMemoryCache(true) // Glideã«ãã£ãŠã¡ã¢ãªãã£ãã·ã¥ãããªãããã«ãã .diskCacheStrategy(DiskCacheStrategy.NONE) // Glideã¯ããã©ã«ãã§DiskCacheããã®ã§ãããªãããã«ãã .listener(object : RequestListener<Bitmap> { override fun onLoadFailed( e: GlideException?, model: Any?, target: Target<Bitmap>?, isFirstResource: Boolean ): Boolean { return false } override fun onResourceReady( resource: Bitmap?, model: Any?, target: Target<Bitmap>?, dataSource: DataSource?, isFirstResource: Boolean ): Boolean { resource ?: return false // ç»åãããŠã³ããŒããããããã£ãã·ã¥ã«è¿œå ãã cache.put(imageUrl, resource) return false } }) .into(binding.artworkImageView) } } } }
ãã€ã³ã1: LruCacheã®ãµã€ãºã決ãã
LruCacheã¯ãåãã«ä¿æãããµã€ãºã決ãããšå
ã§èª¬æãããããã®åºæºãšãªãã®ãã LruCacheRecyclerAdapter
ã®constractorã«æž¡ããŠãã maxCacheSize
ã§ããã
ãã㯠LruCacheRecyclerAdapter
ãã€ã³ã¹ã¿ã³ã¹åããŠãã Activity
ã§æ¬¡ã®ããã«ååŸããŠããã
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager val maxCacheSize = activityManager.memoryClass * 1024 * 1024
ActivityManager#getMemoryClass
ã¯ãããã€ã¹ããã®ã¢ããªã«å¯ŸããŠäœ¿çšã§ããã¡ã¢ãªãµã€ãºéãè¿ããŠããããè¿ã£ãŠããå€ã®åäœã¯ã¡ã¬ãã€ãã§ããã
developer.android.com
ãã®å€ã8ã§å²ã£ãå€ãä»åã¯LruCacheã®ã¡ã¢ãªãµã€ãºã«æå®ããŠããã
ãã€ã³ã2: LruCacheãã€ã³ã¹ã¿ã³ã¹åãã
LruCacheã¯Mapã®ããã«ãkeyã§valueã管çããŠããã
ä»åã¯keyãç»åã®URLãvalueãBitmapãšããŠLruCacheãäœæããã
private val cache: LruCache<String, Bitmap> = lruCache(maxCacheSize / 8, { _, value -> value.byteCount })
ktxã« lruCache
ãšããæ¡åŒµé¢æ°ãçšæãããŠãããèªå㧠LruCache
ãç¶æ¿ããã¯ã©ã¹ãäœæããªããŠããã®ã§äŸ¿å©ã§ããã
android.github.io
第äžåŒæ°ã«ã¯ãå
ã§èª¬æãããã£ãã·ã¥ã®ä¿æãµã€ãºãæå®ããã
第äºåŒæ°ã§ã¯ãäžã€ã®Bitmapã®ããŒã¿ã®ãµã€ãºãè¿ãé¢æ°ãæå®ããŠããã
ãœãŒã¹ã³ãŒããèªãã°ããããããã㯠LruCache#sizeOf
ãoverrideããŠããã
ãã LruCache
ãç¶æ¿ããã¯ã©ã¹ãèªäœããå Žåã«ã¯ããã® LruCache#sizeOf
ãoverrideããããšãå¿ããªãããã«ãããã
ããã©ã«ãã§ã¯1ãè¿ãããã«ãªã£ãŠããããã ã
ãã€ã³ã3: LruCacheãžã®ããŒã¿ã®ä¿åãšåãåºã
LruCacheã«ããŒã¿ãä¿åããŠããã®ãããããåãåºãã®ãéåžžã«ç°¡åã§ããã
ããŒã¿ãä¿åãããå Žåã«ã¯ LruCache#put
ã§keyãšvalueãæž¡ãã ãã
ããŒã¿ãåãåºãå Žåã«ã¯ã LruCache#get
ã«keyãæž¡ããŠãkeyã«å¯Ÿå¿ããããŒã¿ãè¿ã£ãŠããã
ããkeyã«å¯Ÿå¿ããããŒã¿ããªãå Žåã«ã¯nullãè¿ã£ãŠããã
ãã£ãããã ãã§ãç°¡åã«ã¡ã¢ãªãã£ãã·ã¥ã«å¯Ÿå¿ããå®è£
ãã§ããŠããŸãã
ãã£ãããªã®ã§ãLruCacheã䜿çšããã¢ããªãšäœ¿çšããŠããªãã¢ããªã®åäœãæ¯ã¹ãŠã¿ãã
LruCacheäœ¿çš | LruCacheæªäœ¿çš |
---|---|
èŠæ¯ã¹ããšéããäžç®çç¶ã ãšæãããLruCacheã䜿çšããæ¹ã¯ã¹ã ãŒãºã«ç»åã衚瀺ã§ããŠãããã䜿çšããŠããªãæ¹ã¯ãç»åãå
šç¶è¡šç€ºããããã¹ã¯ããŒã«ãéãã
LruCacheã䜿çšããŠããæ¹ã¯ããã£ãã·ã¥ã«ç»åããªãå Žåã®ã¿ããŒã¿ãããŠã³ããŒãããŠããã®ã«å¯Ÿãã䜿çšããŠããªãæ¹ã¯ã RecyclerView#Adapter#onBind
ãåŒã°ãããã³ã«ç»åãããŠã³ããŒãããŠããŠãããããåœç¶ã®çµæã§ããã
ã¢ããªãå¿«é©ã«åäœãããã«ã¯ããã£ãã·ã¥ãããŸã掻çšããããŒã¿ãçŽ æ©ã衚瀺ããããšã倧åã ãªããšæã£ãã
ããŸã
LruCacheã® LruCache#put
ãš LruCache#get
ã®åŠçã¯å
éšã§ synchronized
ãçšããŠåŠçãè¡ãããŠãããããã¹ã¬ããã»ãŒãã§ããã
LruCache#get
ããŠããäœãåŠçãã㊠LruCache#put
ãããæã«ã LruCache
ã®ã¢ãããã¯æ§ãä¿æããŠããããå Žåã«ã¯ããã®åŠçå
šäœã synchronized
ã§åŠçããæ¹ããããããããªãã
åè
Daggerããã£ãŠãããããš (AAC ViewModelç·š)
ååãDaggerããã£ãŠãããããš (Android Supportç·š)ãæžããã
ä»åã¯ãããã«Android Architecture Componentã®ViewModelãé©çšããéã«ãViewModelã«å¯ŸããŠã©ã®ããã«diãå®çŸãããã®ããèŠãŠããã
TL;DR
- Daggerã®MultiBindingsæ©èœãçšããããšã§ãViewModelã¯ã©ã¹ãkeyãšããViewModelãã¡ã¯ããªã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ã®Mapãçšæããã
ViewModelProvider#Factory
ã®ãµãã¯ã©ã¹ã«ãã®Mapãæ³šå ¥ããããšã§ãViewModelProvider#Factory#create
å ã§ViewModelã®ã€ã³ã¹ã¿ã³ã¹åãšãäŸåã®å 足ãè¡ã
Daggerããã£ãŠãããããš (Android Supportç·š)
ååãDaggerããã£ãŠãããããš (SubComponentç·š)ãæžããã
ä»åã¯ååã®ã³ãŒãã«ãDagger Androidãé©çšãããå Žåã«ã©ã®ãããªã³ãŒããçæããããèŠãŠããã
Dagger Androidã®é©çšæ¹æ³ãªã©ã¯èª¬æããªãã
TL;DR
@ContributesAndroidInjector
ã䜿çšããããšã§ãSubComponent
ãèªåçæããã@ContributesAndroidInjector
ãæå®ããã¡ãœããã®è¿ãå€ã®åã®ã¯ã©ã¹åãšãã®SubComponentBuilder
ã®Provider
ã®Mapãäœããã- Activityãªã©ã®äžã§
AndroidInjection#inject
ãåŒã¶ãšãåŒã³å ã®ã¯ã©ã¹åã«å¯Ÿå¿ããSubComponentBuilder
ãä»ããŠãåŒã³å ã®ã¡ã³ããŒã«injectããã
Daggerããã£ãŠãããããš (SubComponentç·š)
åå Daggerããã£ãŠãããããš ãšããèšäºãæžããã
ä»åã¯ãã®ç¶ãã§ãSubComponentãå©çšããæã«Daggerãã©ã®ãããªã³ãŒããçæãããèŠãŠããã
TL;DR
- SubComponentåã«ãã£ãŠãMembersInjectorã¯çæãããªããªã
- SubComponentã¯èŠªComponentå ã«å®è£ ã¯ã©ã¹ãçæããã
- injectãŸã§ã®æµãã¯ãSubComponentã䜿ããªãå Žåãšãããªã«å€ãããªã
Daggerããã£ãŠãããããš
Javaã¢ããªã±ãŒã·ã§ã³ã§DI(Dependency Injection)ãããéã«ããã䜿çšãããã®ãDaggerã
äœãšãªãDaggerã䜿ã£ãŠããããã©ã®ããã«ããŠDIãå®çŸããŠãããç解ã§ããŠããªãã£ãã®ã§ã¡ã¢ã
TL;DR
- çæãããã¯ã©ã¹
- Componentã®å®è£ ã¯ã©ã¹
- Moduleã§
@Provides
ãæå®ããåã®Factoryã¯ã©ã¹ - ã€ã³ãžã§ã¯ããããã¯ã©ã¹ã®MembersInjector
- Componentã®ã€ã³ã¹ã¿ã³ã¹åæã«é¢é£ããModuleãã€ã³ã¹ã¿ã³ã¹åããã
- ã¹ã³ãŒãæå®ããModuleãããå Žåã¯ãFactoryã¯ã©ã¹ãã€ã³ã¹ã¿ã³ã¹åããã
- ã€ã³ãžã§ã¯ããããåŽã§
inject
ãåŒã¶ããšã§ãComponentã®å®è£ ã¯ã©ã¹
-> (Moduleã§
@Providesãæå®ããåã®Factoryã¯ã©ã¹
) ->ã€ã³ãžã§ã¯ããããã¯ã©ã¹ã®MembersInjector
ãšããã«ãŒãã§ã¡ã³ããŒãåæåãã