使用AsyncTask从内部存储加载图像文件

时间:2015-01-23 02:59:28

标签: android android-asynctask baseadapter getview

我正在尝试将缩略图形式的图片文件从内部存储加载到列表视图。目前,我正在使用ViewHolder,但滚动时加载仍然不稳定所以我将尝试使用AsyncTask。但是我无法理解如何构建AsyncTask,因为我发现大多数示例都是从网站下载的。我甚至不确定我是否应该在我的BaseAdapter或我的MainActivity中将其子类化。我在下面添加了我的baseadapter,底部是未完成的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 个答案:

答案 0 :(得分:1)

AsyncTask应该做任何在UI线程中做得太慢的事情。在此示例中,应在后台完成对图像的提取和下采样以及设置ViewHolder。

但是,我建议您不要自己尝试修复ListView,而是查看现有的解决方案,例如:https://github.com/lucasr/smoothie

另外,我强烈建议你对你的位图进行下采样,否则会消耗大量的计算时间和内存。虽然前一个可以在滚动时滞后你的UI,但后者会给你一个很好的OutOfMemoryException。请参阅:http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html