如何用单个图像表示图像目录中的文件来实现图像库

How to implement Image gallery with single image representing file in image directory

我正在尝试实现类似 Instagram 或 WhatsApp 的功能,其中存在于 android 文件夹中的单个图像的缩略图显示在列表项的顶部,更像是文件夹中的图像类型。

帮助我了解这个功能。

我是如何实现的。虽然它可能不是最好的,但它确实有效。

  1. 我使用 MediaStore, you can learn how to use it here 获取了所有图像的 URI。

  2. 第一步是在后台线程中完成的,以防止它阻塞 UI 线程。

  3. 我整理了我得到的图像,将它们分组在一个 List<Image> 中,这将代表一个目录。

  4. 然后我将 List<Image> 添加到 List<List<Image>> 中,它作为获取的整体图像并具有它们的总大小,我稍后用它来跟踪数量目录中的图片。

代码如下

   @Override
   public void run() {
      Uri storageUri;
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
         storageUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
      } else {
         storageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
      }

    // the queries to the MediaStore API (The image details or metadata I need

      String[] projection = {
              MediaStore.Images.Media._ID,
              MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
              MediaStore.Images.Media.SIZE,
              MediaStore.Images.Media.DISPLAY_NAME};

     // now query the MediaStore API using ContentResolver    
      Cursor imgCursor = getApplicationContext().getContentResolver().query(storageUri, projection, null, null, null);

      int bucketId = imgCursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID);
      int imgSize = imgCursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE);
      int name = imgCursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME);
      int bucketName = imgCursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);

     // directoryDictionary is a temporary list of directory names that was found, while querying the MediaStore API

      List<String> directoryDictionary = new ArrayList<>();

     // generalList is just a list that would represent a general image list, where all images can be found. Just like Whatsapp

      List<Image> generalList = new ArrayList<>();

      while (imgCursor.moveToNext()) {
         long id = imgCursor.getLong(bucketId);
         int size = imgCursor.getInt(imgSize);
         String fileName = imgCursor.getString(name);
         String folderName = imgCursor.getString(bucketName);

        // As recommended by the Android developers doc

         Uri contentUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);

        // a single image

         Image currentImage = new Image(contentUri, size, fileName, folderName);


         // add all images to the general image list, but modifying the directory name

         Image genImage = new Image(contentUri, size, fileName, "All Media");
         generalList.add(genImage);

         int directoryIndex = CollectionUtils.linearSearch(directoryDictionary, folderName);
         // if search result (directoryIndex) passes this test, then it means that there is
         // no such directory in list of directory names
         if (directoryIndex < 0) {
            imageDirectoryList.add(new ArrayList<>());
            directoryDictionary.add(folderName);
            directoryIndex = CollectionUtils.linearSearch(directoryDictionary, folderName);
            if (directoryIndex >= 0)
               imageDirectoryList.get(directoryIndex).add(currentImage);
         } else {
            imageDirectoryList.get(directoryIndex).add(currentImage);
         }
      }

      //...then add it if the image list of folder is > 2
      if (imageDirectoryList.size() > 2) imageDirectoryList.add(0, generalList);

      imgCursor.close();
      runOnUiThread(() -> {
         // imageAdapter is the RecyclerView's list Adapter.
         // notifyDataSetChanged() must be call to refresh list.

         imageAdapter.notifyDataSetChanged();

        // doViewUpdate was just used to turn on and off the visibility of some views

         doViewUpdate();
      });
   }