Search code examples
androidandroid-asynctaskimage-gallerystaggered-gridview

AsyncTask OutOfMemoryError: bitmap size exceeds VM budget


have to load all SDcard images into staggered view..when i set count 100 it shows that images in staggered view but for many no of images (eg.700/800) I am used AsyncTask but it shows doinbackground error please help me to out this.

import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity
 {
  private StaggeredGridLayoutManager staggeredGridLayoutManager;
  MyAdapter myAdapter;
  List<ItemData> grid_view_item = new ArrayList<>();
   @Override
   protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
    recyclerView.setHasFixedSize(true);

 staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
 recyclerView.setLayoutManager(staggeredGridLayoutManager);
            //call the LoadImage
            new LoadImage().execute();
            myAdapter = new MyAdapter(MainActivity.this, grid_view_item);
            recyclerView.setAdapter(myAdapter);

       }

this is AsncTask class.

class LoadImage extends AsyncTask<Void,Void,Void>
        {
            private int count;
            private Bitmap[] thumbnails;
            private boolean[] thumbnailsselection;
            private String[] arrPath;

            @Override
            protected Void doInBackground(Void... params)
            {
                //load gallery iamges
                final String[] columns = {MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID};
                final String orderBy = MediaStore.Images.Media._ID;
                Cursor imagecursor = managedQuery(
                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null,
                        null, orderBy);
                int image_column_index = imagecursor.getColumnIndex(MediaStore.Images.Media._ID);
                Log.e("COUNT ", "" + image_column_index);
                this.count = imagecursor.getCount();
                Log.e("COUNT ", "" + count);
                this.thumbnails = new Bitmap[this.count];
                Log.e("COUNT ", "" + thumbnails);
                this.arrPath = new String[this.count];
                Log.e("COUNT ", "" + arrPath);
                this.thumbnailsselection = new boolean[this.count];
                Log.e("COUNT ", "" + thumbnailsselection);
                for (int i = 0; i < this.count; i++) {
                    imagecursor.moveToPosition(i);
                    int id = imagecursor.getInt(image_column_index);
                    int dataColumnIndex = imagecursor.getColumnIndex(MediaStore.Images.Media.DATA);
                    thumbnails[i] = MediaStore.Images.Thumbnails.getThumbnail(
                            getApplicationContext().getContentResolver(), id,
                            MediaStore.Images.Thumbnails.MINI_KIND, null);
                    arrPath[i] = imagecursor.getString(dataColumnIndex);
                    grid_view_item.add(new ItemData(thumbnails[i]));
                }

                return null;
            }
        }

this is Adapter class.

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>
{
            private List<ItemData> itemsData;
            private Context context;

    public MyAdapter(Context context, List<ItemData> itemsData)
    {
                this.itemsData = itemsData;
                this.context = context;
    }

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

            @Override
            public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                           int viewType) {
                // create a new view
                View itemLayoutView = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.staggered_view_image, null);

                // create ViewHolder

                ViewHolder viewHolder = new ViewHolder(itemLayoutView);
                return viewHolder;
            }

            // Replace the contents of a view (invoked by the layout manager)
            @Override
            public void onBindViewHolder(ViewHolder viewHolder, final int position) {

                viewHolder.img.setImageBitmap(itemsData.get(position).getImage());

            }


            // inner class to hold a reference to each item of RecyclerView
            public class ViewHolder extends RecyclerView.ViewHolder {
                public ImageView img;

                public ViewHolder(View itemLayoutView) {
                    super(itemLayoutView);
                    img = (ImageView) itemLayoutView.findViewById(R.id.gallery_photo);
                }
            }
}
}

LogCat.

1
12-30 08:49:50.329 2902-2935/com.staggeredgridview E/COUNT: 775
12-30 08:49:50.329 2902-2935/com.staggeredgridview E/COUNT: [Landroid.graphics.Bitmap;@40513478
12-30 08:49:50.329 2902-2935/com.staggeredgridview E/COUNT: [Ljava.lang.String;@405187f8
12-30 08:49:50.329 2902-2935/com.staggeredgridview E/COUNT: [Z@4053aa88
12-30 08:50:24.319 2902-2935/com.staggeredgridview E/dalvikvm-heap: 153600-byte external allocation too large for this process.
12-30 08:50:24.369 2902-2935/com.staggeredgridview E/GraphicsJNI: VM won't let us allocate 153600 bytes
12-30 08:50:24.369 2902-2935/com.staggeredgridview D/skia: libjpeg error 105 <  Ss=%d, Se=%d, Ah=%d, Al=%d> from allocPixelRef [320 240]
12-30 08:50:24.369 2902-2935/com.staggeredgridview D/skia: --- decoder->decode returned false
12-30 08:50:24.369 2902-2935/com.staggeredgridview E/MediaStore: failed to allocate memory for thumbnail content://media/external/images/thumbnails/615; java.lang.OutOfMemoryError: bitmap size exceeds VM budget
12-30 08:50:24.539 2902-2935/com.staggeredgridview E/dalvikvm-heap: 153600-byte external allocation too large for this process.
12-30 08:50:24.589 2902-2935/com.staggeredgridview E/GraphicsJNI: VM won't let us allocate 153600 bytes
12-30 08:50:24.589 2902-2935/com.staggeredgridview D/skia: libjpeg error 105 <  Ss=%d, Se=%d, Ah=%d, Al=%d> from allocPixelRef [320 240]
12-30 08:50:24.589 2902-2935/com.staggeredgridview D/skia: --- decoder->decode returned false
12-30 08:50:24.589 2902-2935/com.staggeredgridview E/MediaStore: failed to allocate memory for thumbnail content://media/external/images/thumbnails/615; java.lang.OutOfMemoryError: bitmap size exceeds VM budget
12-30 08:50:24.599 2902-2935/com.staggeredgridview V/MediaStore: Create the thumbnail in memory: origId=639, kind=1, isVideo=false
12-30 08:50:24.749 2902-2935/com.staggeredgridview E/dalvikvm-heap: 307200-byte external allocation too large for this process.
12-30 08:50:24.799 2902-2935/com.staggeredgridview E/GraphicsJNI: VM won't let us allocate 307200 bytes
12-30 08:50:24.799 2902-2935/com.staggeredgridview D/skia: libjpeg error 105 <  Ss=%d, Se=%d, Ah=%d, Al=%d> from allocPixelRef [320 240]
12-30 08:50:24.799 2902-2935/com.staggeredgridview D/skia: --- decoder->decode returned false
12-30 08:50:24.809 2902-2935/com.staggeredgridview W/dalvikvm: threadid=9: thread exiting with uncaught exception (group=0x40018578)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime: java.lang.RuntimeException: An error occured while executing doInBackground()
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at android.os.AsyncTask$3.done(AsyncTask.java:200)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at java.util.concurrent.FutureTask.run(FutureTask.java:138)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at java.lang.Thread.run(Thread.java:1019)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:  Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at android.graphics.BitmapFactory.nativeDecodeByteArray(Native Method)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at android.graphics.BitmapFactory.decodeByteArray(BitmapFactory.java:508)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at android.media.ThumbnailUtils.createThumbnailFromEXIF(ThumbnailUtils.java:489)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at android.media.ThumbnailUtils.createImageThumbnail(ThumbnailUtils.java:102)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at android.provider.MediaStore$InternalThumbnails.getThumbnail(MediaStore.java:455)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at android.provider.MediaStore$Images$Thumbnails.getThumbnail(MediaStore.java:791)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at com.staggeredgridview.MainActivity$LoadImage.doInBackground(MainActivity.java:73)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at com.staggeredgridview.MainActivity$LoadImage.doInBackground(MainActivity.java:42)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at android.os.AsyncTask$2.call(AsyncTask.java:185)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at java.util.concurrent.FutureTask.run(FutureTask.java:138) 
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088) 
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581) 
12-30 08:50:24.829 2902-2935/com.staggeredgridview E/AndroidRuntime:     at java.lang.Thread.run(Thread.java:1019) 

Solution

  • for solve this issue I added android:largeHeap="true" in Android Manifest file in Application tag..it solve the problem but application require more heap memory..might it affect the other application and second thing it takes more time to load the images

    this is the Android Manifest file

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.staggeredgridview" >
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:largeHeap="true"
            android:theme="@style/AppTheme" >
            <activity
                android:name=".MainActivity"
                android:label="@string/app_name"
                android:theme="@style/AppTheme.NoActionBar" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    

    this is the final code ..its works fine..

    import android.content.Context;
    import android.database.Cursor;
    import android.graphics.Bitmap;
    import android.os.Bundle;
    import android.provider.MediaStore;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.RecyclerView;
    import android.support.v7.widget.StaggeredGridLayoutManager;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ImageView;
    import java.util.ArrayList;
    import java.util.List;
    
    
    public class MainActivity extends AppCompatActivity {
        private int count;
        private Bitmap[] thumbnails;
        private boolean[] thumbnailsselection;
        private String[] arrPath;
        private StaggeredGridLayoutManager staggeredGridLayoutManager;
        MyAdapter myAdapter;
        List<ItemData> grid_view_item = new ArrayList<>();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
            recyclerView.setHasFixedSize(true);
    
    
            staggeredGridLayoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
            recyclerView.setLayoutManager(staggeredGridLayoutManager);
            myAdapter = new MyAdapter(MainActivity.this, grid_view_item);
            recyclerView.setAdapter(myAdapter);
    
    
            //load gallery iamges
            final String[] columns = {MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID};
            final String orderBy = MediaStore.Images.Media._ID;
            Cursor imagecursor = managedQuery(
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null,
                    null, orderBy);
            int image_column_index = imagecursor.getColumnIndex(MediaStore.Images.Media._ID);
            Log.e("COUNT ", "" + image_column_index);
            this.count = imagecursor.getCount();
            Log.e("COUNT ", "" + count);
            this.thumbnails = new Bitmap[this.count];
            Log.e("COUNT ", "" + thumbnails);
            this.arrPath = new String[this.count];
            Log.e("COUNT ", "" + arrPath);
            this.thumbnailsselection = new boolean[this.count];
            Log.e("COUNT ", "" + thumbnailsselection);
            for (int i = 0; i < this.count; i++) {
                imagecursor.moveToPosition(i);
                int id = imagecursor.getInt(image_column_index);
                int dataColumnIndex = imagecursor.getColumnIndex(MediaStore.Images.Media.DATA);
                thumbnails[i] = MediaStore.Images.Thumbnails.getThumbnail(
                        getApplicationContext().getContentResolver(), id,
                        MediaStore.Images.Thumbnails.MINI_KIND, null);
                arrPath[i] = imagecursor.getString(dataColumnIndex);
                grid_view_item.add(new ItemData(thumbnails[i]));
            }
        }
    
        public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
            private List<ItemData> itemsData;
            private Context context;
    
            public MyAdapter(Context context, List<ItemData> itemsData) {
                this.itemsData = itemsData;
                this.context = context;
            }
    
            @Override
            public int getItemCount() {
                return this.itemsData.size();
            }
    
            @Override
            public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                           int viewType) {
                // create a new view
                View itemLayoutView = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.staggered_view_image, null);
    
                // create ViewHolder
    
                ViewHolder viewHolder = new ViewHolder(itemLayoutView);
                return viewHolder;
            }
    
            // Replace the contents of a view (invoked by the layout manager)
            @Override
            public void onBindViewHolder(ViewHolder viewHolder, final int position) {
    
                viewHolder.img.setImageBitmap(itemsData.get(position).getImage());
    
            }
    
    
            // inner class to hold a reference to each item of RecyclerView
            public class ViewHolder extends RecyclerView.ViewHolder {
                public ImageView img;
    
                public ViewHolder(View itemLayoutView) {
                    super(itemLayoutView);
                    img = (ImageView) itemLayoutView.findViewById(R.id.gallery_photo);
                }
            }
        }
    }