Android Troubleshooting: App Crash on multiple orientation change

More of a note to my future self when developing android than anything else, since this is quite a specific corner case, but who knows, maybe it helps someone else out there🙂

 

Problem

An app I wrote seemed to be crashing randomly when a user did a orientation change (i.e. changed from landscape to portrait mode, or vice versa). On closed look, this happened when the user changed the android handset orientation multiple times in quick succession, by turning the handset 90degrees and back about 4 times in a row. This caused the app to show the dreaded “Unfortunately the app has stopped responding”….

Cause

A null pointer exception of course…. Specifically, I was firing off an async task as soon as the activity launches, and such an async task was trying to access an android list layout. It turns out, on every orientation change, android recreates the activity. This means re-drawing the layout. So on every orientation change, an async task was launched. With the user changing the orientation multiple times in quick succession, the layout was still being drawn by the time the first async task completed it’s work and tried to display it’s results on screen, resulting in the null pointer exception

Solution

I surrounded the code in the async task which accesses the layout, and upon a null exception, cancel the async task using something like:

     catch (Exception e){
               cancel(true);
               if (isCancelled()){ 
                        return;
               }
     }


Make sure to cancel the async task before any server calls are done. It seems like a waste of computing resources and network bandwidth to have the async task complete the server call and then just cancelling it, only to have subsequent async calls go through the same process.

 

Note, my research led me across the “retained fragment”, which is explained oh-so-well here:

http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html

Basically:

 “retained” means that the fragment will not be destroyed on configuration changes. That is, the Fragment will beretained even if the configuration change causes the underlying Activity to be destroyed. [1]

And resulted in only the addition of the following to my fragment:

@Override
 public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);

          // Retain this fragment across configuration changes.
          setRetainInstance(true);
 }

 

However, that did not solve the issue for me, and I still required the isCancelled trick….

[1] http://stackoverflow.com/questions/11182180/understanding-fragments-setretaininstanceboolean