本文記錄圖片加載功能中不涉及緩存的部分。
數據
先搞了一些數據,都是 pixabay 的免費圖。
public static final List<String> IMAGES = Arrays.asList(
"https://cdn.pixabay.com/photo/2017/07/18/18/01/little-girl-2516578_960_720.jpg",
"https://cdn.pixabay.com/photo/2016/04/23/10/43/child-1347385_960_720.jpg",
"https://cdn.pixabay.com/photo/2015/06/02/20/58/little-girl-running-795505_960_720.jpg",
"https://cdn.pixabay.com/photo/2014/10/07/01/38/girl-477015_960_720.jpg",
"https://cdn.pixabay.com/photo/2015/07/27/18/52/water-863053_960_720.jpg",
"https://cdn.pixabay.com/photo/2016/05/12/07/13/kids-1387118_960_720.jpg",
"https://cdn.pixabay.com/photo/2017/06/22/23/40/picking-flowers-2432972_960_720.jpg",
"https://cdn.pixabay.com/photo/2018/01/08/20/24/little-girl-3070211_960_720.jpg",
"https://cdn.pixabay.com/photo/2015/06/25/17/56/baby-821627_960_720.jpg",
"https://cdn.pixabay.com/photo/2017/07/18/18/02/chasing-butterflies-2516581_960_720.jpg",
"https://cdn.pixabay.com/photo/2015/07/31/22/59/princess-869721_960_720.jpg"
);
加載的入口
在 RecyclerViewAdapter 的 bind 方法中啓動 AsyncTask。
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
imageView.setTag(url);
ImageWorkTask task = new ImageWorkTask(url);
task.execute();
mTasks.add(task);
}
下載圖片
分爲兩個部分
一是網絡請求部分:
@Override
protected Bitmap doInBackground(String... strings) {
HttpURLConnection connection = null;
try {
URL url = new URL(this.url);
connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(false);
connection.setDoInput(true);
connection.setRequestMethod("GET");
connection.setUseCaches(false);
connection.setChunkedStreamingMode(0);
connection.setConnectTimeout(3000);
connection.connect();
// 主要是爲了獲取 InputStream
Bitmap bitmap = getBitmapFromInputStream(connection.getInputStream());
return bitmap;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
}
return null;
}
二是解析圖片部分:
private Bitmap getBitmapFromInputStream(InputStream input) {
Bitmap bitmap = null;
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
// 讀取所有數據,不直接 decodeStream,因爲可能圖片太大。
byte[] buffer = new byte[1024];
int len;
while ((len = input.read(buffer)) >= 0) {
output.write(buffer, 0, len);
}
byte[] array = output.toByteArray();
// 計算縮放尺寸,這裏最好用 R.dimension 不要寫死。
int scale = calculateScaleOfImage(array, 240 * 2, 240 * 2);
BitmapFactory.Options option = new BitmapFactory.Options();
option.inSampleSize = scale;
// 然後解析成 Bitmap
bitmap = BitmapFactory.decodeByteArray(array, 0, array.length, option);
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
private int calculateScaleOfImage(byte[] array, int maxWidth, int maxHeight) {
BitmapFactory.Options option = new BitmapFactory.Options();
option.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(array, 0, array.length, option);
int xScale = Math.round((float) option.outWidth / maxWidth);
int yScale = Math.round((float) option.outHeight / maxHeight);
return Math.max(xScale, yScale);
}
顯示出來
這裏用的是查找 tag 的策略,好處是不用保存 imageView 的引用。
@Override
protected void onPostExecute(Bitmap bitmap) {
ImageView view = mRecyclerView.findViewWithTag(url);
if (view != null) {
view.setImageBitmap(bitmap);
}
mTasks.remove(url);
}
清理
所有的 ImageWorkTask
在退出界面後應取消掉。
public void clearTasks() {
for (ImageWorkTask task : mTasks) {
task.cancel(true);
}
}
總結
由於 RecyclerView 複用 ItemView 的原因,滑動到被複用的 ItemView 並不會立刻顯示出正確的圖片,還是顯示原來的圖片,得等網絡下載完畢後才能顯示正確。不用緩存真的是體驗很差。
(ole)