android.view.InflateException: 二进制XML文件:错误填充类片段

203

我遇到了一个非常令人沮丧的错误,无法解释。我创建了一个使用 Android AppCompat 使其与旧版本兼容的Android应用程序。这是我的主要活动布局文件:

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <!-- As the main content view, the view below consumes the entire
         space available using match_parent in both dimensions. -->
    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- android:layout_gravity="start" tells DrawerLayout to treat
         this as a sliding drawer on the left side for left-to-right
         languages and on the right side for right-to-left languages.
         If you're not building against API 17 or higher, use
         android:layout_gravity="left" instead. -->

    <!-- The drawer is given a fixed width in dp and extends the full height of
         the container. -->
    <fragment android:id="@+id/navigation_drawer"
        android:layout_width="@dimen/navigation_drawer_width"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:name="com.fragment.NavigationDrawerFragment" />

</android.support.v4.widget.DrawerLayout>

这里是我的活动主要代码:

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

这里的主要问题是:以上代码在几乎所有设备上(模拟设备或某些真实设备)都可以顺利运行。但是当我在三星S3上运行它时,它会提示出现以下错误:

java.lang.RuntimeException: Unable to start activity ComponentInfo{view.MainActivity}: android.view.InflateException: Binary XML file line #25: Error inflating class fragment
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2081)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2106)
            at android.app.ActivityThread.access$700(ActivityThread.java:134)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1217)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4856)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1007)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:774)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: android.view.InflateException: Binary XML file line #25: Error inflating class fragment
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
            at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:316)
            at android.app.Activity.setContentView(Activity.java:1901)
            at android.support.v7.app.ActionBarActivity.superSetContentView(ActionBarActivity.java:208)
            at android.support.v7.app.ActionBarActivityDelegateICS.setContentView(ActionBarActivityDelegateICS.java:111)
            at android.support.v7.app.ActionBarActivity.setContentView(ActionBarActivity.java:76)
请告诉我如何修复错误,谢谢 :)

1
在这一行中,您正在收到异常,请检查类名和包名是否正确。android:name="com.hqt.hac.view.fragment.NavigationDrawerFragment" - kalyan pvs
1
我已经检查过了,这个类是正确的。我可以在一些设备上编译和运行,但三星S3无法。我觉得这里可能有一些奇怪的问题 :( - hqt
如果代码在某个设备上可以执行而不是在S3上,那么这可能是一个奇怪的问题。我的建议是尝试使用SherlacFragment检查一下。 - kalyan pvs
我已经在这里解决了问题:http://stackoverflow.com/a/33128448/4366715。 - daniel kilinskas
3
对于那些试图诊断这个错误原因的人:这里的经验性修复方法是一个误导。在片段膨胀期间发生了一个先前的异常,但它没有在堆栈跟踪中显示出来。它可能是任何问题。要解决这个问题,您必须找出先前的异常是什么。为了做到这一点,请参见我的回答或 @DaveHubbard 的回答。 - LarsH
我的图像文件在“drawable-v24”文件夹中。我也将它们复制到了“drawable”文件夹中。问题解决了。我从https://github.com/chrisjenx/Calligraphy/issues/417得到了这个解决方案。 - Abdul Wahid
42个回答

155

经过长时间调试,我已经解决了这个问题。尽管我仍然无法解释为什么。我将属性android:name更改为class。(尽管在Android文档中,他们说这些属性是相同的,但它确实起作用了!!!)

因此,应该从以下内容进行更改:

 android:name="com.fragment.NavigationDrawerFragment"

为了

class = "com.fragment.NavigationDrawerFragment"
所以,新的布局应该是:

<!-- As the main content view, the view below consumes the entire
     space available using match_parent in both dimensions. -->
<FrameLayout
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

<!-- android:layout_gravity="start" tells DrawerLayout to treat
     this as a sliding drawer on the left side for left-to-right
     languages and on the right side for right-to-left languages.
     If you're not building against API 17 or higher, use
     android:layout_gravity="left" instead. -->

<!-- The drawer is given a fixed width in dp and extends the full height of
     the container. -->
<fragment android:id="@+id/navigation_drawer"
    android:layout_width="@dimen/navigation_drawer_width"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    class = "com.fragment.NavigationDrawerFragment" />

希望这可以帮到您 :)


6
当我尝试按照官方Android教程操作时,遇到了这个问题。你的解决方法(将'android:id'更改为'class')对我起作用了。我还收到了一个Lint警告建议将“Fragment”更改为“fragment”,我已经做了更改。 - stevepastelan
11
@DownVoter: 这个错误很令人困惑。幸运的是,我找到了解决方法。如果我的帖子不能修复您的错误,我真的很抱歉,因为我也无法解释为什么。但我认为这不应该被贬低评分。 :) - hqt
2
我想知道你是否能够在没有将“name”更改为“class”的情况下可靠地重现此崩溃。我有一些用户报告了这个崩溃,但我自己无法重现它! - Daniel Wilson
19
对我没用。我太累了。我已经开发了2个小时,但还是找不到为什么它不起作用(二进制XML文件行...错误膨胀类片段)。你有任何想法吗? - Cocorico
1
过时了!你有关于 "androidx.fragment.app.FragmentContainerView" 的任何想法吗? - Foxhunt

72
TL/DR: 在更高级别的布局XML中引用片段时,创建片段期间发生异常。这个异常导致了更高级别的布局膨胀失败,但是初始异常没有被报告;只有更高级别的膨胀失败出现在堆栈跟踪中。要找到根本原因,您必须捕获和记录初始异常

错误的初始原因可能是各种各样的问题,这就是为什么每个人都有不同的答案来解决问题的原因。对于一些人,这与idclassname属性有关。对于其他人,这是由于权限问题或构建设置而导致的。对我来说,这些都没有解决问题;相反,存在一个可绘制资源,它只存在于drawable-ldrtl-xhdpi中,而不是像drawable这样的适用位置。

但这些只是细节。大局问题是在logcat中显示的错误消息没有描述引起所有问题的异常。当更高级别的布局XML引用片段时,将调用片段的onCreateView()。当片段的onCreateView()中发生异常(例如在膨胀片段的布局XML时),它会导致更高级别的布局XML膨胀失败。这个更高级别的膨胀失败被报告为错误日志中的异常。但初始异常似乎没有很好地沿着链路传播以被报告。

在这种情况下,问题是如何暴露初始异常,当它没有出现在错误日志中时。

解决方案非常简单:在片段的onCreateView()内容周围放置一个try/catch块,并在catch子句中记录异常:

public View onCreateView(LayoutInflater inflater, ViewGroup contnr, Bundle savedInstSt) {
    try {
        mContentView = inflater.inflate(R.layout.device_detail_frag, null);
        // ... rest of body of onCreateView() ...
    } catch (Exception e) {
        Log.e(TAG, "onCreateView", e);
        throw e;
    }
}

可能不是很明显应该在哪个片段类的onCreateView()中进行此操作。如果是这种情况,请对导致问题的布局中使用的每个片段类都进行操作。例如,在OP的情况下,引发异常的应用程序代码为:

at android.app.Activity.setContentView(Activity.java:1901)

这是

   setContentView(R.layout.activity_main);

所以你需要在任何与布局activity_main相关的片段的onCreateView()中捕获异常。

在我的情况下,根本原因异常被证明是

Caused by: android.content.res.Resources$NotFoundException: Resource
   "com.example.myapp:drawable/details_view" (7f02006f)  is not a
   Drawable (color or path): TypedValue{t=0x1/d=0x7f02006f a=-1
   r=0x7f02006f}

在我在onCreateView()中捕获并明确记录异常之前,这个异常在错误日志中没有显示出来。一旦记录下来,问题就很容易诊断和解决了(某种原因下,details_view.xml仅存在于ldrtl-xhdpi文件夹下)。关键是捕获问题的根源异常,并将其暴露出来。

所有你的片段的onCreateView()方法中进行此操作不会有任何损失。如果有未捕获的异常,它将崩溃该活动。唯一的区别是,如果你在onCreateView()中捕获和记录异常,你就不会对发生的原因感到困惑。

P.S. 我刚意识到这个答案与@DaveHubbard的答案相关,但使用了不同的方法来找到根本原因(记录与调试器)。


对我来说,我通过将内部片段的“id”设置为与外部片段用于描述内部片段的相同“id”来解决了我的问题。 换句话说,view.findViewById(R.id.blah) 然后在“blah”上执行 Ctrl+Click 应该返回多个可能片段的结果。 - robotsfoundme
比大多数答案更好的解决方案。其他大部分解决方案在现代的Android Studio上很可能不起作用。 - stardep

37

我无法通过提供的答案解决我的问题。最终,我改变了这个:

<fragment
android:id="@+id/fragment_food_image_gallery"
android:name="ir.smartrestaurant.ui.fragment.ImageGalleryFragment"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout="@layout/fragment_image_gallery"
tools:layout="@layout/fragment_image_gallery" />

到这个:

<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="200dp" />
private void showGallery() {
    ImageGalleryFragment fragment = new ImageGalleryFragment()
    getSupportFragmentManager().beginTransaction()
                .replace(R.id.fragment_container, fragment)
                .commit();
    }

它能正常工作。
如果您在片段内使用它,请使用getChildFragmentManager而不是getSupportFragmentManager


23

我曾经碰到了同样的问题,试过这个主题中所有的答案,但都没有解决。我的解决办法是,在 Activity XML 文件中我没有添加 ID。虽然我一开始认为这并不重要,但事实证明确实很重要。

所以在 Activity XML 文件中,我原本写成:

<fragment
    android:name="com.covle.hellocarson.SomeFragment"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

但应该有:

<fragment
    android:id="@+id/some_fragment"
    android:name="com.covle.hellocarson.SomeFragment"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

如果有人愿意解释为什么这样做,我非常乐意倾听;对于其他人,希望这能有所帮助。

1
谢谢,这对我有用。我已经漏掉了一个ID好几个月了,但在一些布局更改后突然出现了这个崩溃。安卓真奇怪。 - erisco
你的回答对我有帮助。我只是想知道为什么我需要在没有使用id属性的情况下将其放置在代码中。你可以给我解释一下吗? - Moshi

12

我有同样的问题,因为我没有实现监听器。请参考以下代码,加入/*Add This!*/

public class SomeActivity extends AppCompatActivity
        implements BlankFragment.OnFragmentInteractionListener /*Add this!*/ 
{
    @Override                                                  /*Add This!*/
    public void onFragmentInteraction(Uri uri){                /*Add This!*/
    }                                                          /*Add This!*/
}

我的片段类(fragment class)大致如下:

public class SomeFragment extends Fragment {

    private OnFragmentInteractionListener mListener;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (OnFragmentInteractionListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

    public interface OnFragmentInteractionListener {
        public void onFragmentInteraction(Uri uri);
    }
}

编辑:

我还注意到在另一种情况下,当FragmentonCreate函数出现异常时,也会出现相同的错误消息。我的代码如下:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_main, container, false);

    int ID = getArguments().getInt("val");

    return rootView;
} 

因为我重复使用这个片段,所以完全忘记设置参数。然后getArguments()的结果是null。显然,我在这里得到了一个null指针异常。我建议您也要注意这样的错误。


1
谢谢!这帮了很多忙! - DLee

12

如果有读者仍然需要此信息,你或许不再需要了。我遇到了与你完全相同的问题android.view.InflateException:...Error inflating class fragment,我的库都没问题。通过在AndroidManifest.xml文件中添加一个用户权限<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>解决了问题。

顺便说一下,我是在运行Ubuntu 12.04上的Android Studio 0.8.9时遇到这个问题的。


对我有用!非常感谢! - Aesthetic

8

你的NavigationDrawerFragment是否扩展了android.support.v4.app.Fragment?换句话说,你是否导入了正确的包?

import android.support.v4.app.Fragment;

6
我曾经也遇到过类似的问题,错误信息通常提供很少的细节,无论实际原因是什么。但我找到了一个获取更有用信息的方法。事实证明,内部android类'LayoutInflater.java'(在android.view包中)有一个“inflate”方法,它重新抛出异常,但不捕获详细信息,因此导致您丢失关于原因的信息。
我使用AndroidStudio,在LayoutInflator第539行(我正在使用的版本中),即该“inflate”方法中通用异常catch块的第一行设置断点:
        } catch (Exception e) {
            InflateException ex = new InflateException(
                    parser.getPositionDescription()
                            + ": " + e.getMessage());
            ex.initCause(e);
            throw ex;

如果你在调试器中查看'e',你会看到一个'cause'字段。它可以非常有帮助地提示你发生了什么。例如,我就是通过这种方式发现包含的片段的父级必须具有id,即使在代码中没有使用。或者TextView存在尺寸问题。


6

我也遇到过这个问题。我通过替换MainActivityNavigationDrawerFragment中的导入解决了它。

import android.app.Activity;
import android.app.ActionBar;

To

import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;

我将MainActivity从继承自Activity改为继承自ActionBarActivity

public class MainActivity extends ActionBarActivity implements NavigationDrawerFragment.NavigationDrawerCallbacks

同时使用 ActionBar actionBar = getSupportActionBar(); 获取 ActionBar。

我更新了 NavigationDrawerFragment 中的以下函数:

private ActionBar getActionBar()
{
    return ((ActionBarActivity)getActivity()).getSupportActionBar();
}

我认为这是正确的答案。但是我使用了AppCompatActivity而不是ActionBarActivity(已弃用),并且也没有删除import android.app.ActionBar(因为onAttach方法使用它)。 - GramThanos

6
我遇到了这个问题,并通过使用下面的代码解决了它。我使用ChildFragmentManager开始了片段事务。
布局:
                  <fragment
                    class="com.google.android.youtube.player.YouTubePlayerSupportFragment"
                    android:id="@+id/youtube_fragment"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"/>

这是我开始片段事务的方式:
   youTubePlayerFragment = (YouTubePlayerSupportFragment) getChildFragmentManager().findFragmentById(R.id.youtube_fragment);

以下代码解释了我如何通过使用ChildFragmentManager删除添加的片段。
@Override
    public void onDestroyView() {
        super.onDestroyView();

        youTubePlayerFragment = (YouTubePlayerSupportFragment) getChildFragmentManager().findFragmentById(R.id.youtube_fragment);

        if (youTubePlayerFragment != null)
        {
            getChildFragmentManager().beginTransaction().remove(youTubePlayerFragment).commitAllowingStateLoss();
        }

        youTubePlayer = null;
    }

谢谢您,Ali。您救了我的一天! - vm345
运行正常。谢谢! - Polyariz

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