嗨,我正在尝试通过启动扫描来刷新图库。对于运行Kitkat和更高版本的设备,我正在使用mediascannerconnection。但是mediaScannerConnection需要绝对路径来进行扫描。我所拥有的是 DocumentFile ,它似乎没有任何方法来获取它的绝对路径。

以下是我正在使用的代码:

要获得使用新的棒棒糖API写入文件夹的权限->将选定的URI保存到全局变量中->隐藏的逻辑(创建/删除“.nomedia”文件)。

// Calling folder selector.
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, 42);
..............
@SuppressLint("NewApi") @Override
    public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
        if (resultCode == RESULT_OK && requestCode == 42) {
            Uri treeUri = resultData.getData();
            getContentResolver().takePersistableUriPermission(treeUri,
//                  Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION |
                    Intent.FLAG_GRANT_READ_URI_PERMISSION |
                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            path = treeUri.getPath();
        }

 }
 ..........
 public void hide(boolean hide){
    DocumentFile pickedDir = DocumentFile.fromTreeUri(this,Uri.parse(path));
    if(hide){
            if(pickedDir.findFile(".nomedia")==null){
                pickedDir.createFile(null, ".nomedia");
                tellgallery(pickedDir.findFile(".nomedia").getUri().getPath());
            }
    }
    else{
            DocumentFile filetodelete = pickedDir.findFile(".nomedia");
            if(filetodelete!=null){
                filetodelete.delete();
                tellgallery(filetodelete.getPath());
            }
    }
 }

上面的代码可以完美运行,并在所需的文件夹中创建/删除“.nomedia”文件。

现在,当我尝试告诉画廊该文件夹的文件已更改时。图库无法选择更改。

以下是刷新/请求扫描的代码。
private void tellgallery(String path) {
    pathtonomedia = path;
    if(path!=null){
    if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
        mediaScannerConnection = new MediaScannerConnection(con,mediaScannerConnectionClient);
        mediaScannerConnection.connect();
    }
      else{
            this.sendBroadcast(new Intent(
            Intent.ACTION_MEDIA_MOUNTED,
            Uri.parse("file://" + path)));
      }
    }

}

MediaScanner类如下:
private MediaScannerConnectionClient mediaScannerConnectionClient =
        new MediaScannerConnectionClient() {

        @Override
        public void onMediaScannerConnected() {
            mediaScannerConnection.scanFile(pathtonomedia, null);
        }

        @Override
        public void onScanCompleted(String path, Uri uri) {
            if(path.equals(pathtonomedia))
                mediaScannerConnection.disconnect();

        }
    };

但是代码不会刷新图库,我仍然可以在图库中看到该文件夹​​。但是,该文件夹会在10到20分钟后消失,可能是由于系统刷新。

最后我想要的是
  • 无论如何,我是否可以获得DocumentFile实例的路径?这样我就可以直接将其传递给mediascanner路径
  • 否则,我们可以通过其他方法请求对Lollipop中的特定文件夹进行扫描。该特定文件夹位于SDCARD中,我只知道其URI,而不是实际路径。

  • 非常感谢您的帮助。

    最佳答案

    如您所知,删除操作不会触发媒体扫描,并且DocumentFile Uri不适用于MediaScanner,因此在删除文件之前,您必须查询MediaScanner以获取有效路径。我要做的是遍历所有DocumentFile对象,并在它们上调用.getLastPathSegment()。返回的值如下:

    E25A-3848:Pictures/appname/images/foo.jpg
    

    在我的测试中,该值始终带有一个冒号,以将某些设备特定的值与路径的尾部分开。如果用户选择内部存储空间而不是E25A-3838,他们将得到类似primary的字眼,但这并不相关。重要的是您想获取冒号后面的所有内容,因此我像这样遍历需要删除的文档:
    String temp = document.getUri().getLastPathSegment();
    final int lastColon = temp.lastIndexOf(":");
    if (lastColon > 0) {
        boolean deletionSuccess = document.delete();
        if (deletionSuccess) {
            Log.d(TAG, "Deleted " + document.getUri());
            segmentsToDelete.add(temp.substring(lastColon + 1));
        }
    }
    

    在此循环之后,文档将消失,并且segmentsToDelete数组列表将包含所有需要从MediaScanner清除的尾随路径。因此,我进行了另一个循环,要求MediaScanner删除所有以相同值结尾的条目:
    final Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
    for (String lastPathSegment : segmentsToDelete) {
        final int result = contentResolver.delete(uri,
            MediaStore.MediaColumns.DATA + " LIKE ? ESCAPE '\\'",
            new String[]{"%" + escapedLike(lastPathSegment)}
        );
        Log.d(TAG, "Media deletion for " + lastPathSegment + " was " + result);
    }
    
    .delete()调用将返回已删除的行数,因此您可以在其中放置一个断言以确保它始终返回1。如果由于某种原因文档从未将其放入mediascanner中,则可以返回较少的断言。 escapedLike()方法是一个自定义函数,用于确保SQLITE like pattern matching与错误的路径不匹配:
    static String escapedLike(@NonNull String text)
    {
        return text.replace("%", "\\%").replace("_", "\\_");
    }
    

    当然,如果您要删除整个目录,则上述方法是相同的。在这种情况下,您不需要运行循环,可以先在DocumentFile上为目录调用.delete(),然后在构建删除查询时,将尾随%用作sql LIKE参数,该参数应返回很多删除操作(在媒体扫描仪中注册的文件数量一样多)。

    之所以使用LIKE匹配而不是确切的完整路径,是因为从DocumentFile获得的先前值永远不会匹配完整路径。像E25A-3848:Pictures/appname/images/foo.jpg这样的东西稍后将由MediaScanner数据库返回,例如/storage/sdcard1/Pictures/appname/images/foo.jpg。可惜删除未在内部调用MediaScanner ...

    关于java - 使用MediaScanner连接和从TreeUri获得的Lollipop版本的DocumentFile URI刷新画廊,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33089649/

    10-09 01:24