【问题标题】:Uri from Intent is different with different Devices来自 Intent 的 Uri 因设备不同而不同
【发布时间】:2019-12-15 03:47:21
【问题描述】:

我正在尝试使用 Intent.ACTION_GET_CONTENT 打开文件,就像在这篇文章中一样:

Android opening a file with ACTION_GET_CONTENT results into different Uri's

但这只是一个解决方案,如何使用不同的 SDK/文件夹而不是不同的设备获取文件名。获取 Uri 的意图也保持不变。

我想打开 .png 文件。

两个设备的 Uri.getPath() 是(两个 .png 文件都存储在下载文件夹中):

   Samsung S3 Tablet (Android 8.0): /document/559

   Samsung Galaxy S7 (Android 8.0): /document/raw:/storage/0/emulated/Download/Karte1.png

因此问题是,如果我用

初始化 InputStream
   getActivity().getContentResolver().openInputStream(uri)

它不适用于平板电脑。

这里是 Intent 代码 sn-p:

    public void browseClick() {
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("image/png");
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        try {
            startActivityForResult(Intent.createChooser(intent, 
            getString(R.string.choose_floorPlan)),REQUEST_CODE_OPEN_FILE);
        } catch (Exception ex) {
            System.out.println("browseClick :"+ex);
        }
    }

OnActivityResult:

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode != REQUEST_CODE_OPEN_FILE) {
            return;
        }
        if ((resultCode == RESULT_OK) && (data != null)) {

            try {
                selectedMap = data.getData();
                String filename = FileHelper.getUriName(selectedMap, 
                getActivity());              

                textMapDir.setText(getString(R.string.placeholder_
                folder_begin, filename));
                textMapDir.setText(selectedMap.getPath());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

在这个方法中我使用了 uri 和 openInputStream(uri)

    private boolean createFiles(String pathProjectDir, Uri selectedMap) {
    if (!ExistsDir(pathProjectDir)) { //it should be possible to add more floors/buildings to an existing project
        if (getAndCreateDir(pathProjectDir).exists()) {
            InputStream excelFile;
            InputStream mapFile;
            try {
                excelFile = Objects.requireNonNull(getActivity()).getAssets().open(EXCEL_FILE_NAME);
                mapFile = getActivity().getContentResolver().openInputStream(selectedMap);

                if (FileHelper.getMimeType(selectedMap.getPath()).equals("application/pdf")) {

                    // some code

                } else if (FileHelper.getMimeType(selectedMap.getPath()).equals("image/png")) {
                    if ((copyFile(excelFile, getExcelPath(pathProjectDir)))
                            && (copyFile(mapFile, getMapPathPNG(pathProjectDir)))) {
                        return true;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                Toast.makeText(getActivity(), getString(R.string.excel_file_unable_to_create), Toast.LENGTH_LONG).show();
                return false;
            }
        }
        Toast.makeText(getActivity(), getString(R.string.project_dir_was_not_created), Toast.LENGTH_LONG).show();
        return false;
    }
    Toast.makeText(getActivity(), getString(R.string.project_dir_exisitng), Toast.LENGTH_LONG).show();
    return false;
    }

那是 getMimeType() 方法,我从 uri 检查 MIME,这可能是问题所在:

    public static String getMimeType(String path) {
    String type = null;
    String extension = MimeTypeMap.getFileExtensionFromUrl(path);
    if (extension != null) {
        type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
    }
    return type;
}

这是我复制 InputStream 的 copyFile() 方法:

    public static Boolean copyFile(InputStream isFile, String pathOutput) {
    try {
        FileOutputStream fos = new FileOutputStream(new File(pathOutput));
        copyFileBuffer(isFile, fos);
        isFile.close();
        fos.flush();
        fos.close();
        return true;
    } catch (IOException io) {
        io.printStackTrace();
    }
    return false;
}

为了完成这里的代码是 copyFileBuffer() 方法,但这应该没问题:

    public static Boolean copyFile(InputStream isFile, String pathOutput) {
    try {
        FileOutputStream fos = new FileOutputStream(new File(pathOutput));
        copyFileBuffer(isFile, fos);
        isFile.close();
        fos.flush();
        fos.close();
        return true;
    } catch (IOException io) {
        io.printStackTrace();
    }
    return false;
}

【问题讨论】:

  • 你需要从中获取真实路径
  • @Piyush:没有“真正的路径”
  • "如果我初始化一个 InputStream... 它不适用于平板电脑" -- 您的 onActivityResult() 代码未显示使用 openInputStream()。请提供minimal reproducible example。这将包括使用openInputStream() 的代码以及关于“它不工作”的具体细节。例如,如果您正在崩溃,请提供完整的堆栈跟踪。请注意,getPath() 本身只有在 Uri 的方案是 file 时才有价值。
  • 感谢您的回答。我会提供平板电脑的确切错误,但我知道我没有,我的公司正在寻求帮助。我希望它更简单,或者任何人都面临同样的问题并有解决方案。但我很快就会拿到平板电脑并可以调试代码。我会添加更多的细节!
  • 我添加了一些代码:createFiles() 方法中的 selectedMap.getPath()).equals("image/png") 可能不适用于 uri

标签: android android-intent uri


【解决方案1】:

您必须从 uri 获取真实路径。下面是它的代码。我从关于堆栈溢出的帖子中找到它,但我没有指向它的链接。所以功劳归于发布它的人。传递上下文和uri,获取真实路径

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static String getPathFromUri(final Context context, final Uri uri) {

    final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

    // DocumentProvider
    if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
        // ExternalStorageProvider
        if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            if ("primary".equalsIgnoreCase(type)) {
                return Environment.getExternalStorageDirectory() + "/" + split[1];
            }

            // TODO handle non-primary volumes
        }
        // DownloadsProvider
        else if (isDownloadsDocument(uri)) {

            final String id = DocumentsContract.getDocumentId(uri);
            final Uri contentUri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

            return getDataColumn(context, contentUri, null, null);
        }
        // MediaProvider
        else if (isMediaDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            Uri contentUri = null;
            if ("image".equals(type)) {
                contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            } else if ("video".equals(type)) {
                contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
            } else if ("audio".equals(type)) {
                contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
            }

            final String selection = "_id=?";
            final String[] selectionArgs = new String[] {
                    split[1]
            };

            return getDataColumn(context, contentUri, selection, selectionArgs);
        }
    }
    // MediaStore (and general)
    else if ("content".equalsIgnoreCase(uri.getScheme())) {

        // Return the remote address
        if (isGooglePhotosUri(uri))
            return uri.getLastPathSegment();

        return getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }

    return null;
}

public static String getDataColumn(Context context, Uri uri, String selection,
                                   String[] selectionArgs) {

    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {
            column
    };

    try {
        cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
                null);
        if (cursor != null && cursor.moveToFirst()) {
            final int index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}


/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is ExternalStorageProvider.
 */
public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is DownloadsProvider.
 */
public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is MediaProvider.
 */
public static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is Google Photos.
 */
public static boolean isGooglePhotosUri(Uri uri) {
    return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多