Использование AsyncTask для загрузки файлов изображений из внутреннего хранилища
Я пытаюсь загрузить файлы изображений в виде миниатюр из своего внутреннего хранилища в список. В настоящее время я использую ViewHolder, но при прокрутке загрузка все еще прерывистая, поэтому я попытаюсь использовать AsyncTask. Однако я не могу понять, как структурировать AsyncTask, так как большинство примеров, которые я нашел, касается загрузки с веб-сайта. Я даже не уверен, стоит ли мне создавать подклассы в BaseAdapter или в MainActivity. Я добавил свой базовый адаптер ниже с незавершенной AsyncTask внизу. Как мне структурировать это так: используйте AsyncTask, чтобы помочь ViewHolder, или напрямую передайте изображение в AsyncTask и верните ему растровое изображение, чтобы ListView плавно прокручивался?
public class ListViewAdapter extends BaseAdapter {
private static final int WIDTH = 250;
private static final int HEIGHT = 250;
private static final int ROTATION = 90;
private final static String TAG = "Pictures";
private final ArrayList<SelfieObject> mItems = new ArrayList<SelfieObject>();
private Context mContext;
private File mStorageDir;
private String mFilePrefix;
public ListViewAdapter(Context context, File storageDir, String filePrefix) {
mContext = context;
mStorageDir = storageDir;
mFilePrefix = filePrefix;
//get file list from storage to display
InitializeItemsFromStorage(storageDir, filePrefix);
}
//this method creates an array of files stored on the device or SD card.
private void InitializeItemsFromStorage(File storageDir, String prefix) {
log("in InitializeItemsFromStorage()");
mItems.clear();
File[] files = getFiles(storageDir, prefix);
for (File f : files) {
SelfieObject selfie = new SelfieObject(f);
mItems.add(selfie);
}
}
public void Update() {
log("in Update()");
InitializeItemsFromStorage(mStorageDir, mFilePrefix);
notifyDataSetChanged();
}
/*
* return the list of file objects of the given directory that begin with
* the prefix.
*/
private File[] getFiles(File storageDir, final String prefix) {
FileFilter fileFilter = new FileFilter() {
@Override
public boolean accept(File pathname) {
if (pathname.isFile() && pathname.getName().startsWith(prefix))
return true;
else
return false;
}
};
File[] result = storageDir.listFiles(fileFilter);
return result;
}
public int getCount() {
log("in getCount()");
return mItems.size();
}
public Object getItem(int position) {
log("in getItem()");
return mItems.get(position);
}
public long getItemId(int position) {
log("in getItemId()");
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Log.v(TAG, "in getView for position " + position +
", convertView is " +
((convertView == null)?"null":"being recycled"));
View newView = convertView;
ViewHolder holder;
if (null == convertView) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
newView = inflater.inflate(R.layout.single_item, null);
holder = new ViewHolder();
holder.description = (TextView) newView.findViewById(R.id.textView1);
holder.picture = (ImageView) newView.findViewById(R.id.imageView1);
newView.setTag(holder);
} else {
holder = (ViewHolder) newView.getTag();
}
holder.picture.setScaleType(ImageView.ScaleType.CENTER_CROP);
SelfieObject selfie = (SelfieObject) getItem(position);
setPic(holder.picture, new Point(WIDTH, HEIGHT), selfie.getPath());
TextView textView = (TextView) holder.description;
textView.setText(selfie.getName());
log("Exiting getView");
return newView;
}
static class ViewHolder {
ImageView picture;
TextView description;
}
public void add(SelfieObject listItem) {
mItems.add(listItem);
notifyDataSetChanged();
}
public ArrayList<SelfieObject> getList(){
return mItems;
}
public void removeAllViews(){
mItems.clear();
this.notifyDataSetChanged();
}
public static void setPic(ImageView imageView, Point requestedSize,
String pathName) {
// set the dimensions of the View
int targetW = requestedSize.x;
int targetH = requestedSize.y;
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW / targetW, photoH / targetH);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(pathName, bmOptions);
imageView.setImageBitmap(bitmap);
imageView.setRotation(ROTATION);
}
//Automation logging tool
public void log(String s){
Log.i(TAG, s);
}
private class AsyncTaskLoadImage extends AsyncTask<Object, Void, Bitmap>{
private ImageView image;
private String path;
public AsyncTaskLoadImage(ImageView image){
this.image = image;
this.path = image.getTag().toString();
}
@Override
protected Bitmap doInBackground(Object... params) {
Bitmap bitmap = null;
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + path);
if(file.exists()){
bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
}
return bitmap;
}
}
}
1 ответ
AsyncTask должен делать все слишком медленно, чтобы делать это в потоке пользовательского интерфейса. В этом примере выборка и уменьшение выборки изображения и настройка ViewHolder должны выполняться в фоновом режиме.
Однако я предлагаю вам не пытаться исправить ListView самостоятельно, а взглянуть на уже существующие решения, такие как: https://github.com/lucasr/smoothie
Кроме того, я настоятельно рекомендую вам уменьшить количество ваших растровых изображений, в противном случае они будут занимать много лишнего вычислительного времени и памяти. В то время как предыдущий может задерживать ваш пользовательский интерфейс при прокрутке, последний даст вам приятное исключение OutOfMemoryException. Смотрите: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html