2

Description

Suppose I have a RecyclerView that shows 50 photos from extras folder in internal storage. Considering that, That 50 photos are not going to change anytime. So, when user launches the app it fetches 50 photos from internet and saves in internal storage. if user launches photos activity then a cycle of fetching those 50 photos from extras folder will run. This cycle will fetch all the photos from the internal storage and will compare their BUCKET_DISPLAY_NAME with extras. If both are equal then and only it will be shown in recyclerView

considering this scenario, I want to save the recyclerView state or data in internal storage. So, when next time user opens app it will not go through fetching all the photos and instead it will direclty load recyclerview with photos which is saved.

Fetch Method

 public ArrayList<ImageModel> fetchImages() {
        uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        projection = new String[]{MediaStore.Images.Media._ID, MediaStore.Images.Media.BUCKET_DISPLAY_NAME};
        cursor = activity.getApplicationContext().getContentResolver().query(uri, projection, null, null, null);
        column_index_data = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID);
        arrayList.clear();          
        while (cursor.moveToNext()) {
            long mediaId = cursor.getLong(column_index_data);
            name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME));
            if (name.equals("extras")) {       
                Uri uriMedia = Uri.withAppendedPath(uri, "" + mediaId);
                ImageModel imageModel = new ImageModel();
                imageModel.setUri(uriMedia.toString());
                arrayList.add(imageModel);
            }
        }
        cursor.close();
        return arrayList;
    }

As you going through this method may take a lot of time if user has lot of photos other than required 50 photos.

then,

 arrayList = fetchImages();
adapter = new PhotosAdapter(requireActivity().getApplicationContext(), arrayList, getActivity(), this, this);
        recyclerView.setAdapter(adapter);

Using this method images are loaded in recyclerView.

So, is there any way to save the loaded RecyclerView or RecyclerView Data?

Doubt

According to, https://developer.android.com/reference/androidx/recyclerview/widget/RecyclerView.State

State object can also keep arbitrary data, identified by resource ids.

I don't understand much by arbitary data but, if it means recyclerView's data then How can I use RecyclerView.State object to restore the data inside recyclerView?

Note

Assume I can save any type of object in internal storage and load that object into another same class's object.

Edit As mentioned in answer loaded recyclerView cannot be stored. Instead data needs to be cached. As cache memory is inside the internal storage as well it is forcing my app to skip frames because I am loading images inside onCreateView() of my app. I can create a new Thread it will handle it in background and there are no skipped frames. But, It creates a blink effect which i don't want.

enter image description here no skipped frames

  • I guess you need to use some caching technique. I suggest you implement something that have been proven such as LRUCache. https://developer.android.com/reference/android/util/LruCache – Ivan Verges Jul 12 '21 at 18:12

1 Answers1

1

I don't understand much by arbitary data but, if it means recyclerView's data then How can I use RecyclerView.State object to restore the data inside recyclerView?

No, recyclerview's state refers to the recyclerview's state, like its vertical distance, view related data etc. The list/data factory is not handled by the recyclerview itself, rather it is provided by the Adapter. And there is no Adapter's state that is why you have to manage to load data into the adapter yourself.

As you going through this method may take a lot of time if user has lot of photos other than required 50 photos.

For your particular case, you can use cache directory for faster and easier access to your photos, you can just check if a photo exists in the cache, if not, then download, otherwise fetch it from cache. Official docs

I think that is all you want. However, if you further want to remember the last scroll position, you can do so by storing the last scroll position into SharedPreferences or similar utilities. Then after loading data, you can just manually scroll the recyclerview to that position.

Ananta Raha
  • 1,011
  • 5
  • 14
  • The cache is going to be deleted and when android will delete the cache that can'be predicted. I want to ensure that fetch from internal storage is done only one time. I don't want to run the cycle second time unless user commands it. So, the saved data should be permenant. Downloaded photos are already inside the storage so, there is no need of internet fetch but, If single image is not found in cache directory then whole cycle will run in order to find single image. – Anirudhdhsinh Jadeja Jul 13 '21 at 05:36
  • Yes, but photo from internal storage might be deleted by user too. I suggest you to use Glide library for lazy loading images from the internet, which will do everything for you, you don't need to handle cache or anything. You call with the links directly from view holder. This library is built for this purpose. – Ananta Raha Jul 13 '21 at 05:50
  • The photos are stored inside the hidden folder. So, user can't delete it. I am already using glide to load that. And i want to avoid the cycle because the cycle is the reason of skipped frames in my app. I want to load all the photos inside onCreate . But doing so forces my app to skip frames. Even with the glide library's cached images. I just stumbled with RecyclerView.ViewCacheExtension. Do you know what is that? – Anirudhdhsinh Jadeja Jul 13 '21 at 06:14
  • I did create the cache directory and tried. The performance is same. As cache directory is also going to be created inside internal storage it's not helping. – Anirudhdhsinh Jadeja Jul 13 '21 at 06:45
  • Please use Glide if you have the individual link/path for each image, it will be helpful for this scenario. – Ananta Raha Jul 13 '21 at 08:47
  • I have got your updated post, but I cannot see any blink effect as you mentioned. Since the loading is a blocking task, there must be a little delay during which you can optionally display a loading icon/just blank. – Ananta Raha Jul 13 '21 at 16:48
  • Please see the left one. It is has loading of images running on UI thread.After Photos splash screen It is showig title "Photos" and recycler view photos at the same time. Where as in the right one After the splash screen title "Photos" is displayed first and then the recycler view with photos. in which loading is done in background thread and then attached the adapter in ui thread. – Anirudhdhsinh Jadeja Jul 14 '21 at 09:02
  • I want to eliminate the right gif's blink effect caused by the slow loading speed. loading speed is propotional to cpu, ram, internal storage speed and many factors wich cannot be controlled by app. But, instead if we can save the current loaded recycler view and eliminate loading of photos at next launch we can avoid the blink effect in gif at right side. – Anirudhdhsinh Jadeja Jul 14 '21 at 09:05
  • If I get you right, what you are trying to achieve is not possible, because the loaded images along with recyclerview are all Views, which cannot be stored/persisted across process/app lifecycles. They are created for every instances of your activity/component and get destroyed once finished. – Ananta Raha Jul 14 '21 at 12:21
  • ok. I understand. I tried a different approach by saving arraylist which is returned by method mentioned in question to internal storage and loading that from second time on. Doing so, I did eliminated the fetchImages method from second time on. But, it is still skipping frames which indicates it is still slow. If I save the same arraylist via Realm database will it increase the speed of loading? – Anirudhdhsinh Jadeja Jul 14 '21 at 12:51
  • So far as I know, the skipped frame you are talking about is the result of recyclerview being loaded with the viewholders which is a CPU intensive task. So I think, Realm database might not help in this aspect, however you are free to try. – Ananta Raha Jul 14 '21 at 14:15
  • so, can you suggest a way to lower the skipped frames? It is only task which is skipping frames. When I load photos from drawable folder it doesn't skip frames. So, getting photos from internal storage is consuming time. The method mentioned above is the cause. Is there any way to reduce skipped frames by changing the method or some thing else? – Anirudhdhsinh Jadeja Jul 14 '21 at 17:30
  • if you can, please go through this post. https://stackoverflow.com/questions/68390421/how-to-select-multiple-items-in-recycler-view-android – Anirudhdhsinh Jadeja Jul 15 '21 at 08:33