【问题标题】:Android activity and fragment lifecycle issue?Android活动和片段生命周期问题?
【发布时间】:2016-12-06 15:13:06
【问题描述】:

我有以下由 NPE 引起的崩溃的堆栈跟踪:

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() 是安全的,因为onLocationChange() 中的findFragmentById() 不会找到任何片段。

现实 从堆栈跟踪我们可以看到调用是从MainActivity.onCreate() 发起的。但令我困惑的是,当时onLocationChange()是从MainActivity.onCreate()内调用的,findFragmentById()onLocationChange()在视图容器中找到片段并调用片段onLocationChange()。当这种情况发生时,viewSwitcherNULL 并导致应用程序崩溃。

很明显,fragment 已经被添加到视图容器中,fragment onCreateView() 还没有被调用。

问题

我无法重新创建此崩溃,并且不确定导致此崩溃的生命周期过程。

谁能告诉我

  1. 如何重现此错误以及
  2. 负责导致 NPE 的流的生命周期过程?

【问题讨论】:

  • FindViewById 在某些条件下返回 null,是的。我不明白为什么这是一个生命周期问题
  • 您可以通过从 Fragment 的 XML 布局中排除 view_switcher 来轻松重现错误
  • @cricket_007 我怀疑我的用户正在编辑片段的 XML 文件...需要知道在用户设备上运行时它是如何发生的。
  • 你并没有真正说这是用户的外部堆栈跟踪,你只是说你有一个 NPE 和这个堆栈跟踪,所以 ViewSwitcher 为空,因为它从未被发现......

标签: android android-fragments nullpointerexception android-lifecycle


【解决方案1】:

这是由设备旋转引起的。可以通过旋转设备重新创建堆栈跟踪。

注意:即使应用程序的方向被锁定(如我的情况),也会发生这种情况;如果用户在另一个应用程序中的方向与您的应用程序锁定的方向不同并且他们切换回该应用程序,则您的应用程序的方向生命周期将被触发。

解决方案 在从片段调用方法之前添加f != null &amp;&amp; f.isResumed()isResumed() 将返回 false 如果片段在重新创建后尚未恢复。

【讨论】:

    猜你喜欢
    • 2020-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-02
    • 1970-01-01
    • 1970-01-01
    • 2014-07-28
    • 1970-01-01
    相关资源
    最近更新 更多