Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Android Implementing Designs for Android Customizing a ListView for the Inbox Adding a Swipe-to-Refresh Gesture

I'm getting a crash when I run Ribbit on a device after trying to take a picture. But not when picking from the gallery.

This happens in my app and in the downloaded project from treehouse. After taking a picture and returning to the MainActivity, I get crashes in either the FriendsListFragment or the InboxFragment. This happens in the 'done' callback of the ParseQuery during the call to setProgressBarIndeterminateVisibility(false); in both cases. If I comment out that line it crashes when trying to access the 'ListView' with 'getListView(). Basically anytime the view is accessed. I get an error of 'Content view not yet created.' I believe this is due to the activity or view being destroyed when the app hands off to the camera due to more memory pressure on my device than in the emulator. After coming back from the camera the async 'done' method from the destroyed activity/fragment is called and tries to access a reference which is no longer valid. The crash happens most of the time, but not always. How can I prevent this? Any help would be greatly appreciated.

2 Answers

Ok, so the problem was that on a device with limited memory, android was destroying mainActivity when switching to the camera, but not destroying the fragments associated with them. Then on coming back to the mainActivity from the camera app, the code in the done() method was running before the fragment was reattached to its recreated activity, and so I was getting a nullPointer error when trying to access the activity. The solution was just to wrap the code in the done() method with an if(isAdded()) to check if the fragment is attached to it's activity before trying to access it like so:

@Override
            public void done(List<ParseUser> friends, ParseException e) {
                if (isAdded()) {
                    getActivity().setProgressBarIndeterminateVisibility(false);

                    if (e == null) {

                        mFriends = friends;

                        String[] userNames = new String[mFriends.size()];
                        int i = 0;
                        for (ParseUser user : friends) {
                            userNames[i] = user.getUsername();
                            i++;
                        }
                        ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                                getListView().getContext(),
                                android.R.layout.simple_list_item_1,
                                userNames);
                        setListAdapter(adapter);
                    } else {
                        // something went wrong
                        AlertDialog.Builder builder = new AlertDialog.Builder(getListView().getContext())
                                .setMessage(e.getMessage())
                                .setTitle(getString(R.string.error_title))
                                .setPositiveButton(android.R.string.ok, null);
                        AlertDialog dialog = builder.create();
                        dialog.show();
                    }
                }
            }
        });

This works fine to keep things from crashing, but I feel like this is not ideal, as there is a wasted network call when returning to the mainActivity after taking a picture to send. Also to keep the app from crashing at the point of hitting the send button we have to save the mMediaUri of mainActivity in the onSaveInstanceState(Bundle bundle) method to keep from losing it when the activity is destroyed:

 @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        // Save the media uri in case we get destroyed in the background
        outState.putParcelable(KEY_MEDIA_URI, mMediaUri);
    }

And check for it on creating to bring it back:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Check if there is a saved state to restore
        if (savedInstanceState != null) {
            // Restore the media uri so we can pass it to RecipientsFragment
            mMediaUri = savedInstanceState.getParcelable(KEY_MEDIA_URI);
        }
// Rest of code omitted
}
Harry James
Harry James
14,780 Points

Hey James!

You can use the onViewCreated() method like this:

public void onViewCreated (View view, Bundle savedInstanceState) {

// Insert code

}

Simply move the relevant code into this method instead.

This should fix everything for you but, if you have any problems or any further questions, feel free to ask :)

You can read more about onViewCreated() on the Android Documentation here

Hi, thanks for responding. Unfortunately, I'm still getting crashes with the code moved to the onViewCreated method. I've now been able to reproduce the problem in the emulator by setting activities to be destroyed when they're no longer on screen in the developer options. Many times it crashes on getting back to the inbox or friends fragment or mainActivity. Sometimes it makes it to the recipientsActivity, but mMediaUri is null, and crashes then. I'm going to step back a few revisions and start from one that works and see if I can figure out what change exactly starts causing problems. I'll post back here when I find out more.

Thanks again

Harry James
Harry James
14,780 Points

Yes, that is correct. You can't destroy an activity unless it is running so, that is why you will be getting a crash when trying to do this.

Thanks for responding Harry. I apologize, I realize now that my original question was not very clear and I should have posted my code and should also have tried to be more concise describing the problem I was having.

Harry James
Harry James
14,780 Points

Not a problem!

I didn't mean for my last comment to be stern if that's how it came across by the way! I meant for it to be informative :)

Not at all, I appreciate your help :)