Httpで画像をとってきてImageViewにセットする
Weak Referencesから学ぶJavaにおけるオブジェクトの4種類の参照でWeak Referenceを学んだ後、http://android-developers.blogspot.jp/2010/07/multithreading-for-performance.htmlを真似ながら、HTTPで画像をとってきてImageViewにセットするクラスを書いた。
テストはこんな感じ。
@RunWith(RobolectricTestRunner.class) public class DownloadImageTaskTest { private static final MockWebServer mockWebServer = new MockWebServer(); @BeforeClass public static void prepare() throws IOException { mockWebServer.play(); } @AfterClass public static void cleanup() throws IOException { mockWebServer.shutdown(); } @Test public void testTask() throws Exception { ByteArrayOutputStream buffer = createImageByteArray(); mockWebServer.enqueue(new MockResponse() .setResponseCode(HttpRequest.SC_OK) .setBody(buffer.toByteArray() )); URL url = mockWebServer.getUrl("/"); ImageView imageView = new ImageView(null); DownloadImageTask task = new DownloadImageTask(imageView); task.execute(url); assertThat(imageView.getDrawable(), is(notNullValue())); } private ByteArrayOutputStream createImageByteArray() throws IOException { File file = new File("./src/test/resources/files/jpg/猫.jpeg"); InputStream in = new BufferedInputStream(new FileInputStream(file)); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); int nRead; byte[] data = new byte[1024]; while ((nRead = in.read(data, 0, data.length)) != -1) { buffer.write(data, 0, nRead); } buffer.flush(); return buffer; } }
で、実装はこんな感じ。
public class DownloadImageTask extends AsyncTask<URL, Void, Bitmap> { private static final String TAG = DownloadImageTask.class.getSimpleName(); private final WeakReference<ImageView> imageViewReference; public DownloadImageTask(ImageView imageView) { this.imageViewReference = new WeakReference<ImageView>(imageView); } @Override protected Bitmap doInBackground(URL... urls) { URL url = urls[0]; try { HttpGet get = new HttpGet(url); HttpResponse response = get.execute(); return response.getResponseBodyBitmap(); } catch (MalformedURLException e) { Log.e(TAG, e.getMessage(), e); } catch (IOException e) { Log.e(TAG, e.getMessage(), e); } return null; } @Override protected void onPostExecute(Bitmap bitmap) { if (imageViewReference != null) { ImageView imageView = imageViewReference.get(); if (imageView != null) { imageView.setImageBitmap(bitmap); } } } }
doInBackground()内でViewに触ろうとするとdoInBackgroundの処理はUIスレッド上じゃないので
Only the original thread that created a view hierarchy can touch its views.
って言われるからね。
と言われて意味がよくわからなかったらAndroidの公式ドキュメントをちゃんと嫁、という啓示かもしれない。
ちなみにActivityからこんな感じで使う。
new DownloadImageTask(mImageView).execute(imageUrl);
なお、
HttpGet get = new HttpGet(url);
HttpResponse response = get.execute();
は、どこかのと名前がかぶっているけど両方共お手製のクラスです。
今日は眠いなぁ。。