Использование 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

Другие вопросы по тегам