当前位置: 代码迷 >> 综合 >> 2022-02-26 AndroidR 11 调用文件管理器并返回选中文件的路径
  详细解决方案

2022-02-26 AndroidR 11 调用文件管理器并返回选中文件的路径

热度:5   发布时间:2023-11-27 10:45:56.0

一、Android8 调用文件管理器并返回选中文件的路径的时候可以参考这个文章。

Android中调用文件管理器并返回选中文件的路径_潘侯爷的博客-CSDN博客

二、Android11的从图标打开ExternalStorage是跟之前一样的。但是是打开Recent、Images、Downloads的时候各种问题,同样的软件在android8的时候可以运行,到Android11就不行,这里简单总结一下在Android11的时候打开浏览器的demo。

       1、打开文件管理器的效果。

       2、测试过的demo 代码如下:

package com.giada.fileexplorer;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;import java.io.File;public class MainActivity extends AppCompatActivity {TextView tv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button btn = (Button) findViewById(R.id.confirm);tv = (TextView) findViewById(R.id.textView);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Uri uri = Uri.parse("content://com.android.externalstorage.documents/document/primary:");Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);intent.addCategory(Intent.CATEGORY_OPENABLE);intent.setType("*/*");intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, uri);startActivityForResult(intent, 1);}});}String path = "NULL";@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (resultCode == Activity.RESULT_OK) {Uri uri = data.getData();if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {//4.4以后path = getPath(this, uri);tv.setText("uri.getAuthority()="+uri.getAuthority()+"   path:"+path);} else {//4.4以下下系统调用方法// path = getRealPathFromURI(uri);//tv.setText(path);// Toast.makeText(MainActivity.this, path+"222222", Toast.LENGTH_SHORT).show();}}}public String getRealPathFromURI(Uri contentUri) {String res = null;String[] proj = { MediaStore.Images.Media.DATA };Cursor cursor = getContentResolver().query(contentUri, proj, null, null, null);if(null!=cursor&&cursor.moveToFirst()){;int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);res = cursor.getString(column_index);cursor.close();}return res;}/*** 专为Android4.4设计的从Uri获取文件绝对路径,以前的方法已不好使*/@SuppressLint("NewApi")public  String getPath(final Context context, final Uri uri) {final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;// DocumentProviderif (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {// ExternalStorageProviderif (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];}}// DownloadsProviderelse if (isDownloadsDocument(uri)) {final String id = DocumentsContract.getDocumentId(uri);Log.d("FUCKFUCK", id);if (id != null && id.startsWith("raw:")) {return id.substring(4);}String[] contentUriPrefixesToTry = new String[]{"content://downloads/public_downloads","content://downloads/my_downloads"};for (String contentUriPrefix : contentUriPrefixesToTry) {Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));try {String path = getDataColumn(context, contentUri, null, null);if (path != null && !path.equals("")) {return path;}} catch (Exception e) {}}String fileName = getFileName(context, uri);if(!fileName.toLowerCase().contains("/storage/emulated/0/Download/".toLowerCase())) {fileName = "/storage/emulated/0/Download/"+fileName;}return "fileName = " +fileName;/*final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));// Toast.makeText(MainActivity.this,  " Long.valueOf(id) "+Long.valueOf(id), Toast.LENGTH_SHORT).show();return getDataColumn(context, contentUri, null, null);*/}// MediaProviderelse 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 getDataColumn(context, uri, null, null);}// Fileelse if ("file".equalsIgnoreCase(uri.getScheme())) {// return uri.getPath();}return "NULL";}public  String getFileName(@NonNull Context context, Uri uri) {String mimeType = context.getContentResolver().getType(uri);String filename = null;if (mimeType == null && context != null) {/* String path = getPath(context, uri);if (path == null) {filename = getName(uri.toString());} else {File file = new File(path);filename = file.getName();}*/} else {Cursor returnCursor = context.getContentResolver().query(uri, null,null, null, null);if (returnCursor != null) {int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);Log.d("FUCKFUCK nameIndex", ""+nameIndex);returnCursor.moveToFirst();filename = returnCursor.getString(nameIndex);returnCursor.close();}}return filename;}public  String getName(String filename) {if (filename == null) {return null;}int index = filename.lastIndexOf('/');return filename.substring(index + 1);}/*** Get the value of the data column for this Uri. This is useful for* MediaStore Uris, and other file-based ContentProviders.** @param context       The context.* @param uri           The Uri to query.* @param selection     (Optional) Filter used in the query.* @param selectionArgs (Optional) Selection arguments used in the query.* @return The value of the _data column, which is typically a file path.*/public  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 column_index = cursor.getColumnIndexOrThrow(column);return cursor.getString(column_index);}} finally {if (cursor != null)cursor.close();}return null;}/*** @param uri The Uri to check.* @return Whether the Uri authority is ExternalStorageProvider.*/public  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  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  boolean isMediaDocument(Uri uri) {return "com.android.providers.media.documents".equals(uri.getAuthority());}
}

       3、布局文件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/textView"android:text="Hello World!"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent" /><Buttonandroid:id="@+id/confirm"android:layout_width="150dp"android:layout_height="100dp"android:layout_alignParentBottom ="true"android:background="#00BCD4"android:textSize="35dp"android:text="open" /></androidx.constraintlayout.widget.ConstraintLayout>

       4、src\main\AndroidManifest.xml添加权限

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

三、测试结果

 四、过程中会遇到的问题

1、打开Download目录会提示 java.lang.IllegalArgumentException: Unknown URI: content://downloads/public_downloads/11,download目录好像比较特殊,Authority是这个com.android.providers.downloads.documents"

 解决方法,加try catch 抛出异常

2、在downlaod目录下有个很长文件名的一个文件,获取的路径只有文件名,而没有前面的路径。

 我能想到的方案,但是是最笨的解决方案,添加下面红框的内容。 

3、Android 调用系统文件管理器在指定路径目录打开文件,Android 8 以上可以使用 DocumentsContract.EXTRA_INITIAL_URI 来实现,例如指定:/sdcard/Download

Uri uri = Uri.parse("content://com.android.externalstorage.documents/document/primary:Download");
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, uri);
startActivityForResult(intent, 1);

五、参考文章

Android中调用文件管理器并返回选中文件的路径_潘侯爷的博客-CSDN博客

https://segmentfault.com/q/1010000021126126/a-1020000021139219

Uri转Path。修复java.lang.IllegalArgumentException: Unknown URI: content://downloads/public_ - 简书