Android でインターネットの画像をキャッシュする
Android アプリを作っていると、インターネットから画像を取得して利用することがよくありますが、 それをローカルにキャッシュするにはどうすればいいでしょう、という話を書きます。
ネットからのダウンロードはバックグラウンド・スレッドでやらないと(3.0 以降で)落ちるので、AsyncTask
@Override protected Bitmap doInBackground(Void... params) { try { URL url = new URL(mUrl); URLConnection connection = url.openConnection(); connection.setUseCaches(true); // ここが大切 return BitmapFactory.decodeStream(connection.getInputStream()); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; }
途中の強調表示したところがポイントです。Java 標準でキャッシュする機能があるとか知らなかった。
実はこれだけでは動かなくて、どのようにキャッシュするのか自分で実装しないと駄目です。ResponseCache というクラスを継承して作ります。こんな感じです。
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.CacheRequest; import java.net.CacheResponse; import java.net.ResponseCache; import java.net.URI; import java.net.URLConnection; import java.net.URLEncoder; import java.util.List; import java.util.Map; public class AndroidResponseCache extends ResponseCache { private final File mCacheDir; public AndroidResponseCache(File cacheDir) { mCacheDir = cacheDir; } @Override public CacheResponse get(URI uri, String s, Map<String, List<String>> arg2) throws IOException { final File file = new File(mCacheDir, escape(uri.getPath())); if (file.exists()) { return new CacheResponse() { @Override public Map<String, List<String>> getHeaders() throws IOException { return null; } @Override public InputStream getBody() throws IOException { return new FileInputStream(file); } }; } return null; } @Override public CacheRequest put(URI uri, URLConnection connection) throws IOException { final File file = new File(mCacheDir, escape(connection.getURL().getPath())); return new CacheRequest() { @Override public OutputStream getBody() throws IOException { return new FileOutputStream(file); } @Override public void abort() { file.delete(); } }; } private String escape(String uri) { // ちょっとオーバーキルらしい (ファイル名に使える文字変換してしまう) return URLEncoder.encode(uri); } }
Application か Activity の onCreate あたりでキャッシングに上のクラスを使うように設定します。
ResponseCache.setDefault(new AndroidResponseCache(getCacheDir()));
これまで何度も自前で作ってきた苦労は何だったんだ。
- 参考にしたページ (というかほとんど組み合わせて翻訳しただけかもしれない)
コメント
コメントを投稿