0

我有引起的NPE崩潰以下堆棧跟蹤:Android活動和片段生命週期問題?

Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.daybreak.my.app/com.daybreak.my.app.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ViewSwitcher.setOnClickListener(android.view.View$OnClickListener)' on a null object reference 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2430) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2490) 
    at android.app.ActivityThread.access$900(ActivityThread.java:153) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1358) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:148) 
    at android.app.ActivityThread.main(ActivityThread.java:5456) 
    at java.lang.reflect.Method.invoke(Method.java) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:735) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625) 
Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ViewSwitcher.setOnClickListener(android.view.View$OnClickListener)' on a null object reference 
    at com.daybreak.my.app.TimesFragment.onLocationChange(TimesFragment.java:446) 
    at com.daybreak.my.app.MainActivity.onLocationChange(MainActivity.java:289) 
    at com.daybreak.my.app.MainActivity.onCreate(MainActivity.java:112) 
    at android.app.Activity.performCreate(Activity.java:6302) 
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108) 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2383) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2490) 
    at android.app.ActivityThread.access$900(ActivityThread.java:153) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1358) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:148) 
    at android.app.ActivityThread.main(ActivityThread.java:5456) 
    at java.lang.reflect.Method.invoke(Method.java) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:735) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625) 

我已經安裝的方式我的應用程序如下:

MainActivity

public class MainActivity extends AppCompatActivity implements LocationChangeListener { 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     //... 
     onLocationChange(LocationManager.getSavedLocation(this)); // Manually calling onLocationChange() method 
     if (findViewById(R.id.fragment_container) != null) { 
      if (savedInstanceState != null) return; 
      showFragment(new TimesFragment(), TimesFragment.TAG); 
     } 
    } 

    @Override 
    public void onLocationChange(Locatin location) { 
     if (location == null) return; 
     //... 
     // Call attached onLocationChange() if it implements LocationChangeListener 
     Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragment_container); 
     if (f instanceof LocationChangeListener) 
      ((LocationChangeListener) f).onLocationChange(location); 
    } 

} 

TimesFragment

public class TimesFragment extends Fragment implements LocationChangeListener { 

    private ViewSwitcher viewSwitcher; 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     //... 
     viewSwitcher = (ViewSwitcher) view.findViewById(R.id.view_switcher); 
    } 

    @Override 
    public void onLocationChange(Location location) { 
     this.location = location; 
     viewSwitcher.setOnClickListener(null); //<-- NPE Cause here 
     updateContent(); 
    } 

} 

我的意料 據我瞭解,在Activity.onCreate()後,才重新開始或應用程序已被殺害後(由用戶明確或內存管理用戶返回到應用程序之後被調用時,其他應用需要記憶)。如果發生這種情況,碎片也將被銷燬並且需要被創建,即碎片的onCreateView()將被調用。因此在連接片段之前從MainActivity.onCreate()調用onLocationChange()是安全的,因爲findFragmentById()onLocationChange()內不會找到任何片段。

REALITY 從堆棧跟蹤中我們可以看到從MainActivity.onCreate()發起的呼叫。但是令我費解的是,當時onLocationChange()MainActivity.onCreate()調用時,onLocationChange()中的findFragmentById()在視圖容器中找到片段並調用片段onLocationChange()。發生這種情況時,viewSwitcherNULL,並導致應用程序崩潰。

很明顯,片段已經被添加到視圖容器中,片段onCreateView()尚未被調用。

問題

我不能重現此死機了,不知道這是造成這一生命週期的過程。

因此,誰能告訴我

  1. 如何重現這個錯誤,
  2. 生命週期過程中,負責就是造成NPE流量?
+0

FindViewById在某些條件下返回null,是的。我不明白爲什麼這是一個生命週期問題 –

+0

通過從片段的XML佈局中排除'view_switcher',您可以輕鬆地重現錯誤 –

+0

@ cricket_007我懷疑我的用戶正在編輯片段的XML文件......需要了解它在用戶設備上運行時發生。 – fahmy

回答

0

這是由設備旋轉引起的。可以通過旋轉設備重新創建堆棧跟蹤。

注意:即使應用程序的方向被鎖定,也會發生這種情況(如我的情況);如果用戶在另一個應用中的方向與您的應用鎖定的方向不同,並且他們切換回應用,則您的應用的方向生命週期將被觸發。

SOLUTION 在從片段調用方法之前添加f != null && f.isResumed()isResumed()將返回false如果片段尚未恢復後重新創建。