意外と見てる人がいるので、調子乗って酔った勢いでその2を書いてみたぁ(*ノω・*)テヘ
寝ても酔っても仕事するさきちゃん(^o^)v
気を取り直して、まずはやっぱりディスクキャッシュからやな。と言っても前回することは大体書いてもうたけど。
じゃじゃんと取り出したりまするは4.1.1_r1のDiskLruCache.java^^
元々はキーとしてStringを使うようになっておりまする。でも今回は諸般の事情でMediaCodecのエンコーダーが吐くpresentationTimeUsをキーに使いたいのでありまする。キーとしてlongしか来ないとわかってるのにわざわざザワザワStringに変換するなんてありえないのでありんす。
という事で、キーの型をStringからlongに変えます。でも一部分は残念なJavaの制限によりLongにしまする(´・ω・`)
ついでに前回も書きましたがLruだと都合がわるいので挿入順にする必要があります。
という事で例えば
1 2 |
private final LinkedHashMap<string , Entry> lruEntries = new LinkedHashMap<>(0, 0.75f, true); </string> |
となっていた所は
1 2 3 |
private final LinkedHashMap<long , Entry> mEntries = new LinkedHashMap</long><long , Entry>(0, 0.75f, false/*accessOrder*/); // 挿入順 </long> |
みたく書き換えてしまいます。
フィールド名が変わってるのは好みの問題^^; だってLruじゃないんだもーん^^
これでディスクキャッシュの方はだいたいおしまいなんやけど、多少は使いやすいようにヘルパーメソッドを追加しましょう。
まずは一番古い要素のキーとそれに対応する要素を取得するメソッド
1 2 3 4 5 6 7 |
public synchronized long oldestKey() { return mEntries.size() > 0 ? mEntries.keySet().iterator().next() : 0; } public synchronized Snapshot getOldest() throws IOException { return get(oldestKey()); } |
イテレータの先頭を取得するだけ。簡単にゃぁ(\^^/)
さらに元々のDiskLruCacheクラスでは#getメソッドで
1 |
public synchronized Snapshot get(String key) throws IOException; |
Snapshotとして要素を取得したあとはSnapshot#getStringで文字列として読み取るか、Snapshot#getInputStreamでInputStreamとして読み取るかの2択となりますが、今回の用途ではbye配列またはByteArray、あるいはintとして読み取れた方が便利です。
という事で、Snapshotクラスにもメソッドを追加します。
今回は使ってないけどおまけで余計なのも追加してこんな感じ。
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 |
public final class Snapshot implements Closeable { private final long key; private final long sequenceNumber; private final InputStream[] ins; private Snapshot(final long key, final long sequenceNumber, final InputStream[] ins) { this.key = key; this.sequenceNumber = sequenceNumber; this.ins = ins; } /** * Returns an editor for this snapshot's entry, or null if either the * entry has changed since this snapshot was created or if another edit * is in progress. */ public Editor edit() throws IOException { return TimeShiftDiskCache.this.edit(key, sequenceNumber); } /** * Returns the unbuffered stream with the value for {@code index}. */ public InputStream getInputStream(final int index) { return ins[index]; } /** * Returns the string value for {@code index}. */ public String getString(final int index) throws IOException { return inputStreamToString(getInputStream(index)); } public byte[] getBytes(final int index) throws IOException { return getBytes(index, null); } public int available(final int index) throws IOException { final InputStream in = getInputStream(index); return in != null ? in.available() : 0; } public int getInt(final int index) throws IOException { final byte[] work = new byte[4]; final InputStream in = getInputStream(index); try { if (in.read(work) == 4) { final ByteBuffer buf = ByteBuffer.wrap(work); return buf.getInt(); } } finally { in.close(); } throw new IOException(); } public long getLong(final int index) throws IOException { final byte[] work = new byte[8]; final InputStream in = getInputStream(index); try { if (in.read(work) == 8) { final ByteBuffer buf = ByteBuffer.wrap(work); return buf.getLong(); } } finally { in.close(); } throw new IOException(); } public float getFloat(final int index) throws IOException { final byte[] work = new byte[4]; final InputStream in = getInputStream(index); try { if (in.read(work) == 4) { final ByteBuffer buf = ByteBuffer.wrap(work); return buf.getFloat(); } } finally { in.close(); } throw new IOException(); } public double getDouble(final int index) throws IOException { final byte[] work = new byte[8]; final InputStream in = getInputStream(index); try { if (in.read(work) == 8) { final ByteBuffer buf = ByteBuffer.wrap(work); return buf.getDouble(); } } finally { in.close(); } throw new IOException(); } public byte[] getBytes(final int index, final byte[] dst) throws IOException { final byte[] buf = new byte[4096]; byte[] result = dst; final InputStream in = getInputStream(index); try { int total = 0; int bytes; while ((bytes = in.read(buf)) != -1) { if ((result == null) || (result.length < total + bytes)) { final byte[] temp = new byte[result == null ? 4096 : result.length * 2]; if ((total > 0) && (result != null)) { System.arraycopy(result, 0, temp, 0, total); } result = temp; } System.arraycopy(buf, 0, result, total, bytes); total += bytes; } } finally { in.close(); } return result; } @Override public void close() { for (InputStream in : ins) { closeQuietly(in); } } public long getKey() { return key; } } |
にゃにゃっ、どさくさに紛れて#getXXX以外のも載せちゃったにゃぁ(*´ڡ`●)
#getStringで文字列として取得したり、BitmapをInputStream経由で読み込むだけであれば無くても困らないんだけど、今回のようにbyte配列またはByteBufferとしてアクセスする場合に必要となるもの、それはデータの長さなのです。という事でこっそりと…ではないけど#availableメソッドも追加してあります。メソッド名は微妙とは思うけど、対応するInputStreamのメソッド名が#availableなんだもん。
それはそうとSnapshotクラスはキャッシュ内の要素のデータを読み取るためのクラスです。豚には真珠、豆腐にはかすがい、馬の耳には東風が必要なように、SnapshotクラスにはEditorクラスと対応するメソッドが必要なのです。ナンノコッチャ。
こっちもどさくさに紛れて使わないのも追加してるけど、
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 |
/** * Edits the values for an entry. */ public final class Editor { ... /** * Sets the value at {@code index} to {@code value}. */ public void set(final int index, final String value) throws IOException { Writer writer = null; try { writer = new OutputStreamWriter(newOutputStream(index), UTF_8); writer.write(value); } finally { closeQuietly(writer); } } /** * Sets the value at {@code index} to {@code buffer}. * @param index * @param buffer * @throws IOException */ public void set(final int index, final ByteBuffer buffer) throws IOException { set(index, buffer, 0, buffer.remaining()); } /** * Sets the value at {@code index} to {@code buffer}. * @param index * @param buffer * @param offset * @param size * @throws IOException */ public void set(final int index, final ByteBuffer buffer, final int offset, final int size) throws IOException { buffer.clear(); buffer.position(offset); if ((work == null) || (work.length < size)) { work = new byte[size]; } buffer.get(work); final OutputStream out = newOutputStream(index); try { out.write(work, 0, size); } finally { closeQuietly(out); } } public void set(final int index, final int value) throws IOException { final byte[] work = new byte[4]; final ByteBuffer buf = ByteBuffer.wrap(work); buf.putInt(value); buf.flip(); final OutputStream out = newOutputStream(index); try { out.write(work, 0, 4); } finally { closeQuietly(out); } } public void set(final int index, final long value) throws IOException { final byte[] work = new byte[8]; final ByteBuffer buf = ByteBuffer.wrap(work); buf.putLong(value); buf.flip(); final OutputStream out = newOutputStream(index); try { out.write(work, 0, 8); } finally { closeQuietly(out); } } public void set(final int index, final float value) throws IOException { final byte[] work = new byte[4]; final ByteBuffer buf = ByteBuffer.wrap(work); buf.putFloat(value); buf.flip(); final OutputStream out = newOutputStream(index); try { out.write(work, 0, 4); } finally { closeQuietly(out); } } public void set(final int index, final double value) throws IOException { final byte[] work = new byte[8]; final ByteBuffer buf = ByteBuffer.wrap(work); buf.putDouble(value); buf.flip(); final OutputStream out = newOutputStream(index); try { out.write(work, 0, 8); } finally { closeQuietly(out); } } ... } |
てな感じで(元からあるのは省略)。まぁオーバーロードメソッドを追加しただけやな。他の方法もあるので好みの方法で実装してんな。
一見は百聞にしかず…説明は省略です。単に面倒臭いだけという疑惑も(汗)
本当は#setも#getXXXもループ内で繰り返し呼ばれるのでメソッド内部でワーク用のバッファを確保したくは無いんだけど(。・_・。)
まぁプリミティブのローカル配列なのでスタックに積まれるだろうと言う事で勘弁してんな。
という事で酔いどれさきちゃんはそろそろお眠なのですーす。
次はService側な。
おやすみー(^_^)/~