1

I have been searching for a solution to my problem. The most common recommendations are to add android:hardwareAccelerated="false" and android:largeHeap="true" to the application tag in the manifest, however I still get the following error:

E/UncaughtException: java.lang.OutOfMemoryError: Failed to allocate a 56272 byte allocation with 19848 free bytes and 19KB until OOM
    at java.lang.StringBuilder.toString(StringBuilder.java:408)
    at org.chromium.content_public.browser.LoadUrlParams.buildDataUri(LoadUrlParams.java:113)
    at org.chromium.content_public.browser.LoadUrlParams.createLoadDataParamsWithBaseUrl(LoadUrlParams.java:164)
    at org.chromium.android_webview.AwContents.loadDataWithBaseURL(AwContents.java:1523)
    at com.android.webview.chromium.WebViewChromium.loadDataWithBaseURL(WebViewChromium.java:609)
    at android.webkit.WebView.loadDataWithBaseURL(WebView.java:1015)
    at com.google.android.gms.internal.zzakn.loadDataWithBaseURL(Unknown Source)
    at com.google.android.gms.internal.zzakm.loadDataWithBaseURL(Unknown Source)
    at com.google.android.gms.internal.zzxy.zzgo(Unknown Source)
    at com.google.android.gms.internal.zzxq.zzgp(Unknown Source)
    at com.google.android.gms.internal.zzxw.zza(Unknown Source)
    at com.google.android.gms.ads.internal.zzl.run(Unknown Source)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6119)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
                                                                             
                                                                             
                                                                             --------- beginning of crash
E/AndroidRuntime: FATAL EXCEPTION: main
     java.lang.OutOfMemoryError: Failed to allocate a 56272 byte allocation with 19848 free bytes and 19KB until OOM
     at java.lang.StringBuilder.toString(StringBuilder.java:408)
     at org.chromium.content_public.browser.LoadUrlParams.buildDataUri(LoadUrlParams.java:113)
     at org.chromium.content_public.browser.LoadUrlParams.createLoadDataParamsWithBaseUrl(LoadUrlParams.java:164)
     at org.chromium.android_webview.AwContents.loadDataWithBaseURL(AwContents.java:1523)
     at com.android.webview.chromium.WebViewChromium.loadDataWithBaseURL(WebViewChromium.java:609)
     at android.webkit.WebView.loadDataWithBaseURL(WebView.java:1015)
     at com.google.android.gms.internal.zzakn.loadDataWithBaseURL(Unknown Source)
     at com.google.android.gms.internal.zzakm.loadDataWithBaseURL(Unknown Source)
     at com.google.android.gms.internal.zzxy.zzgo(Unknown Source)
     at com.google.android.gms.internal.zzxq.zzgp(Unknown Source)
     at com.google.android.gms.internal.zzxw.zza(Unknown Source)
     at com.google.android.gms.ads.internal.zzl.run(Unknown Source)
     at android.os.Handler.handleCallback(Handler.java:751)
     at android.os.Handler.dispatchMessage(Handler.java:95)
     at android.os.Looper.loop(Looper.java:154)
     at android.app.ActivityThread.main(ActivityThread.java:6119)
     at java.lang.reflect.Method.invoke(Native Method)
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

So here are my activities that might have part in this, unfortunately I am lost and don't know what to adjust to resolve this problem.

Gridviewadapter

import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class GridViewAdapter extends ArrayAdapter<ImageItem> {

    private Context context;
    private int layoutResourceId;
    private ArrayList<ImageItem> data = new ArrayList<ImageItem>();

    public GridViewAdapter(Context context, int layoutResourceId, ArrayList<ImageItem> data) {
        super(context, layoutResourceId, data);
        this.layoutResourceId = layoutResourceId;
        this.context = context;
        this.data = data;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = convertView;
        ViewHolder holder;

        if (row == null) {
            LayoutInflater inflater = ((Activity) context).getLayoutInflater();
            row = inflater.inflate(layoutResourceId, parent, false);
            holder = new ViewHolder();
            holder.imageTitle = (TextView) row.findViewById(R.id.text);
            holder.image = (ImageView) row.findViewById(R.id.image);
            row.setTag(holder);
        } else {
            holder = (ViewHolder) row.getTag();
        }


        ImageItem item = data.get(position);
        holder.imageTitle.setText(item.getTitle());
        holder.image.setImageBitmap(item.getImage());
        return row;
    }

    static class ViewHolder {
        TextView imageTitle;
        ImageView image;
    }
}

Imageitem

import android.graphics.Bitmap;

public class ImageItem {

    private int arrayIndex;
    private Bitmap image;
    private String title;

    public ImageItem(int arrayIndex, Bitmap image, String title) {
        super();
        this.arrayIndex = arrayIndex;
        this.image = image;
        this.title = title;
    }

    public Bitmap getImage() {
        return image;
    }

    public void setImage(Bitmap image) {
        this.image = image;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getArrayIndex() {
        return arrayIndex;
    }

    public void setArrayIndex(int arrayIndex) {
        this.arrayIndex = arrayIndex;
    }
}

Mainactivity

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;

import java.util.ArrayList;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import com.google.firebase.iid.FirebaseInstanceId;

public class MainActivity extends ActionBarActivity {

    private GridView gridView;
    private GridViewAdapter gridAdapter;
    private Toolbar toolbar;

    private static final String TAG = MainActivity.class.getSimpleName();
    private static final int STORAGE_PERMISSION_REQUEST = 2001;

    AdRequest adRequest;
    AdView mAdView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //loading ads
        loadAds();

        toolbar = (Toolbar) findViewById(R.id.app_bar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
        getSupportActionBar().setLogo(R.drawable.home_icon);
        getSupportActionBar().setDisplayUseLogoEnabled(true);

        gridView = (GridView) findViewById(R.id.gridView);
        gridAdapter = new GridViewAdapter(this, R.layout.grid_item_layout, getData());
        gridView.setAdapter(gridAdapter);

        isStoragePermissionGranted();


        gridView.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
                ImageItem item = (ImageItem) parent.getItemAtPosition(position);

                //Create intent
                Intent intent = new Intent(MainActivity.this, DetailsActivity.class);
                intent.putExtra("title", item.getTitle());
                intent.putExtra("index", item.getArrayIndex());

                //Start details activity
                startActivity(intent);
            }
        });
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu_main, menu);
        return true;
    }

    public boolean onOptionsItemSelected(MenuItem item) {

        int id = item.getItemId();

        if (id==R.id.navigate) {
            startActivity(new Intent(this, SettingsActivity.class));
        }
        return super.onOptionsItemSelected(item);
    }

    private void loadAds() {
        mAdView = (AdView) findViewById(R.id.adView);
        adRequest = new AdRequest.Builder().build();
        mAdView.loadAd(adRequest);
    }

    public boolean isStoragePermissionGranted() {
        if (Build.VERSION.SDK_INT >= 23) {
            if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    == PackageManager.PERMISSION_GRANTED) {
                Log.v(TAG, "Permission is granted");
                return true;
            } else {
                Log.v(TAG, "Permission is revoked");
                ActivityCompat.requestPermissions(
                        this,
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                        1);
                return false;
            }
        } else { //permission is automatically granted on sdk<23 upon installation
            Log.v(TAG, "Permission is granted");
            return true;
        }
    }

    @Override
    public void onRequestPermissionsResult(
            int requestCode,
            String[] permissions,
            int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == STORAGE_PERMISSION_REQUEST) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Log.d(TAG, "Permission: " + permissions[0] + "was " + grantResults[0]);
                // resume tasks needing this permission
            } else {
                // TODO: You should not allow the user to continue!
            }
        }
    }

    /**
     * Prepare some dummy data for gridview
     */
    private ArrayList<ImageItem> getData() {
        final ArrayList<ImageItem> imageItems = new ArrayList<>();
        TypedArray imgs = getResources().obtainTypedArray(R.array.image_ids);
        for (int i = 0; i < imgs.length(); i++) {
            Log.d(TAG, "Image ID: " + String.valueOf(i));
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), imgs.getResourceId(i, -1));
            imageItems.add(new ImageItem(i, bitmap, "Image#" + i));
        }
        return imageItems;
    }
}

Detailsactivity

import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.StringTokenizer;

import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import com.google.android.gms.ads.InterstitialAd;

public class DetailsActivity extends ActionBarActivity {

    Button btnShare;
    private InterstitialAd interstitialAd;
    boolean exitApp=false;
    private Toolbar toolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.details_activity);

        toolbar = (Toolbar) findViewById(R.id.app_bar);
        TextView titleTextView = (TextView) findViewById(R.id.title);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
        getSupportActionBar().setLogo(R.drawable.home_icon);
        getSupportActionBar().setDisplayUseLogoEnabled(true);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        String title = getIntent().getStringExtra("title");
        int index = getIntent().getIntExtra("index", -1);

        // Worked on by Douglas

        if(title!=null){
            titleTextView.setText(title);
        }else{
            titleTextView.setText("No title");
        }

        Bitmap bitmap = getBitmap(0);
        try{
            bitmap = getBitmap(index);
        }catch (Exception e){
            Log.d("getBitmap Broke: ", e.toString());
        }

        // Till here


        ImageView imageView = (ImageView) findViewById(R.id.image);
        imageView.setImageBitmap(bitmap);

        String imgBitmapPath= MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, title ,null);
        final Uri imgBitmapUri=Uri.parse(imgBitmapPath);

        btnShare=(Button)findViewById(R.id.button);
        btnShare.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                // Get the URI
                // Replace R.drawable.image with the name of the image you want to display
                //Uri uri = Uri.parse("android.resource://" + BuildConfig.APPLICATION_ID + "/" + R.drawable.image_1);

                // Now that you have the URI you can create your intent
                Intent share = new Intent(Intent.ACTION_SEND);
                share.putExtra(Intent.EXTRA_STREAM, imgBitmapUri);
                share.setType("image/*");
                share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

                // Create a chooser to share your emoji
                try {
                    DetailsActivity.this.startActivity(Intent.createChooser(share, "Share Emoji"));
                } catch (ActivityNotFoundException e) {
                    // Whatsapp might not be installed
                }

            }
        });

        launchInter();
        loadInterstitial();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onSupportNavigateUp() {
        onBackPressed();
        return true;
    }

    public boolean onOptionsItemSelected(MenuItem item) {

        int id = item.getItemId();

        if (id==R.id.navigate) {
            startActivity(new Intent(this, SettingsActivity.class));
        }
        return super.onOptionsItemSelected(item);
    }

    /**
     * Prepare some dummy data for gridview
     */
    private Bitmap getBitmap(int index) {
        final ArrayList<ImageItem> imageItems = new ArrayList<>();
        TypedArray imgs = getResources().obtainTypedArray(R.array.image_ids);
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), imgs.getResourceId(index, -1));
        return bitmap;
    }

    private void launchInter() {
        interstitialAd = new InterstitialAd(this);
        interstitialAd.setAdUnitId("ca-app-pub-7350914179187171/1372559648");

        interstitialAd.setAdListener(new AdListener() {
            @Override
            public void onAdLoaded() {
                showAdInter();
            }

            @Override
            public void onAdFailedToLoad(int errorCode) {
                String message=String.format("onAdFailedToLoad (%s)",getErrorReason(errorCode));
            }

            @Override
            public void onAdClosed() {
                if (exitApp)
                    finish();
            }
        });
    }

    private void showAdInter() {
        if (interstitialAd.isLoaded()) {
            interstitialAd.show();
        }
        else
        {
            Log.d("","Interstitial ad was not ready to be shown");
        }
    }

    public void loadInterstitial() {
        AdRequest adRequest = new AdRequest.Builder()
                .addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
                .addTestDevice("Insert_your_hashed_device_id_here")
                .build();

        interstitialAd.loadAd(adRequest);
    }

    private String getErrorReason(int errorCode) {
        String errorReason="";
        switch(errorCode) {
            case AdRequest.ERROR_CODE_INTERNAL_ERROR:
                errorReason="Internal Error";
                break;
            case AdRequest.ERROR_CODE_INVALID_REQUEST:
                errorReason="Invalid Request";
                break;
            case AdRequest.ERROR_CODE_NETWORK_ERROR:
                errorReason="Network Error";
                break;
            case AdRequest.ERROR_CODE_NO_FILL:
                errorReason="No Fill";
                break;
        }
        return errorReason;
    }
}

I would really appreciate any help with this!

7
  • 1
    the error is because of getData method which is storing each bitmap in memory and app crashes because of out of memory Commented Jul 12, 2017 at 12:19
  • better option is not to link bitmap to ImageItem class object instead use URI of image path and then load this image in adapter using any image loader library such as Picasso Commented Jul 12, 2017 at 12:20
  • thanks ELITE, do you have any code adjustments you recommend to fix this issue? i was quite proud of myself to get to this step, now I just need this last bug resolved :D Commented Jul 12, 2017 at 12:21
  • You can store bitmap with compress level because most of the time when you are trying to deal with bitmap you face OOM Commented Jul 12, 2017 at 12:28
  • Hi @AjayPandya could you show me how to change it in the code? I would really appreciate it Commented Jul 12, 2017 at 12:31

1 Answer 1

1

My suggestion is to modify your code to remove Bitmap instance from ImageItem class like below

public class ImageItem {

    private int arrayIndex;
    private int imageResource;
    private String title;

    public ImageItem(int arrayIndex, int imageResource, String title) {
        super();
        this.arrayIndex = arrayIndex;
        this.imageResource = imageResource;
        this.title = title;
    }

    public int getImageResource() {
        return imageResource;
    }

    public void setImageResource(int imageResource) {
        this.imageResource = imageResource;
    }

    // rest methods should be same

}

In GridViewAdapter class load image from resource id like below

public class GridViewAdapter extends ArrayAdapter<ImageItem> {

    // your old logic here

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        // your old logic here

        // holder.image.setImageBitmap(item.getImage());
        Picasso.with(context).load(item.getImageResource()).into(holder.image);
    }

    // your old logic here

}

Modify getData method of your MainActivity.java

private ArrayList<ImageItem> getData() {
    final ArrayList<ImageItem> imageItems = new ArrayList<>();
    TypedArray imgs = getResources().obtainTypedArray(R.array.image_ids);
    for (int i = 0; i < imgs.length(); i++) {
        Log.d(TAG, "Image ID: " + String.valueOf(i));
        // no need to load image here
        // Bitmap bitmap = BitmapFactory.decodeResource(getResources(), imgs.getResourceId(i, -1));
        imageItems.add(new ImageItem(i, imgs.getResourceId(i, -1), "Image#" + i));
    }
    return imageItems;
}

And last one to add compile dependency in app's build.gradle like below

dependencies {
    ...
    compile 'com.squareup.picasso:picasso:2.5.0'
    ...
}

and done.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.