【问题标题】:Android Fragment lifecycle makes app crashAndroid Fragment 生命周期导致应用崩溃
【发布时间】:2015-05-11 21:08:44
【问题描述】:

创建显示自定义Session 对象信息的Fragment 时,我需要加载带有所选Session 属性的UI。

第一次创建 Fragment 时可以正常工作 我在onStart 中编写了设置的代码,因为布局直到onCreateView 才会膨胀,它在onStart 之前调用。 (http://developer.android.com/guide/components/fragments.html)

问题是:每当手机旋转时,应用程序就会崩溃,显然是因为onStart 被调用,

我尝试改用onActivityCreatedonResume,但都没有成功,这是在onCreateView 之后自动调用的仅有的三个函数

如果不禁用旋转,我该怎么办?

这里有一个很好的片段生命周期图: http://developer.android.com/guide/components/fragments.html

05-12 01:03:12.968  21599-21599/com.example.kn.ib W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0x418f3da0)
    05-12 01:03:12.968  21599-21599/com.example.kn.ib E/AndroidRuntime﹕ FATAL EXCEPTION: main
        Process: com.example.kn.ib, PID: 21599
        java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.kn.ib/com.example.kn.ib.IBCentralActivity}: java.lang.NullPointerException
                at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2305)
                at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2363)
                at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3924)
                at android.app.ActivityThread.access$1000(ActivityThread.java:161)
                at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1271)
                at android.os.Handler.dispatchMessage(Handler.java:102)
                at android.os.Looper.loop(Looper.java:157)
                at android.app.ActivityThread.main(ActivityThread.java:5356)
                at java.lang.reflect.Method.invokeNative(Native Method)
                at java.lang.reflect.Method.invoke(Method.java:515)
                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
                at dalvik.system.NativeStart.main(Native Method)
         Caused by: java.lang.NullPointerException
                at com.example
                at android.app.Fragment.performActivityCreated(Fragment.java:1708)
                at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:908)
                at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1062)
                at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1044)
                at android.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1853)
                at android.app.Activity.performCreate(Activity.java:5429)
                at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
                at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2269)
                at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2363)
                at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3924)
                at android.app.ActivityThread.access$1000(ActivityThread.java:161)
                at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1271)
                at android.os.Handler.dispatchMessage(Handler.java:102)
                at android.os.Looper.loop(Looper.java:157)
                at android.app.ActivityThread.main(ActivityThread.java:5356)
                at java.lang.reflect.Method.invokeNative(Native Method)
                at java.lang.reflect.Method.invoke(Method.java:515)
                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
                at dalvik.system.NativeStart.main(Native Method)

片段 onStart(第 117 行是 "ID: "+ session._id + "\n" +

   @Override
    public void onStart() {
        super.onStart();


        sessionID = activityCallback.getSelectedSessionID();
        db = activityCallback.getSessionDatabase();

        session = db.getSession(sessionID);

        TextView textViewForTesting = (TextView) getView().findViewById(R.id.test);
        String testText = "\n" +
                "ID: "+ session._id + "\n" +
                "LAP COUNT: "+ session._lapCount + "\n" +
                "DATE: "+ session._date + "\n" +
                "CALORIES: "+ session._calories + "\n" +
                "ISOPEN: "+ session._isOpen + "\n" +
                "LASTMOD: "+ session._lastMod;

        textViewForTesting.setText(testText);

        Button saveButton = (Button) getView().findViewById(R.id.SessionInfo_SaveButton);
        saveButton.setOnClickListener(this);

        isOpenTextField = (EditText) getView().findViewById(R.id.ISOPEN);
        poolSizeTextField = (EditText) getView().findViewById(R.id.POOLSIZE);
        commentTextField = (EditText) getView().findViewById(R.id.COMMENT);
        metricTextField = (EditText) getView().findViewById(R.id.METRIC);


   
            public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
                Calendar newDate = Calendar.getInstance();
                newDate.set(year, monthOfYear, dayOfMonth);
                dateField.setText(dateFormatter.format(newDate.getTime()));
            }

        },sessionYear, sessionMonth, sessionDay);

        timeField = (EditText) getView().findViewById(R.id.sessionTimeField);
        //TODO: set user preferences for time format HH or KK
        timeFormatter = new SimpleDateFormat("HH:mm", Locale.US);

        timeField.setInputType(InputType.TYPE_NULL);
        timeField.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                timePickerDialog.show();
            }
        });
        timeField.setText(sessionHour + ":" + sessionMinute);

        timePickerDialog = new TimePickerDialog(getActivity(), new TimePickerDialog.OnTimeSetListener() {

            public void onTimeSet(TimePicker view,  int hourOfDay, int minute) {
                Calendar newTime = Calendar.getInstance();
                int hr = newTime.get(Calendar.HOUR_OF_DAY);
                int mn = newTime.get(Calendar.MINUTE);
                /*TODO: set user preferences for time format HH or KK */
                dateField.setText(hr+":"+mn);
            }

        },sessionHour, sessionMinute, true/*TODO: set user preferences for time format HH or KK */);
        isOpenTextField.setText(session._isOpen+"");
        metricTextField.setText(session._metric);
        commentTextField.setText(session._comment);
        poolSizeTextField.setText("" + session._poolSize);
    }

【问题讨论】:

  • 可以看看布局代码吗?您如何保留会话对象?
  • stacktrace 也很有用
  • 我投票结束这个问题,因为“没有堆栈跟踪的崩溃”
  • 好的,我已经添加了堆栈跟踪,对我来说没有多大意义
  • 对片段的覆盖方法(onStart 等)的调用在您第一次创建片段和应用旋转时是相同的。

标签: android android-fragments


【解决方案1】:

Activity 和 Fragment 生命周期在 android 上并非微不足道。 请记住活动和片段将在设备旋转时被销毁并重新创建,因此,如果您需要一个不再调用的方法,您可以使用片段的 onCreate 方法并将 setRetainInstanceState(true) 放入同一方法中。这样,片段将在设备方向更改时保留而不是销毁。 此外,您必须在 xml 布局中定义片段并且必须分配一个 id,如果您的布局是通过编程方式添加的或没有 UI,您可以使用 FragmentManager 和标签来添加和检索片段。

您可以查看android handling runtime changes指南

【讨论】:

  • 是的,onCreate 的问题是它没有找到我的 UI 元素,直到调用 onCreateView 才加载布局
猜你喜欢
  • 2016-11-15
  • 1970-01-01
  • 1970-01-01
  • 2017-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多