【问题标题】:Android inflate layout crashes after adding fragment container view添加片段容器视图后,Android 膨胀布局崩溃
【发布时间】:2023-01-04 09:57:00
【问题描述】:

目前我有一个扩展 AppCompatActivity 的自定义抽屉活动,如下所示:

public class DrawerActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener{
    
    ...

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

        ...
    }


    @Override
    public void setContentView(int layoutResID) {
        frameLayout = findViewById(R.id.drawer_frame);
        LayoutInflater.from(getApplicationContext()).inflate(layoutResID, frameLayout);
        super.setContentView(drawerLayout);
    }

    ...
}

正如您在此处看到的,我覆盖了 setContentView 方法,因此扩展此抽屉活动的活动的布局 ID 将被传递到此方法中并在抽屉活动的子视图中膨胀。简而言之,我希望扩展此抽屉活动的所有活动都将具有导航抽屉。它适用于一般活动。

但是现在,我有一个包含片段容器视图并扩展抽屉活动的活动。当我启动此活动时,应用程序崩溃并出现以下错误:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.aaa, PID: 10730
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.aaa/com.example.aaa.gym.GymActivity}: android.view.InflateException: Binary XML file line #29 in com.example.aaa:layout/activity_gym: Binary XML file line #29 in com.example.aaa:layout/activity_gym: Error inflating class androidx.fragment.app.FragmentContainerView
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3635)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3792)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7839)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
     Caused by: android.view.InflateException: Binary XML file line #29 in com.example.aaa:layout/activity_gym: Binary XML file line #29 in com.example.aaa:layout/activity_gym: Error inflating class androidx.fragment.app.FragmentContainerView
     Caused by: android.view.InflateException: Binary XML file line #29 in com.example.aaa:layout/activity_gym: Error inflating class androidx.fragment.app.FragmentContainerView
     Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Constructor.newInstance0(Native Method)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
        at android.view.LayoutInflater.createView(LayoutInflater.java:858)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1010)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:965)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1127)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1088)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:686)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:538)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:485)
        at com.example.aaa.DrawerActivity.setContentView(DrawerActivity.java:57)
        at com.example.aaa.gym.GymActivity.onCreate(GymActivity.java:62)
        at android.app.Activity.performCreate(Activity.java:8051)
        at android.app.Activity.performCreate(Activity.java:8031)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3608)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3792)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7839)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
     Caused by: java.lang.UnsupportedOperationException: FragmentContainerView must be within a FragmentActivity to use android:name="com.example.aaa.gym.PlaceFragment"
E/AndroidRuntime:     at androidx.fragment.app.FragmentContainerView.<init>(FragmentContainerView.java:142)
        at androidx.fragment.app.FragmentContainerView.<init>(FragmentContainerView.java:120)
            ... 28 more

如您所见,根本原因是java.lang.UnsupportedOperationException: FragmentContainerView must be within a FragmentActivity to use android:name="com.example.aaa.gym.PlaceFragment"。但是,活动应该能够扩展片段,因为它扩展了 DrawerActivity,DrawerActivity 扩展了 AppCompatActivity,AppCompatActivity 扩展了 Fragment Activity。我对此很困惑。

这是活动代码:

public class GymActivity extends DrawerActivity implements OnMapReadyCallback, GoogleMap.OnMarkerClickListener {

    private ActivityGymBinding binding;
    
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        markers = new ArrayList<>();

        binding = ActivityGymBinding.inflate(getLayoutInflater());

        // here crashes, the actual crash line is the second line of the drawer activity's setContentView
        setContentView(binding.getRoot().getSourceLayoutResId()); 

        ...

    }
    
    ...
}

这是活动 xml

<?xml version="1.0" encoding="utf-8"?>

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/mapLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".gym.GymActivity">


    <com.google.android.gms.maps.MapView
        android:id="@+id/mapView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:contentDescription="@string/title_activity_gym"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/place_fragment"
        android:name="com.example.aaa.gym.PlaceFragment"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:layout="@layout/place_fragment" />

</androidx.constraintlayout.widget.ConstraintLayout>

而片段,几乎没有任何改变

public class PlaceFragment extends Fragment {

    private PlaceViewModel mViewModel;
    private PlaceFragmentBinding binding;

    public static PlaceFragment newInstance() {
        return new PlaceFragment();
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {

        mViewModel = new ViewModelProvider(requireActivity()).get(PlaceViewModel.class);

        mViewModel.getName().observe(getViewLifecycleOwner(), s -> binding.name.setText(s));
        mViewModel.getLocation().observe(getViewLifecycleOwner(), s -> binding.location.setText(s));

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

fragment.xml,只是一个简单的框架布局

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".gym.PlaceFragment">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/name"
        android:text="Hello" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/location"
        android:text="Hello" />

</FrameLayout>

谁能看出我的应用程序崩溃的原因?任何建议将不胜感激。

【问题讨论】:

    标签: java android android-fragments android-appcompat appcompatactivity


    【解决方案1】:

    问题在这里:

    LayoutInflater.from(getApplicationContext()).inflate(layoutResID, frameLayout);
    

    您正在使用应用程序上下文 - 特别是不是因此,您的 Activity 不使用 Activity 的主题,您的 Application 类也不扩展 FragmentActivity。您需要使用 LayoutInflater.from(this) 来实际使用您的 Activity 作为布局 inflater。

    然而,虽然这会修复你的崩溃,但你的 GymActivity 仍然无法工作,因为这些行:

    binding = ActivityGymBinding.inflate(getLayoutInflater());
    
    // here crashes, the actual crash line is the second line of the drawer activity's setContentView
    setContentView(binding.getRoot().getSourceLayoutResId()); 
    

    在这里,您创建了一个 binding 对象,但实际上从未将它添加到您的 Activity 中。相反,您调用您的 setContentView 重写,它会膨胀该视图的全新实例。这意味着对 binding 的任何更改都不会反映在您的 UI 中。

    相反,您希望提供对您的 setContentView 的覆盖,它采用 View 并在您的 FrameLayout 上调用 addView 以将已经膨胀的视图添加到您的布局中。

    @Override
    public void setContentView(View view) {
        frameLayout = findViewById(R.id.drawer_frame);
        frameLayout.addView(view)
        // Note you should never be calling super.setContentView here.
        // You've already called it in your own onCreate()
    }
    

    这让你可以像这样使用它:

    binding = ActivityGymBinding.inflate(getLayoutInflater());
    
    setContentView(binding.getRoot()); 
    

    【讨论】:

    • 天哪!你是天才XD
    【解决方案2】:

    :)

    我有同样的问题,但以其他方式:

    我使用片段内部的按钮通过界面通信在 MainActivity 中膨胀不同的布局。它在布局仅包含一个 TextView 时有效,但当我将其替换为 Fragment Container View 时,它崩溃了。我使用@ianhanniballake 回答将上下文更改为 (this) 并且它消除了崩溃,但它仍然没有膨胀任何东西..

    这是我的代码:

    public class MainActivity extends AppCompatActivity implements FragmentB.FragmentBListener {
    
        ViewGroup main_layout;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            main_layout = findViewById(R.id.main_layout);
        }
    
        //fullScreen method comes from a button click listener from FragmentB
        @Override
        public void fullScreen() {
            LayoutInflater inflater = LayoutInflater.from(MainActivity.this);
            View view = inflater.inflate(R.layout.fullscreen, main_layout,false);
            main_layout.removeAllViews();
            main_layout.addView(view);
        }
    }
    

    这是我要膨胀的布局:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <androidx.fragment.app.FragmentContainerView
            android:id="@+id/fragmentContainerViewB"
            android:name="com.example.testglide.FragmentB"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="500dp"
            tools:layout="@layout/fragment_b" />
    
    </RelativeLayout>
    

    【讨论】:

      猜你喜欢
      • 2013-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多