В этом уроке:
- Получение файловых запросов
- Создание активити выбора файла
- Ответить на выбор файла
- Предоставление разрешений для файла
- Предоставить доступ к файлу запрашивающему приложению
Вы также должны прочитать:
После того как вы настроили свое приложение для обмена файлами с использованием URI контента, вы можете отвечать на запросы других приложений для обмена этими файлами. Один из способов ответить на эти запросы это обеспечить интерфейс выбора файла с помощью серверного приложения, который другие приложения смогут вызвать. Такой подход позволяет клиентскому приложению дать пользователю возможность выбрать файл с помощью серверного приложения, а затем получить содержимое выбранного файла используя URI.
Этот урок покажет вам, как создать Activity
для выбора файла в вашем приложении, которая реагирует на файловые запросы.
[wpanchor id=”1″]
Получение файловых запросов
Для получения запросов на файлы из клиентских приложений и отвечать с помощью URI содержимого, ваше приложение должно обеспечить выбор файлов с помощью специальнойActivity
. Клиентские приложения запускают эту Activity
с помощью вызоваstartActivityForResult()
с Intent
содержащим действие ACTION_PICK
. Когда клиентское приложение вызывает startActivityForResult()
, ваше приложение может вернуть результат в клиентскую программу в виде URI содержимого файла, выбранного пользователем.
Чтобы узнать, как реализовать запрос на получение файла в клиентском приложении, см. урок Запрос файла в android приложении.
[wpanchor id=”2″]
Создание активити выбора файла
Чтобы настроить выбор файлов через Activity
, начните с указания Activity
в вашем манифесте, наряду с фильтром интентов, который соответствует действию ACTION_PICK
и категориямCATEGORY_DEFAULT
и CATEGORY_OPENABLE
. Кроме того, добавьте фильтр MIME типа для файлов вашего приложения, которые будут использоваться в других приложениях. В следующем фрагменте показано, как указать новую Activity
и фильтр интента:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> ... <application> ... <activity android:name=".FileSelectActivity" android:label="@"File Selector" > <intent-filter> <action android:name="android.intent.action.PICK"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.OPENABLE"/> <data android:mimeType="text/plain"/> <data android:mimeType="image/*"/> </intent-filter> </activity>
Определите активити выбора файла в коде
Затем, определите Activity
подкласс, который отображает файлы доступные из каталога вашего приложения files/images/
во внутреннем хранилище, и позвольте пользователю выбрать нужный файл. В следующем фрагменте показано, как определить эту Activity
и отвечать на выбор пользователя:
public class MainActivity extends Activity { // The path to the root of this app's internal storage private File mPrivateRootDir; // The path to the "images" subdirectory private File mImagesDir; // Array of files in the images subdirectory File[] mImageFiles; // Array of filenames corresponding to mImageFiles String[] mImageFilenames; // Initialize the Activity @Override protected void onCreate(Bundle savedInstanceState) { ... // Set up an Intent to send back to apps that request a file mResultIntent = new Intent("com.example.myapp.ACTION_RETURN_FILE"); // Get the files/ subdirectory of internal storage mPrivateRootDir = getFilesDir(); // Get the files/images subdirectory; mImagesDir = new File(mPrivateRootDir, "images"); // Get the files in the images subdirectory mImageFiles = mImagesDir.listFiles(); // Set the Activity's result to null to begin with setResult(Activity.RESULT_CANCELED, null); /* * Display the file names in the ListView mFileListView. * Back the ListView with the array mImageFilenames, which * you can create by iterating through mImageFiles and * calling File.getAbsolutePath() for each File */ ... } ... }
[wpanchor id=”3″]
Ответить на выбор файла
После того, как пользователь выбирает файл, приложение должно определить, какой файл был выбран, а затем сгенерировать URI контента для файла. Поскольку Activity
отображает список доступных файлов в ListView
, когда пользователь щелкает имя файла система вызывает методonItemClick()
, в котором вы можете получить выбранный файл.
В onItemClick()
, получите File
объект для имени выбранного файла и передайте его в качестве аргумента в getUriForFile()
, вместе с авторитетным источником, который вы указали в<provider>
элементе для FileProvider
. Результирующий URI контента содержит авторитетный источник, сегмент пути соответствующего каталога, содержащего файл (как указано в мета-данных XML), а также имя файла, включая его расширение. Как FileProvider
устанавливает соответствие каталогов и сегментов пути на основе XML мета-данных описывается в разделе Укажите каталоги совместного использования
В следующем фрагменте показано, как определить выбранный файл и получить URI контента для него:
protected void onCreate(Bundle savedInstanceState) { ... // Define a listener that responds to clicks on a file in the ListView mFileListView.setOnItemClickListener( new AdapterView.OnItemClickListener() { @Override /* * When a filename in the ListView is clicked, get its * content URI and send it to the requesting app */ public void onItemClick(AdapterView<?> adapterView, View view, int position, long rowId) { /* * Get a File for the selected file name. * Assume that the file names are in the * mImageFilename array. */ File requestFile = new File(mImageFilename[position]); /* * Most file-related method calls need to be in * try-catch blocks. */ // Use the FileProvider to get a content URI try { fileUri = FileProvider.getUriForFile( MainActivity.this, "com.example.myapp.fileprovider", requestFile); } catch (IllegalArgumentException e) { Log.e("File Selector", "The selected file can't be shared: " + clickedFilename); } ... } }); ... }
Помните, что вы можете сгенерировать только URI контента для файлов, находящихся в каталогах, которые указанны в файле мета-данных, содержащем <paths>
элементы, как описано в разделе Укажите каталоги совместного использования. Если вы вызовите getUriForFile()
для File
в каталоге, который не был указан, то вы получите IllegalArgumentException
.
[wpanchor id=”4″]
Предоставление разрешений для файла
Теперь, когда у вас есть URI контента для файла, доступ к которому вы хотите предоставить другим приложениям, вам нужно позволить клиентскому приложению получить доступ к файлу. Чтобы разрешить доступ, предоставьте разрешение клиентскому приложению, добавив URI контента вIntent
, а затем установив флаги разрешений на Intent
. Предоставляемые разрешения являются временными и их срок действия истекает автоматически, когда стек задачи принимающего приложения завершается.
Следующий фрагмент кода показывает, как задать разрешение на чтение файла:
protected void onCreate(Bundle savedInstanceState) { ... // Define a listener that responds to clicks in the ListView mFileListView.setOnItemClickListener( new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long rowId) { ... if (fileUri != null) { // Grant temporary read permission to the content URI mResultIntent.addFlags( Intent.FLAG_GRANT_READ_URI_PERMISSION); } ... } ... }); ... }
Внимание: Вызов setFlags()
метода является единственным способом для безопасного предоставления доступа к файлам с помощью разрешения на временный доступ. Избегайте вызова метода Context.grantUriPermission()
для URI контента файла, так как этот метод предоставляет доступ, который вы можете отменить только вызвавContext.revokeUriPermission()
.
[wpanchor id=”5″]
Предоставить доступ к файлу запрашивающему приложению
Чтобы предоставить доступ к файлу приложению, которое его просило, передайте Intent
содержащий URI контента и разрешение в setResult()
. Когда Activity
, которую вы только что определили, завершается, система посылает Intent
, содержащий URI контента, в клиентскую программу. Следующий фрагмент кода показывает, как это сделать:
protected void onCreate(Bundle savedInstanceState) { ... // Define a listener that responds to clicks on a file in the ListView mFileListView.setOnItemClickListener( new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long rowId) { ... if (fileUri != null) { ... // Put the Uri and MIME type in the result Intent mResultIntent.setDataAndType( fileUri, getContentResolver().getType(fileUri)); // Set the result MainActivity.this.setResult(Activity.RESULT_OK, mResultIntent); } else { mResultIntent.setDataAndType(null, ""); MainActivity.this.setResult(RESULT_CANCELED, mResultIntent); } } });
Предоставьте пользователям возможность немедленно вернуться в клиентскую программу, как только они выбрали файл. Один из способов сделать это заключается в предоставлении галочки или кнопки Готово . Свяжите метод с кнопкой при помощью android:onClick
атрибута. В методе, вызовите finish()
. Например:
public void onDoneClick(View v) { // Associate a method with the Done button finish(); }