在自定义 ListView 适配器中执行 findViewById() 时发生 NullPointerException
Posted
技术标签:
【中文标题】在自定义 ListView 适配器中执行 findViewById() 时发生 NullPointerException【英文标题】:NullPointerException occurs while executing findViewById() in custom ListView adaptor 【发布时间】: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_
android:layout_
android:layout_centerInParent="true"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/itemIcon"
android:layout_
android:layout_
android:layout_gravity="center_horizontal|center_vertical"
android:layout_weight="1"
android:gravity="center" />
<LinearLayout
android:layout_
android:layout_
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_
android:layout_
android:textColor="@color/contents_title"
android:textSize="18sp" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/fileInfo"
android:layout_
android:layout_
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_
android:layout_>
<RelativeLayout
android:layout_
android:layout_
android:orientation="vertical">
<LinearLayout
android:layout_
android:layout_
android:layout_above="@id/fileManagerBottomBar">
<ListView
android:id="@+id/mainContent"
android:layout_
android:layout_
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</LinearLayout>
<LinearLayout
android:id="@+id/fileManagerBottomBar"
android:layout_
android:layout_
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/back"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_
android:layout_
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_
android:layout_
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_
android:layout_
android:layout_weight="1"
app:srcCompat="@drawable/create" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/refreshContents"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_
android:layout_
android:layout_weight="1"
app:srcCompat="@drawable/reload" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/parentFolder"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_
android:layout_
android:layout_weight="1"
app:srcCompat="@drawable/up_dir" />
</LinearLayout>
</RelativeLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigationView"
android:layout_
android:layout_
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 的一个内部类 错误给出了一个特定的行号,我不知道哪个行号是什么。你给我整个方法的事实对我没有帮助,除非你告诉我哪一行在哪里 【参考方案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)));
【讨论】:
以上是关于在自定义 ListView 适配器中执行 findViewById() 时发生 NullPointerException的主要内容,如果未能解决你的问题,请参考以下文章
如何在自定义 ListView 适配器中处理 RadioGroup 的 onCheckedChangeListener
listview 项目未在自定义适配器的 getview 方法中显示分配的值
在自定义适配器类中发送服务器请求后,如何更改 Listview 按钮名称?
Android - 通过 getView 函数在自定义 listView 适配器内设置 ImageView 的源无法正常工作
如何在自定义 ListView 中获取 EditText 的所有值
为 listview 定义 onlick:在 listView 级别的 Onclick 与自定义视图适配器内的 Onclick