Использование cwac-endless адаптера для загрузки бесконечного ListView изображений
Я написал следующий код, который реализует бесконечную прокрутку ListView, содержащего ImageViews, с использованием бесконечного адаптера CWAC. Изображения извлекаются из Интернета по запросу с помощью AsyncTasks:
package com.myproject.ui.adapter;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.LruCache;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import com.commonsware.cwac.endless.EndlessAdapter;
public class MyThumbsAdapter extends EndlessAdapter {
public static class FetchThumbTask extends AsyncTask<String, Void, Bitmap> {
private final Context mContext;
private final BaseAdapter mAdapter;
private final String mThumbId;
private final View mView;
public FetchThumbTask(Context context, BaseAdapter adapter, View view, String thumbId) {
mContext = context;
mAdapter = adapter;
mView = view;
mThumbId = thumbId;
}
@Override
protected Bitmap doInBackground(String... arg0) {
Bitmap bitmap = null;
if (cache.get(mThumbId) == null) {
// Fetch thumbnail
try {
URL url = new URL(...);
InputStream is = url.openStream();
bitmap = BitmapFactory.decodeStream(is);
cache.put(mThumbId, bitmap);
} catch (Exception e) {
...
}
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
// Set the loaded image on the ImageView
ImageView imageView = (ImageView) mView.findViewById(R.id.thumb_image);
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
public static class MyThumbsBaseAdapter extends BaseAdapter {
private final Context mContext;
private final List<String> mThumbIds = new ArrayList<String>();
public MyThumbsBaseAdapter(Context context) {
mContext = context;
}
public void addThumbIds(List<String> thumbIds) {
mThumbIds.addAll(thumbIds);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
String thumbId = mThumbIds.get(position);
View rootView = convertView;
if (rootView == null) {
rootView = LayoutInflater.from(parent.getContext()).inflate(
R.layout.thumbnails, null);
}
ImageView imageView =
(ImageView) rootView.findViewById(R.id.doodle_thumb_image);
Bitmap bitmap = cache.get(thumbId);
if (bitmap == null) {
loadThumbBitmap(rootView, thumbId);
} else if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
return rootView;
}
@Override
public int getCount() {
return mThumbIds.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
private void loadThumbBitmap(View view, String thumbId) {
new FetchThumbTask(mContext, this, view, thumbId)
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
static {
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 8;
cache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in kilobytes rather than
// number of items.
return bitmap.getByteCount() / 1024;
}
};
}
private static final LruCache<String, Bitmap> cache;
private List<String> mThumbIdsCache;
public MyThumbsAdapter(Context context) {
super(new MyThumbsBaseAdapter(context));
}
@Override
protected View getPendingView(ViewGroup parent) {
return LayoutInflater.from(parent.getContext())
.inflate(R.layout.loading_thumb, null);
}
@Override
protected boolean cacheInBackground() throws Exception {
JsonReader reader = // Retrieve thumb ids list from server
mThumbIdsCache = // Returned thumb ids list
return true;
}
@Override
protected void appendCachedData() {
MyThumbsBaseAdapter adapter = (MyThumbsBaseAdapter) getWrappedAdapter();
adapter.addThumbIds(mThumbIdsCache);
}
}
Я использую LruCache для кэширования растровых изображений, загруженных из Интернета. Проблема в том, что при тестировании на моем Nexus 7 я вижу много ошибок в кеше, на которых должно быть достаточно памяти. Это заставляет изображения встать на свои места, когда я прокручиваю вверх / вниз по ListView.
Хуже того, я видел сбой приложения с ошибками OutOfMemory, но не могу последовательно воспроизвести.
Что я здесь не так делаю? Разве я не должен запускать отдельные AsyncTasks для каждого изображения?
РЕДАКТИРОВАТЬ: я должен также отметить, что загружаемые мной изображения предварительно масштабируются.
1 ответ
Я думаю, что вам нужно сделать, это показать Thumbnails
вместо растрового изображения на вашем экране. Вы можете создавать эскизы и отображать в соответствии с вашими требованиями к размеру. И всякий раз, когда пользователь нажимает на Thumb
Возьми оригинальный путь и поставь обои.
Другой вариант - вы можете использовать Universal Image Loader, который поможет вам сохранить изображение на диске (например, SD card
или ваше приложение Internal memory
). Так что выпуск Out of Memory
может быть решена.
А также для лучшей практики для отображения растровых изображений, эффективное отображение растровых изображений будет полезным.
Редактировать:
Используйте следующую конфигурацию для вашего приложения. Это позволит кэшировать изображения в директории кеша приложения.
File cacheDir = new File(this.getCacheDir(), "cwac");
if (!cacheDir.exists())
cacheDir.mkdir();
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
CWAC.this)
.threadPoolSize(5)
.threadPriority(Thread.MIN_PRIORITY + 3)
.denyCacheImageMultipleSizesInMemory()
// .memoryCache(new UsingFreqLimitedMemoryCache(2000000)) // You
// can pass your own memory cache implementation
.memoryCacheSize(1048576 * 10)
// 1MB=1048576 *declare 20 or more size if images are more than
// 200
.discCache(new UnlimitedDiscCache(cacheDir))
// You can pass your own disc cache implementation
//.defaultDisplayImageOptions(DisplayImageOptions.createSimple())
.build();