0

I have an app that makes many asynchronous calls to external APIs to fetch details about an image thumbnail to load into my RecyclerView(using Glide) as a user scrolls through it. The Recyclerview is "never-ending" as there can be thousands of images to load if the user wanted to scroll long enough.

I am getting the following error after scrolling through maybe a hundred images:

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

The app never crashes but it remains frozen until I (wait a bit? and then) tab out of the app and back in to it.

From the research I've done I've learned that there's a limit on how many files can be open at once but I'm not sure how to control this.

  1. How do I know how many files are currently open?
  2. How do I "pause" my RecyclerView as it waits for more files to free up?
  3. Am I supposed to be doing something in my AsyncTask to free up the file(s)?
qtmfld
  • 2,916
  • 2
  • 21
  • 36
Isaac Perez
  • 570
  • 2
  • 15
  • 31

2 Answers2

2

You should cancel your api calls and other async work when item is not visible on the screen. Because if user scrolls fast you will have hundreds of useless tasks running.

So, just cancel you tasks when view is scrolled.

You can do all this work in the RecylerView's void onViewRecycled (VH holder) method.

From documentation:

void onViewRecycled (VH holder)

Called when a view created by this adapter has been recycled.

A view is recycled when a RecyclerView.LayoutManager decides that it no longer needs to be attached to its parent RecyclerView. This can be because it has fallen out of visibility or a set of cached views represented by views still attached to the parent RecyclerView. If an item view has large or expensive data bound to it such as large bitmaps, this may be a good place to release those resources.

RecyclerView calls this method right before clearing ViewHolder's internal data and sending it to RecycledViewPool. This way, if ViewHolder was holding valid information before being recycled, you can call getAdapterPosition() to get its adapter position.

0

I believe all you have to do is to close your connections / sockets after downloading a file:

Socket accept - "Too many open files"

If you are caching the downloaded images you should also properly close your FileInputStream or FileOutputStream

Also unregister your adapter while the root view get destroyed:

@Override
protected void onDestroy() {
    super.onDestroy();
    recyclerView.setAdapter(null);
}
alex
  • 8,904
  • 6
  • 49
  • 75