èè ã«ãããšããã®èšäºã¯ããã®ãããªãšããµã€ãã£ã³ã°ãªåéã§æåã®äžæ©ãèžã¿åºããŠããAndroidéçºè ãå§ããã°ããã®äººã«åœ¹ç«ã€ãããããŸããã ãã®èšäºã®äž»é¡ã®æŽå²ã¯ããã¬ãŒãã³ã°ãããžã§ã¯ãã«ããããããããå¹æããäžãããšããã¢ã€ãã¢ããå§ãŸããŸããã ãããã©ãã»ã©æåããããå€æã§ããŸãã ç§ã¯ç«ã®äžã§ãã¹ãŠã®å¥œå¥å¿ãå°ããŸãã
ãã®ãã¹ãŠã®äžåèªã䌎ããã¢ãããžã§ã¯ãã¯ãGitHubã®ãªã³ã¯ã«ãããŸãã
ç§ãã¡ãèå³ãæã£ãŠããç»é¢ã¯ãææã®RecyclerViewã«åºã¥ããŠããŸãã ãããããã€ã©ã€ãã¯ããªã¹ããã¹ã¯ããŒã«ãããšã1ã€ã®å®å šã«è¡šç€ºãããäžéšèŠçŽ ãç¹å¥ãªæ¹æ³ã§æ¡å€§çž®å°ãããããšã§ãã ãã®æ©èœã®ç¹åŸŽã¯ããªã¹ãã¢ã€ãã ãæ§æããã³ã³ããŒãã³ãã®ã¹ã±ãŒãªã³ã°ãç°ãªãããšã§ãã
ãã ããäžåºŠèŠãã»ããããã§ãã
å³ 1.äžè¬çãªãã¥ãŒ
ãªã¹ãé ç®ã詳现ã«æ€èšããŠãã ããã ãããžã§ã¯ãã§ã¯ãCardViewããç¶æ¿ãããã¯ã©ã¹LaunchItemViewãšããŠå®è£ ãããŸãã ãã®ããŒã¯ã¢ããã«ã¯ã次ã®ã³ã³ããŒãã³ããå«ãŸããŠããŸãã
- ç»å-æå®ãããé«ãïŒã¹ã±ãŒãªã³ã°ïŒã§ç»åãã¬ã³ããªã³ã°ããããã«èšèšãããScaledImageViewã¯ã©ã¹ã
- èŠåºãã
- 説ææã
å³ 2.ãªã¹ãé ç®ã®æ§é ïŒLaunchItemViewïŒã
ãªã¹ããã¹ã¯ããŒã«ããéçšã§ã次ã®ããšãçºçããŸãã
- èŠçŽ ã®é«ãã¯ãæå°å€ïŒè£ 食ä»ãã®ã¿ã€ãã«ã®é«ãã«çããïŒããæ倧å€ïŒè£ 食ä»ãã®ã¿ã€ãã«ãšèª¬æããã¹ãã衚瀺ã§ããé«ãã«çããïŒã«å€åããŸãã
- ç»åã®é«ãã¯èŠçŽ ã®é«ãããè£ é£ŸãåŒãããã®ã«çãããå¹ ã¯ããã«æ¯äŸããŠå€åããŸãã
- èŠçŽ å ã®çžå¯Ÿäœçœ®ãšèª¬æããã¹ãã®ãµã€ãºã¯å€æŽãããŸããã
- ã¹ã±ãŒãªã³ã°å€ã¯ãè£ é£Ÿã®å¯Ÿè±¡ãšãªããã¹ãŠã®ã³ã³ãã³ãã衚瀺ããã®ã«ååãªæå°ãµã€ãºã«ãã£ãŠäžããå¶éãããè£ é£Ÿã®å¯Ÿè±¡ãšãªãã¿ã€ãã«ã衚瀺ããã®ã«ååãªæå°ãµã€ãºã«ãã£ãŠäžããå¶éãããŸãã
- å¢çå€ä»¥å€ã®ã¹ã±ãŒãªã³ã°ã¯ãäžéšã®å®å šã«è¡šç€ºããããªã¹ãã¢ã€ãã ã«é©çšãããŸãã ãã®äžã«ããèŠçŽ ã«ã¯æ倧ã¹ã±ãŒã«ãäžã«ããèŠçŽ -æå°èŠçŽ ããããŸãã
ãããã£ãŠãäžæ¹åã«ã¹ã¯ããŒã«ãããšãèŠçŽ ã®ã³ã³ãã³ããåŸã ã«æ¡å€§ãããã€ã¡ãŒãžãæ¯äŸçã«æ¡å€§ãããŸãã äžã«ã¹ã¯ããŒã«ãããšãéã®å¹æãèŠãããŸãã
RecyclerViewã®LayoutManagerãš2ã€ã®è¿œå ã³ã³ããŒãã³ããäœæããŠããã®ããã«ã¿ã¹ã¯ãèšå®ããŸãã ãããããŸãæåã«ã
LaunchLayoutManager
ç§ã®ãã¬ãŒãã³ã°ãããžã§ã¯ãã¯ã¹ããŒã¹ã®åé¡ã«å°å¿µããŠãããããã³ã³ããŒãã³ãã«ã¯å¯Ÿå¿ããååãä»ããããŠããŸãã
ä»»æã®LayoutManagerãäœæãããããã¯ãç 究ããŠããã®ãããã¯ã«é¢ãã2ã€ã®è¯ãèšäºãèŠã€ããŸãã[1ã2]ã å 容ãç¹°ãè¿ããŸããã 代ããã«ã決å®ã®æãèå³æ·±ãç¹ã«ã€ããŠèª¬æããŸãã
åé¡ã®å解ãå®è¡ããŠã2ã€ã®äž»èŠãªæ®µéãç¹å®ããŸããã
- ç»é¢äžã«å®å šãŸãã¯éšåçã«è¡šç€ºãããæåãšæåŸã®èŠçŽ ã®ã€ã³ããã¯ã¹ã決å®ããŸãã
- å¿ èŠãªã¹ã±ãŒãªã³ã°ã§å¯èŠèŠçŽ ãã¬ã³ããªã³ã°ããŸãã
äžè¬ã«ããªã¹ãã¢ã€ãã ã®å Žæãšãµã€ãºã¯æ¬¡ã®ãšããã§ãã
å³3. RecyclerViewãšãã®èŠçŽ ã
å¯èŠèŠçŽ ã®ã€ã³ããã¯ã¹ã®éããééã®å®çŸ©
å³ 3ããvisibleã¯ã3ãã11ãŸã§ã®ã€ã³ããã¯ã¹ãæã€èŠçŽ ã§ãã ããã«ããã®ã¢ã«ãŽãªãºã ã«ããã°ãã€ã³ããã¯ã¹0ã3ã®èŠçŽ ã¯æ倧ãµã€ãºãèŠçŽ 5ã12ã¯æå°ãµã€ãºãã€ã³ããã¯ã¹4ã®èŠçŽ ã¯æå°ãšæ倧ã®äžéã§ãã
ãæ³åã®ãšãããå¯èŠèŠçŽ ã®æå°ããã³æ倧ã€ã³ããã¯ã¹ã決å®ããéã®éèŠãªãã€ã³ãã®1ã€ã¯ãå¯èŠé åã®äžéšå¢çã«å¯ŸããŠãªã¹ããã¹ã¯ããŒã«ããããªãã»ããã§ãã
ãããã®å€ã決å®ããããã«èšèšãããcalculateVisiblePositionsã¡ãœãããæ€èšããŠãã ããã
1 private void calculateVisiblePositions() { 2 if (mBigViewHeight != 0) { 3 mMaximumOffset = (getItemCount() - 1) * mBigViewHeight; 4 mFirstVisibleViewPosition = mOffset / mBigViewHeight; 5 if (mFirstVisibleViewPosition > getItemCount() - 1) { 6 mFirstVisibleViewPosition = 0; 7 mOffset = 0; 8 } 9 10 mLastVisibleViewPosition = mFirstVisibleViewPosition; 11 int emptyHeight = getHeight(); 12 mFirstVisibleViewTopValue = mBigViewHeight * mFirstVisibleViewPosition - mOffset; 13 int firstVisibleViewBottomValue = mFirstVisibleViewTopValue + mBigViewHeight; 14 emptyHeight -= firstVisibleViewBottomValue; 15 int secondVisibleViewHeight = getViewHeightByTopValue(firstVisibleViewBottomValue); 16 if (emptyHeight - secondVisibleViewHeight >= 0) { 17 emptyHeight -= secondVisibleViewHeight; 18 mLastVisibleViewPosition++; 19 int smallViewPosCount = emptyHeight / mSmallViewHeight; 20 mLastVisibleViewPosition += smallViewPosCount; 21 emptyHeight -= smallViewPosCount * mSmallViewHeight; 22 if (emptyHeight > 0) { 23 mLastVisibleViewPosition++; 24 } 25 } 26 if (mLastVisibleViewPosition > getItemCount() - 1) { 27 mLastVisibleViewPosition = getItemCount() - 1; 28 } 29 Timber.d("calculateVisiblePositions mFirstVisibleViewPosition:%d, mLastVisibleViewPosition:%d", mFirstVisibleViewPosition, mLastVisibleViewPosition); 30 } 31 }
2è¡ç®-ãã¹ãŠã®ã³ã³ãã³ãïŒèŠåºããããã¹ããšç»åã®èª¬æïŒã衚瀺ããæ倧ãµã€ãºã®èŠçŽ ã®é«ãã決å®ãããŠãããã©ããã確èªããŸãã ããã§ãªãå Žåã¯ãç¶è¡ããŠãæå³ããããŸããã
è¡3-ãªã¹ãã®ãã¹ãŠã®èŠçŽ ãã¹ã¯ããŒã«ã¢ããããã¹ããŒã¹ã®éãèšç®ããŸãããã ãã1ã€ãé€ããæ倧蚱容ãªãã»ããã§ãã ãã®å€ã¯ãscrollVerticallyByã¡ãœããã®ãªãã»ããå€ãå¶éããŸãã
è¡4-æåã®å¯èŠèŠçŽ ã®ã€ã³ããã¯ã¹ãèšç®ããŸãã å€æ°mFirstVisibleViewPositionã¯æŽæ°åã«å±ãããããå°æ°éšåãç Žæ£ããããšã«ãããéšåçã«è¡šç€ºãããæåã®èŠçŽ ã®ã±ãŒã¹ãèªåçã«èæ ®ããŸãã
5ã8è¡ç®-æåã«è¡šç€ºãããŠããèŠçŽ ã®ã€ã³ããã¯ã¹ãããªã¹ãå ã§æåŸã«äœ¿çšå¯èœãªèŠçŽ ã®ã€ã³ããã¯ã¹ãè¶ ããŠãããã©ããããã§ãã¯ãããŸãã ããã¯ãããšãã°ããªã¹ããæåã«ã¹ã¯ããŒã«ã¢ããããã次ã«ãã£ã«ã¿ãŒãé©çšãããªã©ããŠèŠçŽ ã®æ°ãæžå°ããå Žåã«çºçããå¯èœæ§ããããŸãã ãã®å Žåããªã¹ããæåã«ãå·»ãæ»ããã ãã§ãã
10è¡ç®-æåã®è¡šç€ºèŠçŽ ã®ã€ã³ããã¯ã¹ããæåŸã®ã€ã³ããã¯ã¹ãèŠã€ããããã®éå§ç¹ãšããŠäœ¿çšããŸãã
è¡11-衚瀺é åã®é«ããèšå®ããŸãã ãã®å€ã¯ãå¯èŠèŠçŽ ã®æ倧ã€ã³ããã¯ã¹ã®æ€çŽ¢äžã«æžå°ããŸãã
è¡12ã13-æåã®èŠçŽ ã®æç»é·æ¹åœ¢ã®äžäžã®åº§æšã決å®ããŸãã
14è¡ç®-æåã®èŠçŽ ã®å¯èŠéšåã®ãµã€ãºã ãã空ãå¯èŠé åã®éãæžãããŸãã ã€ãŸã ä»®æ³çã«æåã®èŠçŽ ãç»é¢ã«é 眮ãããã®ããã«ã
è¡15-2çªç®ã®è¡šç€ºèŠçŽ ã®é«ããèšç®ããŸãã ãã®èŠçŽ ã¯ãã¹ã±ãŒãªã³ã°ã®å¯Ÿè±¡ãšãªãå¯èœæ§ããããŸãïŒã¢ã«ãŽãªãºã ã®æ¡é 5ãåç §ïŒã getViewHeightByTopValueã¡ãœããã®è©³çŽ°ã以äžã«èª¬æããŸãã
16è¡ç®-ç»é¢äžã®2çªç®ã®èŠçŽ ã®ãä»®æ³é 眮ãã®åŸã«ãŸã 空ãã¹ããŒã¹ããããã©ããã確èªããŸãã
17è¡ç®-æ®ãã®ç©ºã容éãä¿®æ£ããŸãã
18è¡ç®-æåŸã«è¡šç€ºãããŠããèŠçŽ ã®ã€ã³ããã¯ã¹ãã€ã³ã¯ãªã¡ã³ãããŸãã
19è¡ç®-æ®ãã®ç©ºãé åã«åãŸããåæã«å®å šã«èŠããæå°ãµã€ãºã®èŠçŽ ã®æ倧æ°ãèšç®ããŸãã
20è¡ç®-æåŸã«è¡šç€ºãããèŠçŽ ã®ã€ã³ããã¯ã¹ãèšç®å€ã§å¢ãããŸãã
21ã24è¡ç®-å¥ã®èŠçŽ ãéšåçã«é 眮ããå Žæããããã©ããã確èªããŸãã ãã®å Žåãã€ã³ããã¯ã¹ããã1ã€å¢ãããŸãã
次ã«ãç»é¢äžã®äœçœ®ã«å¿ããŠ2çªç®ã®è¡šç€ºèŠçŽ ã®é«ããèšç®ããæ¹æ³ã«ã€ããŠèª¬æããŸãããã®èŠçŽ ã®è¡šç€ºé·æ¹åœ¢ã®äžéšåº§æšã§ãã
1 private int getViewHeightByTopValue(int topValue) { 2 topValue -= mTopAndBottomMargins; 3 if (topValue > mBigViewHeight) { 4 topValue = mBigViewHeight; 5 } else if (topValue < 0) { 6 topValue = 0; 7 } 8 float scale = 1 - (float) topValue / mBigViewHeight; 9 int height = (int) (mSmallViewHeight + scale * (mBigViewHeight - mSmallViewHeight)); 10 Timber.d("getViewHeightByTopValue topValue:%d, scale:%f, height:%d", topValue, scale, height); 11 return height; 12 }
2è¡ç®-äžããŒãžã³ãšäžããŒãžã³ãããããããŸãã
è¡3ã7-ã¹ã±ãŒã«ãæ£ããèšç®ããããã«ãtopã®å€ã®äžããèŠçŽ ã®æ倧ã®é«ããŸã§ãããã³äžãããŒããŸã§ãå¶éããŸãã
8è¡ç®-ã¹ã±ãŒãªã³ã°ä¿æ°ãèšç®ããŸããããã¯ãæ倧ã«å±éãããèŠçŽ ã«å¯ŸããŠ1ã®å€ããšããæå°å€ã«å¯ŸããŠ0ãåããŸãã ãã®ç¹å®ã®çµæãæ£ç¢ºã«ããã«ã¯ã3ã7è¡ç®ã®å¶éãå¿ èŠã§ãã
9è¡ç®-ã¹ã±ãŒãªã³ã°ä¿æ°ãèæ ®ããŠãæå°é«ãã®è¿œå ãšããŠèŠçŽ ã®é«ããèšç®ããæ倧é«ããšæå°é«ãã®å·®ãèšç®ããŸãã ã€ãŸã ä¿æ°0-æå°é«ããããã³1-æå°+ïŒæ倧-æå°ïŒ=æ倧ã
ããã§ãæç»ããèŠçŽ ã®æåãšæåŸã®ã€ã³ããã¯ã¹ãããããŸããã ãããããæéã§ãïŒ
å¿ èŠãªã¹ã±ãŒãªã³ã°ã§èŠçŽ ãæç»ãã
ã¬ã³ããªã³ã°ããã»ã¹ã¯æ¬è³ªçã«åšæçã§ãããããã¬ã³ããªã³ã°ã®çŽåã«ãæ¢åã®RecyclerViewèŠçŽ ã§ãã£ãã·ã¥ããŠã©ãŒã ã¢ããããŸãïŒããããã°ïŒã ãã®ãããªææ³ã¯[1ã2]ã§èª¬æãããŠãããããã§ã¯è©³ãã説æããŸããã
fillDownã¡ãœãããæ€èšããŸãããã®ã¡ãœããã¯ã䜿çšå¯èœãªå¯èŠé åã«æ²¿ã£ãŠäžããäžã«ç§»åããèŠçŽ ãæç»ããããã«èšèšãããŠããŸãã
1 private void fillDown(RecyclerView.Recycler recycler) { 2 boolean isViewFromCache; 3 int topValue = mFirstVisibleViewTopValue; 4 int bottomValue; 5 int viewHeight; 6 try { 7 for (int curPos = mFirstVisibleViewPosition; curPos <= mLastVisibleViewPosition; curPos++) { 8 isViewFromCache = true; 9 View view = mViewCache.get(curPos); 10 if (view == null) { 11 isViewFromCache = false; 12 view = recycler.getViewForPosition(curPos); 13 } else { 14 mViewCache.remove(curPos); 15 } 16 viewHeight = getViewHeightByTopValue(topValue); 17 bottomValue = topValue + viewHeight; 18 if (view instanceof LaunchItemView) { 19 ((LaunchItemView) view).updateContentSize(viewHeight); 20 } 21 if (isViewFromCache) { 22 if (view.getTop() != topValue) { 23 view.setTop(topValue); 24 } 25 if (view.getBottom() != bottomValue - mTopAndBottomMargins) { 26 view.setBottom(bottomValue - mTopAndBottomMargins); 27 } 28 attachView(view); 29 } else { 30 layoutView(view, topValue, bottomValue); 31 } 32 topValue = bottomValue; 33 } 34 } catch (Throwable throwable) { 35 Timber.d(throwable); 36 } 37 }
3è¡ç®-æåã®å¯èŠèŠçŽ ã®äžéšåº§æšã§å€æ°topValueãéå§ããŸãã ãã®äŸ¡å€ã®ã¹ããŒããããç§ãã¡ã¯èžãç¶ããŸãã
7è¡ç®-æç»ããèŠçŽ ã®ã€ã³ããã¯ã¹ã«ãã£ãŠãµã€ã¯ã«ãéå§ããŸãã
8è¡ç®-ãã£ãã·ã¥ã«å¿ èŠãªã¢ã€ãã ãèŠã€ãããšæ¥œèŠ³çã§ãã
9è¡ç®-ãã£ãã·ã¥ã調ã¹ãŸãïŒåžæãããå ŽåïŒã
10-12è¡ç®-ãã£ãã·ã¥ã«å¿ èŠãªèŠçŽ ãèŠã€ãããªãã£ãå ŽåãRecyclerView.Recyclerã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãããããèŠæ±ããŸããããã¯ãç¹å®ã®äœçœ®ã®ã¢ããã¿ãŒããã®ããŒã¿ã§åæåããããã¥ãŒãè¿ããŸãã
14è¡ç®-èŠçŽ ããŸã ãã£ãã·ã¥å ã«ãã£ãå Žåãããããåé€ããŸãã
è¡16-ç»é¢äžã®äœçœ®ã«å¿ããŠèŠçŽ ã®é«ããèšç®ããŸãã
17è¡ç®-èŠçŽ ã®äžã®å¢çç·ãèšç®ããŸãã
18ã20è¡ç®-å®è¡æ¹æ³ãããã£ãŠããå ŽåãèŠçŽ ã®ã³ã³ãã³ããã¹ã±ãŒãªã³ã°ããŸãã
21è¡ç®-çŸåšã®ãã¥ãŒïŒãã£ãã·ã¥ããååŸïŒã以åã«ã¬ã³ããªã³ã°ããããã©ããããŸãã¯æ°ããã€ã³ã¹ã¿ã³ã¹ãååŸãããã©ãããç解ããããšãéèŠã§ãã ããã2ã€ã®ãªãã·ã§ã³ã«ã¯ãç°ãªãã¢ãããŒããå¿ èŠã§ãã
è¡22ã28-ãã¥ãŒããã£ãã·ã¥ããååŸãããå Žåãå¿ èŠã«å¿ããŠãäžéšãšäžéšã®åº§æšã®å€ãå€æŽãããã¥ãŒãã¢ã¿ããããŸãã
30è¡ç®-ãã¥ãŒããã£ãã·ã¥ããã§ã¯ãªãå ŽåãèŠçŽ ã衚瀺ããã«ã¯ãlayoutViewã¡ãœããã䜿çšããŸããããã«ã€ããŠã¯ä»¥äžã§èª¬æããŸãã
è¡32-topValueãæ°ããæç»ããããã¥ãŒã®äžåŽã®å¢çã«ã·ããããŠããã®å€ãã«ãŒãã®æ¬¡ã®å埩ã®éå§ç¹ã«ãªãããã«ããŸãã
次ã«ãRecyclerView.Recyclerã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ããååŸããæ°ãããªã¹ãã¢ã€ãã ã衚瀺ããããã«èšèšãããlayoutViewã¡ãœããã«ã€ããŠèª¬æããŸãã
1 private void layoutView(View view, int top, int bottom) { 2 addView(view); 3 measureChildWithMargins(view, 0, 0); 4 int decoratedMeasuredWidth = getDecoratedMeasuredWidth(view); 5 RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams(); 6 7 layoutDecorated(view, 8 layoutParams.leftMargin, 9 top + layoutParams.topMargin, 10 decoratedMeasuredWidth + layoutParams.rightMargin, 11 bottom + layoutParams.bottomMargin); 12 }
2è¡ç®-RecyclerViewã«ãã¥ãŒãè¿œå ããŸãã
3è¡ç®-ãã¥ãŒã枬å®ããŸãã
è¡4-ãã¥ãŒã®å¹ ãå®çŸ©ããŸãã
5è¡ç®-ãã¥ãŒã¬ã€ã¢ãŠããªãã·ã§ã³ãååŸããŸãã
è¡7-å®éã«åä¿¡ãã座æšã§ãã¥ãŒãæç»ããŸãã
ã³ã³ãã³ãã®ã¹ã±ãŒãªã³ã°
ãªã¹ãé ç®ã®æ§é å šäœã®ãã¡ãç»åã®ã¿ãã¹ã±ãŒãªã³ã°ã®å¯Ÿè±¡ã§ãã ãã®ã¹ã±ãŒãªã³ã°ã®ããžãã¯ã¯ãViewããç¶æ¿ãããScaledImageViewã¯ã©ã¹ã«ã«ãã»ã«åãããŠããŸãã
ãã®å Žåãã¹ã±ãŒãªã³ã°ã¯ä»»æã®æç¹ã§å¿ èŠã§ããããŠãŒã¶ãŒããªã¹ããã©ãã ãéäžçã«ã¹ã¯ããŒã«ããããªã©ãå¶åŸ¡ã§ããªãå€éšèŠå ã«äŸåããŸãã ããã¯ãªã¢ã¯ãã£ãããã°ã©ãã³ã°ãã©ãã€ã ã«éåžžã«èªç¶ã«é©åãããããRxJavaãšãããããŒã¿ãœãŒã¹ã§ç·Žç¿ããæ©äŒãéãããšã¯ã§ããŸããã§ããã
PublishProcessorã䜿çšããŠãç®çã®ç»åã®é«ãã決å®ããæŽæ°å€ã®ã¹ããªãŒã ãäœæããŸãã
private PublishProcessor<Integer> mScalePublishProcessor;
ãããã£ãŠãã¹ã±ãŒãªã³ã°ãå®è¡ããã«ã¯ãå¿ èŠãªå€ãæã€å¥ã®ã¹ããªãŒã èŠçŽ ãçæããã ãã§ãã
public void setImageHeight(int height) { mScalePublishProcessor.onNext(height); }
ãããŠããã®ã¹ããªãŒã ã®éåæåŠçãã©ã®ããã«è¡ããããã以äžã«ç€ºããŸãã
1 private void initObserver() { 2 mScalePublishProcessor 3 .filter(value -> value > 0 && value != mBitmapHeight && mOriginalBitmap != null) 4 .onBackpressureBuffer(1, 5 () -> Timber.d("initObserver: buffer overflow"), BackpressureOverflowStrategy.DROP_OLDEST) 6 .observeOn(Schedulers.computation(), false, 1) 7 .map(this::createScaledBitmap) 8 .map(this::setScaledBitmap) 9 .subscribe( 10 (value) -> { 11 invalidate(); 12 Timber.d("initObserver invalidate ThreadId:%d", Thread.currentThread().getId()); 13 }, Timber::d); 14 }
è¡3-åæãã£ã«ã¿ãªã³ã°ãå®è¡ããŸãã
- ãŒã以äžã®å€ãç Žæ£ããŸãã
- å€ã以åã«ã¹ã±ãŒãªã³ã°ãããç»åã®é«ããšçããå€ã¯èæ ®ããŸããã ã€ãŸã ã¹ã±ãŒãªã³ã°ãäžèŠã«ãªã£ãå Žåã
- å ã®ç»åãåæåãããŠããªããšãã¯æ¡å€§çž®å°ããªãã§ãã ããã åæåã«ã€ããŠã¯ãsetBitmapã¡ãœããã§åŸè¿°ããŸãã
4è¡ç®-ãããã¡ãŒãµã€ãº1ãšã¬ã¡ã³ãã®ããã¯ãã¬ãã·ã£ãŒãšããããã¡ãŒããå€ããšã¬ã¡ã³ããçµãåºãæŠç¥ã䜿çšããŸãã ãã®ãããã¹ã±ãŒãªã³ã°ã«æãé¢é£ããé«ãã®å€ãåžžã«ååŸããŸãã ç§ãã¡ã®å Žåãããã¯éåžžã«éèŠã§ãããªããªãããŠãŒã¶ãŒã®ã¢ã¯ã·ã§ã³ïŒããšãã°ããªã¹ãã®éäžçãªã¹ã¯ããŒã«ïŒã«å¿çããŠãèŠçŽ ãåŠçãããããéãèŠçŽ ãçæããïŒã¹ã±ãŒãªã³ã°ãå®è¡ããïŒããããœãŒã¹ãããããã§ãã ãã®ãããªç¶æ³ã§ã¯ãå€ããããã¡ã«èç©ããŠãããã®èŠçŽ ãé çªã«åŠçããããšã¯æå³ããããŸããããããã®èŠçŽ ã¯æ¢ã«å€ããªã£ãŠããããããŠãŒã¶ãŒã¯ãã§ã«ãã®ç¶æ ããæŒãã€ã¶ãããŠããŸãã
å¹æã説æããã³åŒ·åããããã«ãç»åã®ã¹ã±ãŒãªã³ã°æ¹æ³ïŒcreateScaledBitmapïŒã«25ããªç§ã®é 延ãè¿œå ãã以äžã®2ã€ã®èŠèŠåãè¡ããŸãããèå§ãªãïŒå·ŠïŒãšèå§ããïŒå³ïŒã å·ŠåŽã®ã€ã³ã¿ãŒãã§ãŒã¹ã¯æããã«ãŠãŒã¶ãŒã®ã¢ã¯ã·ã§ã³ã®èåŸã«ãããäœããã®ç¬èªã®ç掻ãéã£ãŠããŸãã æ£ãã-ã¹ã±ãŒãªã³ã°æ¹æ³ã®è¿œå ã®é 延ã«ããæ»ãããã倱ãããŸããããå¿çæ§ã¯ãããŸããã
æ¯èŒ
èå§ãªã | èå§ |
6è¡ç®-ãããã¡ãŒã®ãµã€ãºã§äœæ¥ãSchedulers.computationïŒïŒã¹ããªãŒã ã«è»¢éããŸãã
7è¡ç®-ã¹ã±ãŒãªã³ã°ãå®è¡ããŸãïŒä»¥äžã®æ¹æ³ã®èª¬æãåç §ïŒã
8è¡ç®-衚瀺ããã¹ã±ãŒãªã³ã°ç»åãèšå®ããŸãã
9è¡ç®-ã¹ããªãŒã ããµãã¹ã¯ã©ã€ãããŸãã
11è¡ç®-ã¹ã±ãŒãªã³ã°ã®æåŸã«ãèŠçŽ ãåæç»ããŸãã
createScaledBitmapã¡ãœãããç®çã®ãµã€ãºã®ç»åã®ååŸã«çŽæ¥é¢äžããŸãã
1 private Bitmap createScaledBitmap (Integer value) { 2 Timber.d("createScaledBitmap value:%d", value); 3 if (value > mHeightSpecSize) { 4 value = mHeightSpecSize; 5 } 6 return Bitmap.createScaledBitmap(mOriginalBitmap, value, value, false); 7 }
è¡3ã5-æ倧é«ãããã¥ãŒãµã€ãºã«å¶éããŸããããã¯ãonMeasureã¡ãœããã§èšç®ãããŸãã
6è¡ç®-å ã®ç»åããç®çã®ãµã€ãºã®ç»åãäœæããŸãã
setScaledBitmapã¡ãœããã§ã¯ããã¥ãŒã«è¡šç€ºããããã«ã¹ã±ãŒãªã³ã°ãããç»åãä¿åããŸãã
1 private Boolean setScaledBitmap(Bitmap bitmap) { 2 try { 3 mBitmapLock.lock(); 4 if (bitmap != mDrawBitmap && mDrawBitmap != null) { 5 mDrawBitmap.recycle(); 6 } 7 mDrawBitmap = bitmap; 8 mBitmapHeight = bitmap.getHeight(); 9 } catch (Throwable throwable) { 10 Timber.d(throwable); 11 } 12 mBitmapLock.unlock(); 13 return true; 14 }
è¡3ã12-ããã¯ã䜿çšããŠãç»é¢ã«æç»ãããç»åãå«ãå€æ°ãžã®ã¢ã¯ã»ã¹ãåæããŸãã
è¡4ã6-以åã«äœæããã€ã¡ãŒãžã䜿çšããŸãã
7ã8è¡ç®-æ°ããç»åãšãã®ãµã€ãºãèŠããŠãããŠãã ããã
setBitmapã¡ãœããã¯ãå ã®ç»åãèšå®ããŸãã
1 public void setBitmap(Bitmap bitmap) { 2 if (bitmap != null) { 3 mOriginalBitmap = Bitmap.createScaledBitmap(bitmap, mWidthSpecSize, mHeightSpecSize, false); 4 if (bitmap != mOriginalBitmap) { 5 bitmap.recycle(); 6 } 7 int height = mBitmapHeight; 8 mBitmapHeight = 0; 9 setImageHeight(height); 10 } 11 }
è¡3-å ã®ç»åãæ¡å€§çž®å°ããŠå¯žæ³ã衚瀺ããŸãã ããã«ãããå ã®ç»åã®ãµã€ãºããã¥ãŒããã倧ããå ŽåãcreateScaledBitmapã¡ãœããã§ã¹ã±ãŒãªã³ã°ãå®è¡ãããšãã«ãªãœãŒã¹ãç¯çŽã§ããŸãã
4-6è¡ç®-å€ãå ã®ç»åãç Žæ£ããŸãã
7ã9è¡ç®-initObserverã¡ãœããã®ãã£ã«ã¿ãŒãå æããããã«ã¹ã±ãŒãªã³ã°ã®é«ãããŒãã«èšå®ããã¹ããªãŒã èŠçŽ ãçæããŠæ°ããã€ã¡ãŒãžãç®çã®ã¹ã±ãŒã«ã§åæç»ããŸãã
ãŸãšã
èšäºã®äžéšãšããŠããã¬ãŒãã³ã°ãããžã§ã¯ãã®äœæ¥äžã«æãã€ããããã€ãã®ã¢ã€ãã¢ãæ確ã«è¿°ã¹ãããšããŸããã ãã¢ãããžã§ã¯ãã¯ãGitHubã«ãããŸãã ã³ã¡ã³ããææ¡ãææ¡ãæ¹å€ãšãšãã«ãã³ã¡ã³ãããŠãã ããã