Android 应用程序在屏幕方向改变时崩溃

4
该应用程序有一个主活动和两个片段。主活动托管MainFragmentMainFragment包含一个按钮以提交BreedingFragment(运行)。当方向没有改变时,应用程序能够正常工作,但在打开BreedingFragment并改变方向时,它会崩溃。
经过在stackoverflow上研究几个小时后,我发现了以下文章并按照答案进行尝试,但无法调试出问题。
  1. Android Application Crashes With Orientation Changes
  2. Orientation change Crash Application
  3. Rotation of screen crashes android app
  4. My Android application crashes when I change screen orientation
答案主要建议在AndroidManifest.xml中使用以下代码:
android:configChanges="orientation|keyboardHidden|screenSize"

最后一个线程建议考虑以下内容:

每次设备方向改变时,活动实际上会停止并重新启动。因此,您需要编写线程时考虑到这一点,即在设备改变方向时停止线程并重新启动它,可能在两者之间保存状态。

MainActivity:

public class MainActivity extends FragmentActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

MainFragment:

public class MainFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View v = inflater.inflate(R.layout.fragment_main, container, false);

        Button breedButton = (Button) v.findViewById(R.id.pokemon_breeding_button);

        breedButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                final FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
                final FragmentTransaction transaction = fragmentManager.beginTransaction();
                transaction.replace(R.id.fragment, new BreedingFragment());
                transaction.addToBackStack(null);
                transaction.commit();
            }
        });
        return v;
    }
}

BreedingFragment:

public class BreedingFragment extends Fragment {

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        return inflater.inflate(R.layout.fragment_breeding, container, false);
    }
}

日志记录器:

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.revittechnology.zapdos, PID: 12795
                  java.lang.RuntimeException: Unable to start activity ComponentInfo{com.revittechnology.zapdos/com.revittechnology.zapdos.MainActivity}: android.view.InflateException: Binary XML file line #24: Error inflating class fragment
                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2429)
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2493)
                      at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4014)
                      at android.app.ActivityThread.access$900(ActivityThread.java:166)
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1289)
                      at android.os.Handler.dispatchMessage(Handler.java:102)
                      at android.os.Looper.loop(Looper.java:136)
                      at android.app.ActivityThread.main(ActivityThread.java:5590)
                      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:1280)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1096)
                      at dalvik.system.NativeStart.main(Native Method)
                   Caused by: android.view.InflateException: Binary XML file line #24: Error inflating class fragment
                      at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:720)
                      at android.view.LayoutInflater.rInflate(LayoutInflater.java:762)
                      at android.view.LayoutInflater.rInflate(LayoutInflater.java:771)
                      at android.view.LayoutInflater.rInflate(LayoutInflater.java:771)
                      at android.view.LayoutInflater.inflate(LayoutInflater.java:499)
                      at android.view.LayoutInflater.inflate(LayoutInflater.java:398)
                      at android.view.LayoutInflater.inflate(LayoutInflater.java:354)
                      at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:331)
                      at android.app.Activity.setContentView(Activity.java:2018)
                      at com.revittechnology.zapdos.MainActivity.onCreate(MainActivity.java:13)
                      at android.app.Activity.performCreate(Activity.java:5447)
                      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1094)
                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2393)
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2493) 
                      at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4014) 
                      at android.app.ActivityThread.access$900(ActivityThread.java:166) 
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1289) 
                      at android.os.Handler.dispatchMessage(Handler.java:102) 
                      at android.os.Looper.loop(Looper.java:136) 
                      at android.app.ActivityThread.main(ActivityThread.java:5590) 
                      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:1280) 
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1096) 
                      at dalvik.system.NativeStart.main(Native Method) 
                   Caused by: java.lang.IllegalStateException: Fragment com.revittechnology.zapdos.MainFragment did not create a view.
                      at android.support.v4.app.FragmentManagerImpl.onCreateView(FragmentManager.java:2319)
                      at android.support.v4.app.FragmentController.onCreateView(FragmentController.java:120)
                      at android.support.v4.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:356)
                      at android.support.v4.app.BaseFragmentActivityHoneycomb.onCreateView(BaseFragmentActivityHoneycomb.java:31)
                      at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:79)
                      at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:696)
                      at android.view.LayoutInflater.rInflate(LayoutInflater.java:762) 
                      at android.view.LayoutInflater.rInflate(LayoutInflater.java:771) 
                      at android.view.LayoutInflater.rInflate(LayoutInflater.java:771) 
                      at android.view.LayoutInflater.inflate(LayoutInflater.java:499) 
                      at android.view.LayoutInflater.inflate(LayoutInflater.java:398) 
                      at android.view.LayoutInflater.inflate(LayoutInflater.java:354) 
                      at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:331) 
                      at android.app.Activity.setContentView(Activity.java:2018) 
                      at com.revittechnology.zapdos.MainActivity.onCreate(MainActivity.java:13) 
                      at android.app.Activity.performCreate(Activity.java:5447) 
                      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1094) 
                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2393) 
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2493) 
                      at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4014) 
                      at android.app.ActivityThread.access$900(ActivityThread.java:166) 
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1289) 
                      at android.os.Handler.dispatchMessage(Handler.java:102) 
                      at android.os.Looper.loop(Looper.java:136) 
                      at android.app.ActivityThread.main(ActivityThread.java:5590) 
                      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:1280) 
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1096) 
                      at dalvik.system.NativeStart.main(Native Method) 
I/Process: Sending signal. PID: 12795 SIG: 9
Application terminated.

Stack Overflow是用于编程问题的。你有什么问题?如果你的问题是“为什么我崩溃了?”,请使用LogCat来检查与崩溃相关的Java堆栈跟踪:https://dev59.com/iGAg5IYBdhLWcg3wpMSz - CommonsWare
如果你的问题是关于你观察到的崩溃原因,那么请在这里发布崩溃堆栈跟踪。 - Tobias
1
你不应该让你的Fragments自我替换。 - OneCricketeer
@cricket_007,您有什么其他建议吗?谢谢。 - Maihan Nijat
1
如果您遵循本指南,它将展示如何在点击事件中“回调”到活动以替换片段。https://developer.android.com/training/basics/fragments/communicating.html - OneCricketeer
你必须将ConfigChanges行放置在Manifest文件中的活动范围内。 - crakxx
1个回答

0

主活动和主片段。 上面的照片阐述了这种情况。MainActivity.java 托管 MainFragment.java,而主片段有一个按钮,可以启动另一个片段。

我的要求是什么?

  1. 主活动只托管主片段,没有其他东西。
  2. 主片段有一个按钮来启动第二个片段。
  3. 按返回按钮时关闭(结束/完成)第二个片段(返回到主活动)。
  4. 与设备(屏幕)旋转一起工作。

第一步是创建主活动。在主活动中有几件事要考虑

  1. MainActivity扩展为FragmentActivity

代码如下:public class MainActivity extends FragmentActivity

  1. 检查 savedInstanceState,如果它是 null,则运行 MainFragment。我们这样做的原因是为了避免在设备旋转时再次运行 MainFragment。

下面是 MainActivity.java 的代码:

public class MainActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            FragmentManager fManager = getSupportFragmentManager();
            FragmentTransaction fTransaction = fManager.beginTransaction();
            fTransaction.add(R.id.fragment, new MainFragment());
            fTransaction.commit();
        }

    }
}

请确保在 activity_main.xml 文件中包含以下代码行:
<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:name="com.revittechnology.zapdos.MainFragment"
    android:id="@+id/fragment" /> 

现在创建MainFragment.java文件:
public class MainFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_main, container, false);
        // Inflate the layout for this fragment
        Button breedButton = (Button) v.findViewById(R.id.pokemon_breeding_button);

        breedButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                final FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
                final FragmentTransaction transaction = fragmentManager.beginTransaction();
                transaction.replace(R.id.fragment, new BreedingFragment());
                transaction.addToBackStack("tag");
                transaction.commit();
            }
        });
        return v;
    }
}

在返回视图之前(return v),请包含所有代码,因为如果视图不存在,则无法找到按钮和其他布局元素。 transaction.addToBackStack("tag"); 可以将片段添加到后退堆栈,并使其能够通过后退键关闭片段。

现在创建第二个片段BreedingFragment.java`

public class BreedingFragment extends Fragment {
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_breeding, container, false);
    }
}

注意:在声明类之前导入所需的库。

结论:应用程序由于设备方向而崩溃,因为通过按钮单击启动了第二个片段,并且MainFragment由MainActivity托管。随着设备方向的变化,片段被关闭,并且MainActivity.java中没有代码来重新初始化片段,因此会出现空异常错误。将与片段相关的代码添加到MainActivity.java中以通过编程方式启动片段解决了问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接