FATAL EXCEPTION error when loading image gallery using Asynctask

Asked

Viewed 115 times

1

I’m creating a small gallery and I’m having trouble uploading the images using Asynctask

class Adapter:

public class AdapterGaleriaFragment extends BaseAdapter {
Context ctx;
List<ImageDataModel> lista;
public AdapterGaleriaFragment(Context ctx, List <ImageDataModel> lista){
    this.ctx = ctx;
    this.lista = lista;
}

@Override
public int getCount() {
    return lista != null ? lista.size():0;
}

@Override
public Object getItem(int position) {
    return lista.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View view;
    ViewHolder holder;
    if (convertView == null) {
        view = LayoutInflater.from(ctx).inflate(R.layout.layout_adapter, parent, false);
        holder = new ViewHolder(view);
        view.setTag(holder);
    } else {
        view = convertView;
        holder = (ViewHolder)view.getTag();
    }
    ImageDataModel img = lista.get(position);
    loadBitmap(img.getImagePath(),holder.imgView);
    return view;
}
public void loadBitmap(String path, ImageView view) {
    Task task = new Task(view);
    task.execute(path);
}
}

class of Asynctask:

public class Task extends AsyncTask<String, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
public Task(ImageView imageView) {
    // Use a WeakReference to ensure the ImageView can be garbage collected
    imageViewReference = new WeakReference<ImageView>(imageView);
}

@Override
protected Bitmap doInBackground(String... params) {
    File file = new File(params[0]);
    Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());

    return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap){
    if (imageViewReference != null && bitmap != null) {
        final ImageView imageView = imageViewReference.get();
        if (imageView != null) {
            imageView.setImageBitmap(bitmap);
        }
    }
}
}

Log:

E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #5
Process: com.example.alex_sama.galeriramesmo, PID: 25570
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:304)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.OutOfMemoryError: Failed to allocate a 3686412 byte allocation with 2714916 free bytes and 2MB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
at android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:635)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:611)
at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:391)
at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:417)
at com.example.alex_sama.galeriramesmo.Task.doInBackground(Task.java:29)
at com.example.alex_sama.galeriramesmo.Task.doInBackground(Task.java:19)
at android.os.AsyncTask$2.call(AsyncTask.java:292)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
at java.lang.Thread.run(Thread.java:818)
  • that wouldn’t be it? Caused by: java.lang.OutOfMemoryError: Failed to allocate a 3686412 byte allocation with 2714916 free bytes and 2MB until OOM at

  • yes, how can I solve?

2 answers

2


Its implementation will fatally fail on large images and/or many images. You need to use a list component that implements recycling of the items displayed/not shown on the screen, as well as make your life easier with an image loading library.

The simple act of loading an image into a ImageView is infinitely more complex on android than one imagines. You need to worry about screen rotations (orientation changes will destroy the context in which you are loading the image), background reading is not simple to implement correctly, and it is necessary to reduce the size of the uploaded image to a size that fits in the memory and is compatible with the ImageView destination, etc..

Solve your life using or Glide, Google’s own, or Picasso’s, square. I suggest Glide.

Also change your project to use RecyclerView, that will implement recycling of their objects ViewHolder, wasting memory only for the images displayed on the screen.

A good tutorial, though in English: http://www.androidhive.info/2016/04/android-glide-image-library-building-image-gallery-app/

To learn more about Glide: https://github.com/bumptech/glide (scroll down as the library’s "readme" is below the code)

To get to know the Picasso library, which is as good an alternative as: http://square.github.io/picasso/ (worth reading to see how it is more complex than it seems to display pictures on android)


This being said, just modifying your code to use Glide or Picasso will most likely avoid the problem of missing memory.

Add Glide to your Gradle project:

dependencies {
  compile 'com.github.bumptech.glide:glide:3.7.0'
  compile 'com.android.support:support-v4:19.1.0'
}

Modify the image load in your code to:

@Override public View getView(int position, View convertView, ViewGroup parent) {
    View view;
    ViewHolder holder;
    if (convertView == null) {
        view = LayoutInflater.from(ctx).inflate(R.layout.layout_adapter, parent, false);
        holder = new ViewHolder(view);
        view.setTag(holder);
    } else {
        view = convertView;
        holder = (ViewHolder)view.getTag();
    }
    ImageDataModel img = lista.get(position);

    // não precisa se preocupar, pois o Glide já faz em background
    Glide
        .with(holder.imgView.getContext())
        .load(img.getImagePath())
        .centerCrop()
        .into(holder.imgView);

    return view; 
}
  • 1

    thank you, I will read the tutorial and test the code above. This Glide it is similar to Picasso that implements automatic cache?

  • Yes, as I said are equivalent, but Glide is made by Google people.

0

You can change the size of your android’s heap memory using the following command in your manifest.xml android:largeHeap="true"

  • 1

    That won’t consume much of the memory?

  • only what is necessary to fit your object

  • still didn’t work, continues with the same error as before

Browser other questions tagged

You are not signed in. Login or sign up in order to post.