滚动 RecyclerView 时出现“打开的文件太多”

Posted

技术标签:

【中文标题】滚动 RecyclerView 时出现“打开的文件太多”【英文标题】:"Too many open files" when scrolling RecyclerView 【发布时间】:2019-03-10 07:40:07 【问题描述】:

我有一个应用程序,它对外部 API 进行许多异步调用,以获取有关图像缩略图的详细信息,以便在用户滚动浏览它时加载到我的 RecyclerView(使用 Glide)中。 Recyclerview 是“永无止境的”,因为如果用户想要滚动足够长的时间,可以加载数千张图片。

滚动浏览一百张图片后出现以下错误:

W/Adreno-GSL: <gsl_ldd_control:541>:ioctl fd 55 code 0xc0200933 (IOCTL_KGSL_TIMESTAMP_EVENT) failed: errno 24 Too many open files
  <ioctl_kgsl_syncobj_create:3977>: (38, 1f, 3907) fail 24 Too many open files
E/Parcel: fcntl(F_DUPFD_CLOEXEC) failed in Parcel::read, i is 0, fds[i] is -1, fd_count is 1, error: Too many open files
I/Adreno: DequeueBuffer: dequeueBuffer failed
E/NativeCrypto: AppData::create pipe(2) failed: Too many open files

该应用永远不会崩溃,但它会一直冻结,直到我(稍等一下?然后)退出该应用并重新进入它。

根据我所做的研究,我了解到一次可以打开多少个文件是有限制的,但我不确定如何控制。

    我如何知道当前打开了多少文件? 如何在 RecyclerView 等待更多文件释放时“暂停”它? 我应该在我的 AsyncTask 中做些什么来释放文件吗?

【问题讨论】:

你应该像 Picasso 或 glide 这样的库来抽象所有这些东西,而不是使用 asynctask 我正在使用 Glide,但我必须从 API 获取 URL 以提供给 Glide 以加载图像... 【参考方案1】:

当项目在屏幕上不可见时,您应该取消您的 api 调用和其他异步工作。 因为如果用户快速滚动,您将有数百个无用的任务在运行。

所以,只需在视图滚动时取消您的任务。

您可以在 RecylerView 的 void onViewRecycled (VH holder) 方法中完成所有这些工作。

来自文档:

void onViewRecycled (VH holder)

在此适配器创建的视图被回收时调用。

当 RecyclerView.LayoutManager 决定回收视图时 不再需要附加到其父 RecyclerView。这可以是 因为它已经失去可见性或一组缓存视图 由仍附加到父 RecyclerView 的视图表示。如果 项目视图绑定了大或昂贵的数据,例如大 位图,这可能是释放这些资源的好地方。

RecyclerView 在清除 ViewHolder 之前调用此方法 内部数据并将其发送到 RecycledViewPool。这样,如果 ViewHolder 在被回收之前持有有效信息,你 可以调用 getAdapterPosition() 来获取它的适配器位置。

【讨论】:

【参考方案2】:

我相信您所要做的就是在下载文件后关闭您的连接/套接字:

Socket accept - "Too many open files"

如果您正在缓存下载的图像,您还应该正确关闭您的FileInputStreamFileOutputStream

同时在根视图被破坏时注销您的适配器:

@Override
protected void onDestroy() 
    super.onDestroy();
    recyclerView.setAdapter(null);

【讨论】:

以上是关于滚动 RecyclerView 时出现“打开的文件太多”的主要内容,如果未能解决你的问题,请参考以下文章

在滚动 RecyclerView 时出现异常:-“java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item p

充气 RecyclerView 时出现 InflateException

实现 Recyclerview 过滤器时出现 indexoutofboundexception

Recyclerview部分:调用notifyDataSetChanged()时出现IllegalStateException [重复]

在 Fragment 中使用 RecyclerView 时出现 Kotlin 错误的 Android

在滚动列表中实现视频的播放(ListView & RecyclerView)