Search code examples
androidout-of-memoryandroid-imageandroid-bitmap

Passing around images with images' Uri still causes Out of Memory Exception


Goal

To pass around images (it fills a quarter of the screen, so it's quite big) for the activities/fragments.

What I tried to do

Instead of passing around BitMaps, I was researched/ was advised to pass the images Uri. The problem is, whenever I click the "Preview Button", which will launch the HomeDescActivity, an Out of Memory Exception will occur.

GalleryFragment

public class GalleryFragment extends Fragment {
    private static final int SELECT_PICTURE = 1;
    public static final String IMAGE_URI_ARRAY_LIST = "IMAGE_URI_ARRAY_LIST";
    private ArrayList<String> mImageUriArrayList = new ArrayList<>();
    RecyclerView recyclerView;
    GalleryAdapter galleryAdapter;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.profile_tab_become_a_host_set_the_scene_gallery_fragment, container, false);
        return view;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        //convert string uri to uri object
        Uri imageUri = Uri.parse(getArguments().getString(PhotoFragment.IMAGE_URI));


        recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
        galleryAdapter = new GalleryAdapter();
        galleryAdapter.addImage(imageUri);
        mImageUriArrayList.add(imageUri.toString());


        GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 2);
        recyclerView.setLayoutManager(gridLayoutManager);

        view.findViewById(R.id.ivAddPhoto).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                //Launch Gallery
                intent.setType("image/*");
                intent.setAction(Intent.ACTION_GET_CONTENT);
                startActivityForResult(Intent.createChooser(intent,
                        "Select Picture"), SELECT_PICTURE);
            }
        });

        view.findViewById(R.id.bPreview).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getContext(), HomeDescActivity.class);
                intent.putStringArrayListExtra(IMAGE_URI_ARRAY_LIST, mImageUriArrayList);
                startActivity(intent);
            }
        });
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            if (requestCode == SELECT_PICTURE) {
                //get selected image from gallery
                Uri imageUri = data.getData();
                galleryAdapter.addImage(imageUri);
                mImageUriArrayList.add(imageUri.toString());
                //refresh adapter
                recyclerView.setAdapter(galleryAdapter);

            }
        }
    }
}

HomeDescActivity (will cause Out of Memory Exception when launched)

public class HomeDescActivity extends AppCompatActivity {

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

        HomeDescFragment homeDescFragment = new HomeDescFragment();

//        Get images (uri) from GalleryFragment + PhotoFragment
        if(getIntent().getExtras().getStringArrayList(GalleryFragment.IMAGE_URI_ARRAY_LIST) != null){
                Bundle bundle = new Bundle();
            bundle.putStringArrayList(GalleryFragment.IMAGE_URI_ARRAY_LIST,
                    getIntent().getExtras().getStringArrayList(GalleryFragment.IMAGE_URI_ARRAY_LIST));

            homeDescFragment.setArguments(bundle);
            getSupportFragmentManager().beginTransaction().replace(R.id.rootLayout, homeDescFragment).commit();
        }

    }

}

HomeDescFragment

public class HomeDescFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.explore_tab_home_desc_fragment, container, false);

        return view;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        //convert strng uri to uri object
        if(getArguments().getStringArrayList(GalleryFragment.IMAGE_URI_ARRAY_LIST) != null){
            ArrayList<String> uriArrayList = getArguments().getStringArrayList(GalleryFragment.IMAGE_URI_ARRAY_LIST);
            ImageView ivHomePhoto = (ImageView) view.findViewById(R.id.ivHomePhoto);

            for(String uriString : uriArrayList){
               ivHomePhoto.setImageURI(Uri.parse(uriString));
            }
        }

    }
}

Update

Stack Trace

android.teamtreehouse.com.airbnb E/AndroidRuntime: FATAL EXCEPTION: main Process: googleplayservices.samples.android.teamtreehouse.com.airbnb, PID: 12434 java.lang.OutOfMemoryError: Failed to allocate a 207360012 byte allocation with 13482248 free bytes and 76MB until OOM at dalvik.system.VMRuntime.newNonMovableArray(Native Method) at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609) at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444) at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:988) at android.content.res.Resources.loadDrawableForCookie(Resources.java:2474) at android.content.res.Resources.loadDrawable(Resources.java:2381) at android.content.res.TypedArray.getDrawable(TypedArray.java:749) at android.widget.ImageView.(ImageView.java:146) at android.widget.ImageView.(ImageView.java:135) at android.support.v7.widget.AppCompatImageView.(AppCompatImageView.java:57) at android.support.v7.widget.AppCompatImageView.(AppCompatImageView.java:53) at android.support.v7.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:106) at android.support.v7.app.AppCompatDelegateImplV9.createView(AppCompatDelegateImplV9.java:1013) at android.support.v7.app.AppCompatDelegateImplV9.onCreateView(AppCompatDelegateImplV9.java:1072) at android.support.v4.view.LayoutInflaterCompatHC$FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:47) at android.view.LayoutInflater$FactoryMerger.onCreateView(LayoutInflater.java:180) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:725) at android.view.LayoutInflater.rInflate(LayoutInflater.java:806) at android.view.LayoutInflater.rInflate(LayoutInflater.java:809) at android.view.LayoutInflater.rInflate(LayoutInflater.java:809) at android.view.LayoutInflater.rInflate(LayoutInflater.java:809) at android.view.LayoutInflater.rInflate(LayoutInflater.java:809) at android.view.LayoutInflater.inflate(LayoutInflater.java:504) at android.view.LayoutInflater.inflate(LayoutInflater.java:414) at googleplayservices.samples.android.teamtreehouse.com.airbnb.ExploreTab.HomeDescFragment$override.onCreateView(HomeDescFragment.java:29) at googleplayservices.samples.android.teamtreehouse.com.airbnb.ExploreTab.HomeDescFragment$override.access$dispatch(HomeDescFragment.java) at googleplayservices.samples.android.teamtreehouse.com.airbnb.ExploreTab.HomeDescFragment.onCreateView(HomeDescFragment.java:0) at android.support.v4.app.Fragment.performCreateView(Fragment.java:2189) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1299) at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1528) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1595) at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:757) at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2355) at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2146) at android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.java:2098) at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2008) at android.support.v4.app.FragmentController.execPendingActions(FragmentController.java:388) at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:607) at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:178) at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1236) at android.app.Activity.performStart(Activity.java:6006) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2288) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387) at android.app.ActivityThread.access$800(ActivityThread.java:151) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303) at android.os.Handler.dispatchMessage(Handler.java:102)


Solution

  • Show us the stacktrace.

    Give us details about the image that is causing the exception, what's the width and height of it, how much memory does it take?

    I'm guessing you're trying to load a stupidly high resolution image like 6000x6000, which is causing the exception, but without more information, i can't say more.

    You should use a library like "Glide" to load the images for you, as it will scale the image down when shown to the user if it's too big. It's also extremely efficient at using the least amount of memory to handle images.