1

I have been receiving occasional Crashlytics reports of a Null Pointer Exception from calls to findViewById() within my onRestart() method in my Root Activity. It happens rarely, but often enough that I want to figure out why and fix it. Clearly, I can check for a null result and not proceed, but that feels like masking an underlying issue rather than fixing it.

I searched SO and have not found anything that matches my situation. I have called setContentView() in onCreate(), I have verified the view item exists in the xml (it is fixed and should always be present), and this code works the vast majority of the time (based on my best estimate, this happens in less than 1 session per 1000 sessions).

I have not run across any documentation that states I should do anything special with the activity in onRestart to access items in the view.

Relevant code snippet:

 public class RootActivity extends FragmentActivity 
 {
     // more member variables, but this is the relevant one
     private StickyListHeadersListView m_layerMenuListView;

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

         // do some required initializations (omitted for snippet)

         setContentView( R.layout.main );

         // do more initializations (also omitted for snippet)
         // initializations include accessing m_layerMenuListView
     }

     @Override
     protected void onRestart()
     {
         super.onRestart();

         // accessing this view occasionally returns null
         m_layerMenuListView = (StickyListHeadersListView) findViewById( R.id.layer_menu );

         // more code, but if the above returns null, it will generate the NPE
     }
 }

Here is a reduced snipped of main.xml showing the layer_menu is defined:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"
                android:id="@+id/main_layout">

   <!--Layer menu-->
   <se.emilsjolander.stickylistheaders.StickyListHeadersListView
         android:id="@+id/layer_menu"
         android:layout_height="wrap_content"
         android:layout_width="210dp"
         android:layout_alignParentBottom="true"
         android:layout_alignParentRight="true"
         android:layout_marginBottom="@dimen/layer_menu_bottom"
         android:layout_marginRight="2dp"
         android:layout_marginTop="@dimen/layer_menu_top"
         android:visibility="invisible"
         android:background="@color/darkGray_with_transparency"
         android:divider="@color/white"
         android:dividerHeight="1dp"
         android:listSelector="@color/header_background"
         android:choiceMode="multipleChoice"
         />
</RelativeLayout>

For completeness, the stack trace:

Fatal Exception: java.lang.RuntimeException: Unable to resume activity {crc.carsapp.la/crc.carsapp.activities.RootActivity}: java.lang.NullPointerException
       at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2790)
       at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2819)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1298)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:137)
       at android.app.ActivityThread.main(ActivityThread.java:5103)
       at java.lang.reflect.Method.invokeNative(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:525)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java)
       at dalvik.system.NativeStart.main(NativeStart.java)
Caused by java.lang.NullPointerException
       at crc.carsapp.activities.RootActivity.onRestart(RootActivity.java:473)
       at android.app.Instrumentation.callActivityOnRestart(Instrumentation.java:1181)
       at android.app.Activity.performRestart(Activity.java:5192)
       at android.app.Activity.performResume(Activity.java:5203)
       at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2780)
       at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2819)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1298)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:137)
       at android.app.ActivityThread.main(ActivityThread.java:5103)
       at java.lang.reflect.Method.invokeNative(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:525)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java)
       at dalvik.system.NativeStart.main(NativeStart.java)
Dan Nichols
  • 769
  • 1
  • 7
  • 19
  • can you elaborate which the the case? seems view is not initialized and you are trying to access the view id. – sumandas Aug 30 '16 at 19:25
  • I would expect if there was a problem with the view, it would throw a NPE on every restart. In essence, onRestart() works nearly all of the time, but for some reason can be null on occasion. The question is what could cause the view to be null when most of the time, it is not. – Dan Nichols Aug 30 '16 at 19:43

2 Answers2

0

Taking an attempt at it:

onRestart() is called only when Activity is onStop() state.

I can't better Android Documentation so referencing it here: Docs,

but idea is onCreate() called after onDestroy(). If you activity is not destroyed and it goes to background and due to excess demand of resource memory is released without making a proper call to onDestroy().

Some more reference to it: Ref

when you make a call to onRestart(), the view might not be created and go to onStart(). Try to have the setContentView() call in onStart() to see if there is a difference and you still get NPE.

sumandas
  • 555
  • 7
  • 20
  • Thanks for the attempt. But, if I read the documentation correctly, onStart() will be called after calling onRestart(), so if there is a problem with the content view, it will still be null in onRestart() even if I set it in onStart(). Perhaps the call to onStop() can potentially clear the content view if necessary and that is what is causing the NPE on occasion. The documentation is less clear on that. – Dan Nichols Aug 30 '16 at 20:35
  • I think clearing the view should be done only in case of onDestroy() and seems OS can call it too. Calling it would make the activity onCreate() getting called. But onDestroy() is not always called and resources released. In this particular case, where app doesn't know if activity needs to be recreated or not is causing it. onStart() is always caled after onStop(), but it is called multiple times so need to have null check if to do a setContentView. – sumandas Aug 30 '16 at 20:42
  • Sorry, I was not clear. I was not advocating clearing the content view explicitly, but openly wondering if the OS is doing it under certain conditions that would cause it to be null in onRestart(). I have found no documentation or anecdotal evidence that is the case, however. – Dan Nichols Aug 30 '16 at 21:03
  • that is true, may be this can help as it can't be simulated OS doing it, but people have suggestions do try it. http://stackoverflow.com/a/37978044/6114925 – sumandas Aug 30 '16 at 21:16
0

Not sure if this will fix the issue, and I won't know until I release a version with the fix since I am unable to reproduce the NPE, but am going to try the following to see if this prevents it:

@Override
protected void onRestart()
{
    super.onRestart();

    // check if there is a valid content view
    if ( findViewById( android.R.id.content ) == null )
    {
        // no content view, so set it back to the expected view
        setContentView( R.layout.main );
    }

    // continue restart code as before
}

Not sure if there are any negative implications of the above. Only time will tell.

Dan Nichols
  • 769
  • 1
  • 7
  • 19