Load bitmap in recyclerView from internalStorage with Asynctask

5.5k Views Asked by At

i'm actually working in an Android app who need to downloading PNG from web and showing it in a recyclerView. The downloading part works fine same as the save in the internal storage. The problem is with the display, when i load it in AsyncTask in my onBindViewHolder, this isn't fluid..... and on AVD i have an exception something like resources not closed. So i will paste the adapter :

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>{
private static final String TAG = "MyAdapter";
private List<Item> listItem = null;

public MyAdapter(List<Item> listItem) {
    this.listItem = listItem;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    // Log.d(logTag, "view group " + parent);
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row, parent, false);
    return new MyViewHolder(v);
}

@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
    //Log.d(logTag, " bind " + position + " holder " + holder);
    final Item item = listItem.get(position);

    holder.position = position;
    //new LoadBitmap(position, holder).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, item.getId());
}

private class LoadBitmap extends AsyncTask<String, Void, Bitmap> {
    private MyViewHolder holder = null;
    private int position = 0;

    public LoadBitmap(int position, MyViewHolder holder) {
        this.holder = holder;
        this.position = position;
    }

    @Override
    protected Bitmap doInBackground(String... params) {
        File file = new File("/data/data/myapp/files", params[0]);
        FileInputStream fis = null;
        Bitmap bitmap = null;
        try {
            fis = new FileInputStream(file);
            bitmap = BitmapFactory.decodeStream(fis);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return bitmap;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (bitmap != null && holder.position == position) {
            holder.imageView.setImageBitmap(bitmap);
        }
    }
}


@Override
public int getItemCount() {
    return listItem.size();
}


public class MyViewHolder extends RecyclerView.ViewHolder {
    private ImageView imageView = null;

    int position = 0;

    public MyViewHolder(View itemView) {
        super(itemView);
        imageView = (ImageView) itemView.findViewById(R.id.imageView_item);
    }
}

}

I try too with UI Thread :

 holder.imageView.post(new Runnable() {
        @Override
        public void run() {
            File file = new File("/data/data/myapp/files", item.getId());
            FileInputStream fis = null;
            Bitmap bitmap = null;
            try {
                fis = new FileInputStream(file);
                bitmap = BitmapFactory.decodeStream(fis);
                holder.imageView.setImageBitmap(bitmap);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } finally {
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    });

I hope it's clear enough and sorry for my english. Thanx.

EDIT : This fix work perfect

@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
    Item item = listItem.get(position);

    holder.position = position;
    File file = new File("/data/data/myApp/files", item.getId());
    Picasso.with(holder.itemView.getContext()).load(file).resize(50,25).centerCrop().into(holder.imageView);
}
2

There are 2 best solutions below

5
On BEST ANSWER

Why not use Picasso or a library for that?

It's as easy as:

Uri uri = Uri.fromFile(yourFilePath);

Picasso.with(activity).load(uri)
            .resize(100, 100).centerCrop().into(viewHolder.imageView);

Or load the image in the onCreateViewHolder method

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    // Log.d(logTag, "view group " + parent);
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row, parent, false);
ImageView imgView = v.findViewById(R.id.yourId);
final int position = holder.getAdapterPosition(); //get your item with position 

new LoadBitmap( ...)
    return new MyViewHolder(v);
}

and do not forget to recycle your bitmap with bitmap.recycle()

But never start async tasks in onBindViewHolder.

EDIT: You can get the item with: final int position = holder.getAdapterPosition();

4
On

Don't ever use AsyncTasks for loading any kind data into RecyclerView or ListView.

Check out Picasso and use this construction

File file = new File(path);
Picasso.with(context).load(file).placeholder(placeholderResId).into(imageView);

to load from disk.