android - 如何从 Android Q 中的 contentResolver.openFileDescriptor(Uri uri, String s) 获取媒体项 real_Path?

标签 android file-descriptor android-contentresolver mediastore

MediaStore.MediaColumns.DATA 常量在 API 级别 Q 中已弃用。

应用程序可能没有直接访问此路径的文件系统权限。应用程序不应尝试直接打开此路径,而应使用 ContentResolver#openFileDescriptor(Uri, String) 来获得访问权限。对于面向 Build.VERSION_CODES.Q 或更高版本的应用,此值将始终为 NULL。

最佳答案

这是真的,我们无法获得真正的路径。只是简单的方法用 contentResolver() 打开流并将文件的全部内容复制到新文件中,为了获取文件信息,我们需要调用 getContentResolver().query() 的 query() 方法,然后我们可以获得文件的 DISPLAY_NAME以及更多信息,例如 FILE_SIZE。

对问题投赞成票的人的简单代码示例:

public class MainFragment extends Fragment {

    private Button openGallery;
    private File selectedFile;
    private Context context;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        context = container.getContext();
        return inflater.inflate(R.layout.fragment_question, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        openGallery = view.findViewById(R.id.openGallery);
        openGallery.setOnClickListener(v->browseFile());
    }


    private void browseFile() {

        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
            openFiles();
        } else {
            requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 786);
        }
    }

    private void openFiles() {

        deleteFileFromCacheDir();

        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("*/*");
        intent.addCategory(Intent.CATEGORY_OPENABLE);

        if (intent.resolveActivity(context.getPackageManager()) != null) {
            startActivityForResult(intent, 786);
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == 786 && resultCode == -1 && data != null) {

            Uri uri = data.getData();
            openStreamAndCopyContent(uri); // Here i am just copy the content of file and paste it into my new file. You can check the type of the file image/video/audio & do it whatever you want

            // Now here is your file

            if (selectedFile != null && selectedFile.exists()){
                // Do it whatever you want Or send it to server 
            } 

        }

    }

    private void openStreamAndCopyContent(Uri uri) {

        try {

            String fileName = "temp" + System.currentTimeMillis() + "." + MimeTypeMap.getSingleton().getExtensionFromMimeType(context.getContentResolver().getType(uri));
            selectedFile = new File(context.getCacheDir().getAbsolutePath() + File.separator + fileName);

            InputStream inputStream = context.getContentResolver().openInputStream(uri);

            if (inputStream != null) {
                Utility.copy(inputStream, selectedFile);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode == 786) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                openFiles();
            } else if (grantResults[0] == PackageManager.PERMISSION_DENIED && getActivity() != null) {

                if (!ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)) {

                    new AlertDialog.Builder(context).setTitle(R.string.permission_required).setMessage(R.string.permission_message)
                            .setPositiveButton(R.string.open_settings, (dialog, which) ->
                                    context.startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                                            Uri.parse("package:" + BuildConfig.APPLICATION_ID)))).setNegativeButton(R.string.close, null).show();
                }
            }
        }
    }


    private void deleteFileFromCacheDir() {

        if (selectedFile != null && selectedFile.exists()) {
            if (selectedFile.delete()) {
                selectedFile = null;
            }
        }
    }

    @Override
    public void onDestroyView() {

        deleteFileFromCacheDir();

        super.onDestroyView();
    }



    }

关于android - 如何从 Android Q 中的 contentResolver.openFileDescriptor(Uri uri, String s) 获取媒体项 real_Path?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55796224/

相关文章:

java - Android线程池管理多个蓝牙处理线程?

android - 使用gradle引用Android Core App中的aosp函数

node.js - 使用 React 和 Golang 进行服务器端渲染

java - 如何按即将到来的生日顺序获取联系人?

android - AsyncQueryHandler 批量插入

Android以编程方式添加两个带有 Canvas 的 View

java - Android recyclerview 像画廊 View 吗?

c - 如果 isatty(1) 为 1,则获取文件描述符

python - 有没有办法获取 'own' 或 'get priority over' linux 中外部进程的 stdin 文件描述符?

android - 权限拒绝 : opening provider Android Studio