Search code examples
androidandroid-cursoradapterandroid-glideandroid-cursorandroid-cursorloader

RecyclerView freezing with Glide


I am using glide in a cursor adapter to load thousands of views. They all have a small image attached to them loaded from disk (all less than 10kb). However i am getting freezing and the issue seems to come from the Glide library (however it might be due to the cursorloader). I attached my code and log files below.

Relevant CursorAdapter Code:

public FilesFragmentCursorAdapter(Activity context, Cursor cursor, Bucket bucket) {
        super(context, cursor, 0);
        mContext = context;
        this.cursor = cursor;
        mBucket = bucket;
        mSelectedItemsIds = new SparseBooleanArray();
        downloader = new ThumbnailDownloader(mContext, mBucket);
        manager = GlideApp.with(mContext);
        inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mShowThumbnails = mContext.getSharedPreferences(Constants.PREFS, Context.MODE_PRIVATE).getBoolean(Constants.PREFS_SHOW_THUMBNAILS, false);
    }

    @Override
    public Object getItem(int position) {
        return super.getItem(position);
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
        return LayoutInflater.from(context).inflate(R.layout.list_file_item, viewGroup, false);
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        FileViewHolder holder = new FileViewHolder();

        holder.mId = view.findViewById(R.id.list_file_id);
        holder.mName = view.findViewById(R.id.list_file_name);
        holder.mSize = view.findViewById(R.id.list_file_size);
        holder.mCreated = view.findViewById(R.id.list_file_date);
        holder.image = view.findViewById(R.id.list_file_image);
        holder.container = view.findViewById(R.id.list_file_item);

        String id = cursor.getString(cursor.getColumnIndex(KEY_PID));
        String name = cursor.getString(cursor.getColumnIndex(KEY_NAME));
        long size = cursor.getLong(cursor.getColumnIndex(KEY_SIZE));
        String created = cursor.getString(cursor.getColumnIndex(KEY_CREATED_AT));
        String mimeType = cursor.getString(cursor.getColumnIndex(KEY_MIME));

        if (id != null) holder.mId.setText(id);
        if (name != null) holder.mName.setText(name);
        String fileSize = Formatter.formatFileSize(mContext, size);
        holder.mSize.setText(fileSize);
        if (created != null && created.length() > 10) {
            String fileCreatedDate = created.substring(0, 10);
            holder.mCreated.setText(fileCreatedDate);
        }
        if (mimeType != null) {
            if (mimeType.contains("image")) {
                holder.image.setImageResource(R.drawable.ic_image_black_48dp);
                if (mShowThumbnails) {
                    String thumbnailPath = cursor.getString(cursor.getColumnIndex(KEY_THUMBNAIL));
                    if (!TextUtils.isEmpty(thumbnailPath)) {
                        manager.load(thumbnailPath).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.NONE).into(holder.image);
                    } else {
                        File current = DatabaseHelper.createFileFromCursor(cursor);
                        downloader.download(current);
                    }
                }
            } else if (mimeType.contains("video")) {
                holder.image.setImageResource(R.drawable.ic_videocam_black_48dp);
            } else if (mimeType.contains("text")) {
                holder.image.setImageResource(R.drawable.ic_text_format_black_48dp);
            } else if (mimeType.contains("audio")) {
                holder.image.setImageResource(R.drawable.ic_audiotrack_black_48dp);
            } else {
                holder.image.setImageResource(R.drawable.ic_insert_drive_file_black_48dp);
            }
        }
    }

Logs:

12-28 21:47:17.212 27355-27450/co.intellidev.storj 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
12-28 21:47:20.150 27355-27752/co.intellidev.storj E/libEGL: error creating cache file /data/user_de/0/co.intellidev.storj/code_cache/com.android.opengl.shaders_cache: Too many open files (24)
12-28 21:50:02.744 27355-27450/co.intellidev.storj E/GraphicBuffer: unflatten: registerBuffer failed: Unknown error -5 (5)
12-28 21:50:02.748 27355-27450/co.intellidev.storj E/Surface: dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: 5
12-28 21:50:02.752 27355-27450/co.intellidev.storj E/Parcel: fcntl(F_DUPFD_CLOEXEC) failed in Parcel::read, i is 1, fds[i] is -1, fd_count is 2, error: Too many open files
12-28 21:50:02.752 27355-27450/co.intellidev.storj E/Surface: dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: -22
12-28 21:50:02.754 27355-27450/co.intellidev.storj E/Parcel: fcntl(F_DUPFD_CLOEXEC) failed in Parcel::read, i is 1, fds[i] is -1, fd_count is 2, error: Too many open files
12-28 21:50:02.754 27355-27450/co.intellidev.storj E/Surface: dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: -22

Solution

  • As Discussed..

    public class FilesFragmentCursorAdapter extends RecyclerView.Adapter<FilesFragmentCursorAdapter.FileViewHolder > {
    /* objects */
    public FilesFragmentCursorAdapter(Activity context, Cursor cursor, Bucket bucket) {
        mContext = context;
        this.cursor = cursor;
        mBucket = bucket;
        mSelectedItemsIds = new SparseBooleanArray();
        downloader = new ThumbnailDownloader(mContext, mBucket);
        manager = GlideApp.with(mContext);
        inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mShowThumbnails = mContext.getSharedPreferences(Constants.PREFS, Context.MODE_PRIVATE).getBoolean(Constants.PREFS_SHOW_THUMBNAILS, false);
    }
    
    
    @Override
    public FilesFragmentCursorAdapter.FileViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.list_file_item, parent, false);
        return new FileViewHolder(itemView); // <- render view here
    }
    
    @Override
    public void onBindViewHolder(FilesFragmentCursorAdapter.FileViewHolder  holder, final int position) {
        String id = cursor.getString(cursor.getColumnIndex(KEY_PID));
        String name = cursor.getString(cursor.getColumnIndex(KEY_NAME));
        long size = cursor.getLong(cursor.getColumnIndex(KEY_SIZE));
        String created = cursor.getString(cursor.getColumnIndex(KEY_CREATED_AT));
        String mimeType = cursor.getString(cursor.getColumnIndex(KEY_MIME));
    
    
        if (id != null) holder.mId.setText(id);
        if (name != null) holder.mName.setText(name);
    
    }
    
    
    
    @Override
    public int getItemCount() {
        return contactsList.size();
    }
    
    public class FileViewHolder  extends RecyclerView.ViewHolder {
        private TextView mId;
        private TextView mName;
        private TextView mSize;
        // so on
        public FileViewHolder (View view) {
            super(view);
            mId = view.findViewById(R.id.list_file_id);
            mName = view.findViewById(R.id.list_file_name);
            mSize = view.findViewById(R.id.list_file_size);
            // so on
    
    
        }
    }
    }
    

    Update your adapter class accordingly.


    I wonder why you are skipping cache for glide and not storing in cache.

    manager.load(thumbnailPath).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.NONE).into(holder.image);
    

    change to this and allow glide to cache resulting image not the original one.

    manager.load(thumbnailPath).diskCacheStrategy(DiskCacheStrategy.RESULT).into(holder.image);