Android:在 Fragment 中扩展自定义视图

Android: Inflate Custom View inside Fragment

我有一个应用程序使用片段视图作为其布局的一部分。在此片段中,我想实例化一个 Paint Canvas,我可以在其中进行自定义绘图。

问题是,当我使用错误 android.view.InflateException: Binary XML file line #15: Binary XML file line #15: Error inflating class com.example.xxxxx.NeckCanvasOverlay

扩充片段时,我的应用程序崩溃了

我不确定是什么导致我的油漆 class 无法正常充气。我知道关于如何在片段内使用 findViewById 有一些特殊规则,但我认为我遵守了这些规则,因为我在片段的视图本身上调用 findViewByid(在我的代码中称为 "v")。

我该如何解决这个问题?

FragmentNeckDisplayMenu.java(片段Class)

public class FragmentNeckDisplayMenu extends Fragment {
    private static View v;
    private NeckCanvasOverlay neckHUD;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        v = inflater.inflate(R.layout.menu_fragment_neck_display,container,false);      //ERROR HERE
        NeckCanvasOverlay neckHUD = (NeckCanvasOverlay) v.findViewById(R.id.neckHUD);   //paint test
        ...
        return v;
    }
}

NeckCanvasOverlay.java(油漆Class)

class NeckCanvasOverlay extends View {
    private Paint mPainter;

    public NeckCanvasOverlay(Context context) {
        super(context);
        initView();
    }

    private void initView(){    //Initializes canvas & paint objects here to save performance
        mPainter = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPainter.setColor(Color.BLUE);
        mPainter.setAlpha(128);
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(180, 900, 200, mPainter);
    }
}

menu_fragment_neck_display.xml(片段的布局)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:id="@+id/canvas"
    android:background="@drawable/image">

    <LinearLayout
        android:layout_width="148dp"
        android:layout_height="0dp"
        android:layout_gravity="center"
        android:layout_weight="4">
        !--Custom view for Canvas here -->
        <com.example.xxxxx.NeckCanvasOverlay
            android:id="@+id/neckHUD"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:background="@drawable/neck_for_menu"/>
    </LinearLayout>

    <Button
        android:id="@+id/menuIcon"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_marginTop="64dp"
        android:text="Menu"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_gravity="bottom"
        android:layout_weight="0.5"/>
</LinearLayout>

完整堆栈跟踪(编辑:包括完整跟踪)

   08-06 21:47:24.894 26334-26334/com.example.xxxxx E/ACRA: ACRA caught a InflateException for com.example.xxxxx
                                                             android.view.InflateException: Binary XML file line #15: Binary XML file line #15: Error inflating class com.example.gu.NeckCanvasOverlay
                                                                 at android.view.LayoutInflater.inflate(LayoutInflater.java:551)
                                                                 at android.view.LayoutInflater.inflate(LayoutInflater.java:429)
                                                                 at com.example.xxxxx.FragmentNeckDisplayMenu.onCreateView(FragmentNeckDisplayMenu.java:32)
                                                                 at android.support.v4.app.Fragment.performCreateView(Fragment.java:1962)
                                                                 at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067)
                                                                 at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248)
                                                                 at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
                                                                 at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613)
                                                                 at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:570)
                                                                 at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141)
                                                                 at android.support.v4.view.ViewPager.populate(ViewPager.java:1106)
                                                                 at android.support.v4.view.ViewPager.populate(ViewPager.java:952)
                                                                 at android.support.v4.view.ViewPager.setOffscreenPageLimit(ViewPager.java:733)
                                                                 at com.example.xxxxx.PlayFrets.configMenu(PlayFrets.java:150)
                                                                 at com.example.xxxxx.AsyncTask_NoteFileLoader.onPostExecute(AsyncTask_NoteFileLoader.java:125)
                                                                 at com.example.xxxxx.AsyncTask_NoteFileLoader.onPostExecute(AsyncTask_NoteFileLoader.java:9)
                                                                 at android.os.AsyncTask.finish(AsyncTask.java:651)
                                                                 at android.os.AsyncTask.access0(AsyncTask.java:180)
                                                                 at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:668)
                                                                 at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                 at android.os.Looper.loop(Looper.java:158)
                                                                 at android.app.ActivityThread.main(ActivityThread.java:7229)
                                                                 at java.lang.reflect.Method.invoke(Native Method)
                                                                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
                                                                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
                                                              Caused by: android.view.InflateException: Binary XML file line #15: Error inflating class com.example.gu.NeckCanvasOverlay
                                                                 at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:788)
                                                                 at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:716)
                                                                 at android.view.LayoutInflater.rInflate(LayoutInflater.java:847)
                                                                 at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810)
                                                                 at android.view.LayoutInflater.rInflate(LayoutInflater.java:855)
                                                                 at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810)
                                                                 at android.view.LayoutInflater.inflate(LayoutInflater.java:527)
                                                                 at android.view.LayoutInflater.inflate(LayoutInflater.java:429) 
                                                                 at com.example.xxxxx.FragmentNeckDisplayMenu.onCreateView(FragmentNeckDisplayMenu.java:32) 
                                                                 at android.support.v4.app.Fragment.performCreateView(Fragment.java:1962) 
                                                                 at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067) 
                                                                 at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248) 
                                                                 at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738) 
                                                                 at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613) 
                                                                 at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:570) 
                                                                 at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141) 
                                                                 at android.support.v4.view.ViewPager.populate(ViewPager.java:1106) 
                                                                 at android.support.v4.view.ViewPager.populate(ViewPager.java:952) 
                                                                 at android.support.v4.view.ViewPager.setOffscreenPageLimit(ViewPager.java:733) 
                                                                 at com.example.xxxxx.PlayFrets.configMenu(PlayFrets.java:150) 
                                                                 at com.example.xxxxx.AsyncTask_NoteFileLoader.onPostExecute(AsyncTask_NoteFileLoader.java:125) 
                                                                 at com.example.xxxxx.AsyncTask_NoteFileLoader.onPostExecute(AsyncTask_NoteFileLoader.java:9) 
                                                                 at android.os.AsyncTask.finish(AsyncTask.java:651) 
                                                                 at android.os.AsyncTask.access0(AsyncTask.java:180) 
                                                                 at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:668) 
                                                                 at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                 at android.os.Looper.loop(Looper.java:158) 
                                                                 at android.app.ActivityThread.main(ActivityThread.java:7229) 
                                                                 at java.lang.reflect.Method.invoke(Native Method) 
                                                                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
                                                                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 
                                                              Caused by: java.lang.ClassNotFoundException: Didn't find class "com.example.gu.NeckCanvasOverlay" on path: DexPathList[[zip file "/data/app/com.example.xxxxx-2/base.apk"],nativeLibraryDirectories=[/data/app/com.example.xxxxx-2/lib/arm64, /vendor/lib64, /system/lib64]]
                                                                 at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
                                                                 at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
                                                                 at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
                                                                 at android.view.LayoutInflater.createView(LayoutInflater.java:595)
                                                                 at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:776)
                                                                 at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:716) 
                                                                 at android.view.LayoutInflater.rInflate(LayoutInflater.java:847) 
                                                                 at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810) 
                                                                 at android.view.LayoutInflater.rInflate(LayoutInflater.java:855) 
                                                                 at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810) 
                                                                 at android.view.LayoutInflater.inflate(LayoutInflater.java:527) 
                                                                 at android.view.LayoutInflater.inflate(LayoutInflater.java:429) 
                                                                 at com.example.xxxxx.FragmentNeckDisplayMenu.onCreateView(FragmentNeckDisplayMenu.java:32) 
                                                                 at android.support.v4.app.Fragment.performCreateView(Fragment.java:1962) 
                                                                 at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067) 
                                                                 at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248) 
                                                                 at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738) 
                                                                 at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613) 
                                                                 at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:570) 
                                                                 at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141) 
                                                                 at android.support.v4.view.ViewPager.populate(ViewPager.java:1106) 
                                                                 at android.support.v4.view.ViewPager.populate(ViewPager.java:952) 
                                                                 at android.support.v4.view.ViewPager.setOffscreenPageLimit(ViewPager.java:733) 
                                                                 at com.example.xxxxx.PlayFrets.configMenu(PlayFrets.java:150) 
                                                                 at com.example.xxxxx.AsyncTask_NoteFileLoader.onPostExecute(AsyncTask_NoteFileLoader.java:125) 
                                                                 at com.example.xxxxx.AsyncTask_NoteFileLoader.onPostExecute(AsyncTask_NoteFileLoader.java:9) 
                                                                 at android.os.AsyncTask.finish(AsyncTask.java:651) 
                                                                 at android.os.AsyncTask.access0(AsyncTask.java:180) 
                                                                 at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:668) 
                                                                 at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                 at android.os.Looper.loop(Looper.java:158) 
                                                                 at android.app.ActivityThread.main(ActivityThread.java:7229) 
                                                                 at java.lang.reflect.Method.invoke(Native Method) 
                                                                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
                                                                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 
                                                                Suppressed: java.lang.ClassNotFoundException: com.example.gu.NeckCanvasOverlay
                                                                 at java.lang.Class.classForName(Native Method)
                                                                 at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
                                                                 at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
                                                                 at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
                                                                        ... 33 more
                                                              Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available
08-06 21:47:24.954 26334-27123/? E/AndroidRuntime: FATAL EXCEPTION: main
                                                   Process: com.example.xxxxx, PID: 26334
                                                   android.view.InflateException: Binary XML file line #15: Binary XML file line #15: Error inflating class com.example.gu.NeckCanvasOverlay
                                                       at android.view.LayoutInflater.inflate(LayoutInflater.java:551)
                                                       at android.view.LayoutInflater.inflate(LayoutInflater.java:429)
                                                       at com.example.xxxxx.FragmentNeckDisplayMenu.onCreateView(FragmentNeckDisplayMenu.java:32)
                                                       at android.support.v4.app.Fragment.performCreateView(Fragment.java:1962)
                                                       at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067)
                                                       at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248)
                                                       at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
                                                       at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613)
                                                       at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:570)
                                                       at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141)
                                                       at android.support.v4.view.ViewPager.populate(ViewPager.java:1106)
                                                       at android.support.v4.view.ViewPager.populate(ViewPager.java:952)
                                                       at android.support.v4.view.ViewPager.setOffscreenPageLimit(ViewPager.java:733)
                                                       at com.example.xxxxx.PlayFrets.configMenu(PlayFrets.java:150)
                                                       at com.example.xxxxx.AsyncTask_NoteFileLoader.onPostExecute(AsyncTask_NoteFileLoader.java:125)
                                                       at com.example.xxxxx.AsyncTask_NoteFileLoader.onPostExecute(AsyncTask_NoteFileLoader.java:9)
                                                       at android.os.AsyncTask.finish(AsyncTask.java:651)
                                                       at android.os.AsyncTask.access0(AsyncTask.java:180)
                                                       at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:668)
                                                       at android.os.Handler.dispatchMessage(Handler.java:102)
                                                       at android.os.Looper.loop(Looper.java:158)
                                                       at android.app.ActivityThread.main(ActivityThread.java:7229)
                                                       at java.lang.reflect.Method.invoke(Native Method)
                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
                                                    Caused by: android.view.InflateException: Binary XML file line #15: Error inflating class com.example.gu.NeckCanvasOverlay
                                                       at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:788)
                                                       at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:716)
                                                       at android.view.LayoutInflater.rInflate(LayoutInflater.java:847)
                                                       at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810)
                                                       at android.view.LayoutInflater.rInflate(LayoutInflater.java:855)
                                                       at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810)
                                                       at android.view.LayoutInflater.inflate(LayoutInflater.java:527)
                                                       at android.view.LayoutInflater.inflate(LayoutInflater.java:429) 
                                                       at com.example.xxxxx.FragmentNeckDisplayMenu.onCreateView(FragmentNeckDisplayMenu.java:32) 
                                                       at android.support.v4.app.Fragment.performCreateView(Fragment.java:1962) 
                                                       at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067) 
                                                       at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248) 
                                                       at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738) 
                                                       at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613) 
                                                       at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:570) 
                                                       at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141) 
                                                       at android.support.v4.view.ViewPager.populate(ViewPager.java:1106) 
                                                       at android.support.v4.view.ViewPager.populate(ViewPager.java:952) 
                                                       at android.support.v4.view.ViewPager.setOffscreenPageLimit(ViewPager.java:733) 
                                                       at com.example.xxxxx.PlayFrets.configMenu(PlayFrets.java:150) 
                                                       at com.example.xxxxx.AsyncTask_NoteFileLoader.onPostExecute(AsyncTask_NoteFileLoader.java:125) 
                                                       at com.example.xxxxx.AsyncTask_NoteFileLoader.onPostExecute(AsyncTask_NoteFileLoader.java:9) 
                                                       at android.os.AsyncTask.finish(AsyncTask.java:651) 
                                                       at android.os.AsyncTask.access0(AsyncTask.java:180) 
                                                       at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:668) 
                                                       at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                       at android.os.Looper.loop(Looper.java:158) 
                                                       at android.app.ActivityThread.main(ActivityThread.java:7229) 
                                                       at java.lang.reflect.Method.invoke(Native Method) 
                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 
                                                    Caused by: java.lang.ClassNotFoundException: Didn't find class "com.example.gu.NeckCanvasOverlay" on path: DexPathList[[zip file "/data/app/com.example.xxxxx-2/base.apk"],nativeLibraryDirectories=[/data/app/com.example.xxxxx-2/lib/arm64, /vendor/lib64, /system/lib64]]
                                                       at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
                                                       at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
                                                       at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
                                                       at android.view.LayoutInflater.createView(LayoutInflater.java:595)
                                                       at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:776)
                                                       at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:716) 
                                                       at android.view.LayoutInflater.rInflate(LayoutInflater.java:847) 
                                                       at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810) 
                                                       at android.view.LayoutInflater.rInflate(LayoutInflater.java:855) 
                                                       at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810) 
                                                       at android.view.LayoutInflater.inflate(LayoutInflater.java:527) 
                                                       at android.view.LayoutInflater.inflate(LayoutInflater.java:429) 
                                                       at com.example.xxxxx.FragmentNeckDisplayMenu.onCreateView(FragmentNeckDisplayMenu.java:32) 
                                                       at android.support.v4.app.Fragment.performCreateView(Fragment.java:1962) 
                                                       at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067) 
                                                       at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248) 
                                                       at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738) 
                                                       at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613) 
                                                       at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:570) 
                                                       at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141) 
                                                       at android.support.v4.view.ViewPager.populate(ViewPager.java:1106) 
                                                       at android.support.v4.view.ViewPager.populate(ViewPager.java:952) 
                                                       at android.support.v4.view.ViewPager.setOffscreenPageLimit(ViewPager.java:733) 
                                                       at com.example.xxxxx.PlayFrets.configMenu(PlayFrets.java:150) 
                                                       at com.example.xxxxx.AsyncTask_NoteFileLoader.onPostExecute(AsyncTask_NoteFileLoader.java:125) 

包含自定义 View 的所有三个构造函数更安全。例如,为您的 NeckCanvasOverlay.

包含以下构造函数
public NeckCanvasOverlay(Context context) {
        super(context);
        initView();
    }

    public NeckCanvasOverlay(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public NeckCanvasOverlay(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView();
    }

希望对您有所帮助。试一试,如果您遇到同样的错误,请告诉我。

眼前的问题是ClassNotFoundException。在布局中处理自定义 View 时,常见的原因是布局 XML 中的 class 名称不正确,这似乎就是这里的问题所在。确保 XML 标签具有自定义 View class 的正确、完全限定的 class 名称,这将是 class 的 package 从文件顶部开始,添加到 class 名称前。

此外,从您的布局中扩充的 Views 将使用带有 ContextAttributeSet 的双参数构造函数实例化。您的 class 定义需要至少具有允许 inflation 的构造函数,否则您将得到 NoSuchMethodException。此外,如果您只是扩展 View,那么如果您将构造函数链接起来,事情会变得更简单一些。例如:

public NeckCanvasOverlay(Context context) {
    this(context, null);
}

public NeckCanvasOverlay(Context context, AttributeSet attrs) {
    super(context, attrs);
    initView();
}