deprecated な Gallery の代替を自作する(1)
android プログラミングで遊ぶ。
ずっと作ってみたかったアプリがあって、先ずはフィルムストリップみたく写真を選ぶ機能から作ってみる。 本を見るとその名も Gallery というコンポーネントがあって、これを配置すれば簡単にできそうである。
ところが配置すると、『deprecated』とある。比較的新しい部品のようではあるが、android 4 からは非推奨らしいのだ。というわけで代替手段を探す。ところが… Gallery ばりにペタンと貼って終了、ってのはどうもなさそう。そもそもなんで Gallery が非推奨なんだって調べたら、どうもキャッシュに問題があるらしい。おそらくものすごく大量の画像リストを喰わせると落ちるとか、落ちないにしてもかなりメモリを喰うんだろうと想像。
無いものは作るしかない、ということで、ネットから拝借した HorizontalListView とキャッシュ機構を自作したら意外に簡単に実装できた。キャッシュのサイズを指定して、キャッシュがいっぱいになるまで画像を先読みしてため込んでおくということもできそう。僕は EOS-60D の画像ビューアを作ろうとしているので、高解像度の画像からサムネイルを作る処理というのは1フレームにはおさまりそうにないのだ。とりあえず、キャッシュ機構はこんな感じ。あらかじめ作った配列をサイズを保ったまま使いまわす。
ずっと作ってみたかったアプリがあって、先ずはフィルムストリップみたく写真を選ぶ機能から作ってみる。 本を見るとその名も Gallery というコンポーネントがあって、これを配置すれば簡単にできそうである。
ところが配置すると、『deprecated』とある。比較的新しい部品のようではあるが、android 4 からは非推奨らしいのだ。というわけで代替手段を探す。ところが… Gallery ばりにペタンと貼って終了、ってのはどうもなさそう。そもそもなんで Gallery が非推奨なんだって調べたら、どうもキャッシュに問題があるらしい。おそらくものすごく大量の画像リストを喰わせると落ちるとか、落ちないにしてもかなりメモリを喰うんだろうと想像。
無いものは作るしかない、ということで、ネットから拝借した HorizontalListView とキャッシュ機構を自作したら意外に簡単に実装できた。キャッシュのサイズを指定して、キャッシュがいっぱいになるまで画像を先読みしてため込んでおくということもできそう。僕は EOS-60D の画像ビューアを作ろうとしているので、高解像度の画像からサムネイルを作る処理というのは1フレームにはおさまりそうにないのだ。とりあえず、キャッシュ機構はこんな感じ。あらかじめ作った配列をサイズを保ったまま使いまわす。
package ps.ksk.imageanalyzer.util; public class LoopedCacheList{ int buffersize = 0; int topPosition = 0; // 配列のどこが先頭か int topIndex = 0; // topPositionの本来のインデックス Object[] objectArray; public LoopedCacheList(int buffersize) { this.buffersize = buffersize; objectArray = new Object[buffersize]; } /** * 指定したインデックスに要素をキャッシュします. * 必要に応じてキャッシュ範囲をシフトし、はみ出す要素は削除します. * * @param index * キャッシュ要素のインデックス * @param object * キャッシュするオブジェクト */ public void cache(int index, T object) { // 1) cache all swipe and build if (index < topIndex - buffersize || index > topIndex + buffersize) { clearBuffer(); topPosition = 0; topIndex = index; objectArray[0] = object; return; } // 2) update only if (isCached(index)) { int rIndex = topPosition + index - topIndex; if (rIndex >= buffersize) rIndex -= buffersize; objectArray[rIndex] = object; return; } // 3) cache left shift if (index < topIndex) { int shiftCount = topIndex - index; for (int i = 0; i < shiftCount; i++) { objectArray[getArrayPosition(i, topPosition, topIndex)] = null; } topPosition -= shiftCount; if (topPosition < 0) topPosition += buffersize; topIndex = index; objectArray[topPosition] = object; return; } // 4) cache right shift if (index > topIndex + buffersize - 1) { int shiftCount = index - topIndex - buffersize + 1; for (int i = 0; i < shiftCount; i++) { objectArray[getArrayPosition(i, topPosition, topIndex)] = null; } topPosition += shiftCount; if (topPosition >= buffersize) topPosition -= buffersize; topIndex = index - buffersize + 1; objectArray[getArrayPosition(index, topPosition, topIndex)] = object; } } /** * インデックスを指定して要素を取得する * * @param index * @return */ @SuppressWarnings("unchecked") public T getAt(int index) { if (!isCached(index)) return null; int rIndex = topPosition + index - topIndex; if (rIndex >= buffersize) rIndex -= buffersize; return (T) objectArray[rIndex]; } /** * 指定したインデックスがキャッシュにヒットするかどうかを判定する * * @param index * @return */ public boolean isCached(int index) { if (index < topIndex) return false; if (index > topIndex + buffersize - 1) return false; return true; } private void clearBuffer() { for (int i = 0; i < buffersize; i++) objectArray[i] = null; } /** * * @param index * @return */ private int getArrayPosition(int index, int topPosition, int topIndex) { int rIndex = topPosition + index - topIndex; while (rIndex >= buffersize) rIndex -= buffersize; while (rIndex < 0) rIndex += buffersize; return rIndex; } }
コメント
コメントを投稿