【问题标题】:NullPointerException occurs while executing findViewById() in custom ListView adaptor在自定义 ListView 适配器中执行 findViewById() 时发生 NullPointerException
【发布时间】:2021-02-19 13:45:24
【问题描述】:

我想在 Android 设备上创建一个文件管理器,并在我的文件管理器中创建了一个自定义适配器作为 ListView 的内部类。

    private static final class FileAdaptor extends BaseAdapter {
           // These variables below would be set in my activity class
            private final List<String> data = new ArrayList<>(); // file name
            private final List<Drawable> data1 = new ArrayList<>(); // file icon
            private final List<String> data2 = new ArrayList<>(); // file modified data
            private final AppCompatActivity activity;
    
            public FileAdaptor(final AppCompatActivity activity) {
                this.activity = activity;
            }
    
            @Override
            public final int getCount() {
                return data.size();
            }
    
            @Override
            public final Object getItem(final int position) {
                return data.get(position);
            }
    
            public final void setData(final List<String> data) {
                if (data != null) {
                    this.data.clear();
                    if (data.size() > 0)
                        this.data.addAll(data);
                    notifyDataSetChanged();
                }
            }
    
            public final void setData1(final List<Drawable> data) {
                if (data != null) {
                    this.data1.clear();
                    if (data.size() > 0)
                        this.data1.addAll(data);
                    notifyDataSetChanged();
                }
            }
    
            public final void setData2(final List<String> data) {
                if (data != null) {
                    this.data2.clear();
                    if (data.size() > 0)
                        this.data2.addAll(data);
                    notifyDataSetChanged();
                }
            }
    
            public final String getData(final int position) {
                return data.get(position);
            }
    
            public final Drawable getData1(final int position) {
                return data1.get(position);
            }
    
            public final String getData2(final int position) {
                return data2.get(position);
            }
    
            @Override
            public final long getItemId(final int position) {
                return 0;
            }
    
            @Override
            public final View getView(final int position, final View convertView, final ViewGroup parent) {
                View v;
                if (convertView == null) {
                    v = LayoutInflater.from(parent.getContext()).inflate(R.layout.file_manager_items, parent, false);
                } else v = convertView;
    
                ViewHolder h = (ViewHolder) v.getTag();
                if (h == null) {
                    h = new ViewHolder(Objects.requireNonNull(activity.findViewById(R.id.itemIcon)), Objects.requireNonNull(activity.findViewById(R.id.fileName)), Objects.requireNonNull(activity.findViewById(R.id.fileInfo)));
                    v.setTag(h);
                }

/**********************
**Error occurred here**
**********************/

                    h.fileIcon.setImageDrawable(getData1(position));
                    h.fileName.setText(getData(position).substring(getData(position).lastIndexOf("/")));
                    h.fileInfo.setText(getData2(position));
                return v;
            }
    
            private static final class ViewHolder {
                public final AppCompatImageView fileIcon;
                public final AppCompatTextView fileName;
                public final AppCompatTextView fileInfo;
    
                public ViewHolder(@NonNull final AppCompatImageView fileIcon, @NonNull final AppCompatTextView fileName, @NonNull final AppCompatTextView fileInfo) {
                    this.fileIcon = fileIcon;
                    this.fileName = fileName;
                    this.fileInfo = fileInfo;
                }
            }
    
            @NonNull
            @Override
            public final String toString() {
                return "FileAdaptor{" +
                        "data=" + data +
                        ", activity=" + activity +
                        '}';
            }
        }

下面是ListView中适配器的布局文件。

<?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="wrap_content"
    android:layout_centerInParent="true"
    android:orientation="horizontal">

    <androidx.appcompat.widget.AppCompatImageView
        android:id="@+id/itemIcon"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_gravity="center_horizontal|center_vertical"
        android:layout_weight="1"
        android:gravity="center" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="left|start"
        android:layout_weight="10"
        android:gravity="start"
        android:orientation="vertical">

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/fileName"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColor="@color/contents_title"
            android:textSize="18sp" />

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/fileInfo"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColor="@color/contents" />
    </LinearLayout>
</LinearLayout>

这是 Activity 的布局文件,其中包括 listView。

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/fileManagerContentView"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@id/fileManagerBottomBar">

            <ListView
                android:id="@+id/mainContent"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fillViewport="true"
                app:layout_behavior="@string/appbar_scrolling_view_behavior" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/fileManagerBottomBar"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_alignParentBottom="true"
            android:orientation="horizontal">

            <androidx.appcompat.widget.AppCompatImageButton
                android:id="@+id/back"
                style="@style/Widget.AppCompat.Button.Borderless"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1"
                app:srcCompat="@drawable/arrow_back" />

            <androidx.appcompat.widget.AppCompatImageButton
                android:id="@+id/next"
                style="@style/Widget.AppCompat.Button.Borderless"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1"
                app:srcCompat="@drawable/arrow_next" />

            <androidx.appcompat.widget.AppCompatImageButton
                android:id="@+id/create"
                style="@style/Widget.AppCompat.Button.Borderless"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1"
                app:srcCompat="@drawable/create" />

            <androidx.appcompat.widget.AppCompatImageButton
                android:id="@+id/refreshContents"
                style="@style/Widget.AppCompat.Button.Borderless"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1"
                app:srcCompat="@drawable/reload" />

            <androidx.appcompat.widget.AppCompatImageButton
                android:id="@+id/parentFolder"
                style="@style/Widget.AppCompat.Button.Borderless"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1"
                app:srcCompat="@drawable/up_dir" />
        </LinearLayout>
    </RelativeLayout>

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/navigationView"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/navigation_header"
        app:menu="@menu/navigation_menu" />
</androidx.drawerlayout.widget.DrawerLayout>

现在看起来一切正常。但是,当我尝试在适配器的 getView 方法中为我的文本视图调用 setText 时,应用程序崩溃了,并输出 java.lang.NullPointerException,但在此之前我已经调用了 findViewById。

后来我为ViewHold中的对象注解了NonNull,为findViewById注解了Objects.requireNonNull,但是仍然出现错误,错误输出如下

java.lang.NullPointerException
        at java.util.Objects.requireNonNull(Objects.java:203)
        at com.example.filemanager.MainActivity$FileAdaptor.getView(MainActivity.java:500)
        at android.widget.AbsListView.obtainView(AbsListView.java:3271)
        at android.widget.ListView.makeAndAddView(ListView.java:2238)
        at android.widget.ListView.fillDown(ListView.java:838)
        at android.widget.ListView.fillFromTop(ListView.java:900)
        at android.widget.ListView.layoutChildren(ListView.java:1974)
        at android.widget.AbsListView.onLayout(AbsListView.java:3041)
        at android.view.View.layout(View.java:23754)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
        at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1818)
        at android.widget.LinearLayout.onLayout(LinearLayout.java:1584)
        at android.view.View.layout(View.java:23754)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1103)
        at android.view.View.layout(View.java:23754)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at androidx.drawerlayout.widget.DrawerLayout.onLayout(DrawerLayout.java:1231)
        at android.view.View.layout(View.java:23754)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at android.view.View.layout(View.java:23754)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at androidx.appcompat.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:530)
        at android.view.View.layout(View.java:23754)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at android.view.View.layout(View.java:23754)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
        at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
        at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
        at android.view.View.layout(View.java:23754)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at com.android.internal.policy.DecorView.onLayout(DecorView.java:1059)
        at android.view.View.layout(View.java:23754)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:3679)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3139)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2200)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8960)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:996)
        at android.view.Choreographer.doCallbacks(Choreographer.java:794)
        at android.view.Choreographer.doFrame(Choreographer.java:729)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:981)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:237)
        at android.app.ActivityThread.main(ActivityThread.java:7814)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1068)

谁能帮我解决这个问题

【问题讨论】:

  • 在 setText 周围使用 try-catch 可以避免 NullPointerException 崩溃,但并不能解决这个问题。
  • getView 方法的第 500 行究竟写了什么?
  • getView 中写的东西在我上面给出的 FileAdaptor 中,FileAdaptor 是 MainActivity 的一个内部类
  • 错误给出了一个特定的行号,我不知道哪个行号是什么。你给我整个方法的事实对我没有帮助,除非你告诉我哪一行在哪里

标签: java android android-layout listview android-listview


【解决方案1】:

您的代码应该是这样的,因为视图是适配器布局的一部分,而不是 Activity 布局的一部分。

h = new ViewHolder(Objects.requireNonNull(v.findViewById(R.id.itemIcon)), Objects.requireNonNull(v.findViewById(R.id.fileName)), Objects.requireNonNull(v.findViewById(R.id.fileInfo)));
       

  

【讨论】:

    【解决方案2】:

    替换这个:

     h = new ViewHolder(Objects.requireNonNull(activity.findViewById(R.id.itemIcon)), Objects.requireNonNull(activity.findViewById(R.id.fileName)), Objects.requireNonNull(activity.findViewById(R.id.fileInfo)));
    

    到:

    h = new ViewHolder(Objects.requireNonNull(v.findViewById(R.id.itemIcon)), Objects.requireNonNull(v.findViewById(R.id.fileName)), Objects.requireNonNull(v.findViewById(R.id.fileInfo)));
    

    因为你必须在你的项目视图中找到子项目

    【讨论】:

      【解决方案3】:

      findViewById 可以返回一个Nullable 对象,因此它不会将您从 NPE 中拯救出来。

      您在这里得到 NPE,因为您尝试使用活动布局中的 findViewById 来扩充您的视图,而它们实际上位于由 convertView 表示的项目布局中

      所以,将activity 更改为converView,如下所示

      h = new ViewHolder(Objects.requireNonNull(converView.findViewById(R.id.itemIcon)), Objects.requireNonNull(converView.findViewById(R.id.fileName)), Objects.requireNonNull(converView.findViewById(R.id.fileInfo)));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-01
        相关资源
        最近更新 更多