0

I持っ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()が呼び出されます。そのため、onLocationChange()MainActivity.onCreate()から呼び出す前に、内のfindFragmentById()はフラグメントを検出しないため安全です。

リアリティ スタックトレースから、MainActivity.onCreate()からコールが開始されたことがわかります。しかし私にとって困惑しているのは、onLocationChange()MainActivity.onCreate()の中から呼び出されたときに、onLocationChange()内のfindFragmentById()がそのフラグメントを見つけて、onLocationChange()というフラグメントを呼び出すということです。この場合、viewSwitcherNULLであり、アプリがクラッシュする原因となります。

明らかに、フラグメントは既にビューコンテナに追加されており、フラグメントonCreateView()はまだ呼び出されていません。

QUESTION

私はこのクラッシュを再作成することができ、これを引き起こしているライフサイクルプロセスのわからないではないと思います。

だから、誰もがこのエラーを再現し、NPEを引き起こしている流れに責任がある

  • ライフサイクルプロセスする方法を私に

    1. を伝えることができますか?
  • +0

    FindViewByIdは、特定の条件ではnullを返します。なぜそれがライフサイクルの問題なのか分かりません –

    +0

    フラグメントのXMLレイアウトから 'view_switcher'を除外することでエラーを非常に簡単に再現することができます –

    +0

    @ cricket_007ユーザーがフラグメントのXMLファイルを編集しているのではないか...ユーザデバイス上で動作しているときに発生します。 – fahmy

    答えて

    0

    これは、デバイスのローテーションによるものです。デバイスを回転してスタックトレースを再作成できます。

    注:注:これは、私の場合のように、アプリケーションの向きがロックされている場合でも起こります。ユーザーが別のアプリの方向にあるアプリの方向がアプリのロックされている方向と異なる場合、アプリに戻ると、アプリのオリエンテーションライフサイクルが開始されます。

    SOLUTION は、フラグメントからメソッドを呼び出す前にf != null && f.isResumed()を追加します。 isResumed()は、レクリエーション後にフラグメントが再開されなかった場合は、falseを返します。

    関連する問題