Dostęp do dokumentów i innych plików z pamięci współdzielonej

Na urządzeniach z Androidem 4.4 (poziom interfejsu API 19) lub nowszym aplikacja może wchodzić w interakcje z dostawcą dokumentów, w tym woluminy pamięci zewnętrznej i miejsca w chmurze, z użyciem funkcji Platforma dostępu. Ta platforma umożliwia użytkownikom interakcję z selektorem systemu aby wybrać dostawcę dokumentów i określone dokumenty oraz inne pliki w aplikacji, aby ją utworzyć, otworzyć lub zmodyfikować.

Ponieważ użytkownik bierze udział w wyborze plików lub katalogów aplikacji nie może uzyskać dostępu, jednak ten mechanizm nie wymaga żadnego systemu uprawnień oraz kontroli i prywatności użytkowników jest ulepszony. Dodatkowo pliki te są przechowywane poza w katalogu aplikacji i poza sklepem multimedialnym, pozostaną na urządzeniu. po odinstalowaniu aplikacji.

Aby korzystać z platformy, wykonaj te czynności:

  1. Aplikacja wywołuje intencję, która zawiera działanie związane z pamięcią. To działanie odpowiada konkretnemu przypadkowi użycia platformy i dostępności informacji.
  2. Użytkownik widzi selektor systemowy, który umożliwia przeglądanie dostawcy dokumentów i wybierz lokalizację lub dokument, w którym ma nastąpić działanie związane z przechowywaniem.
  3. Aplikacja uzyskuje uprawnienia do odczytu i zapisu do identyfikatora URI reprezentującego wybranej lokalizacji lub dokumentu. Za pomocą tego identyfikatora URI aplikacja może wykonywać operacje na w wybranej lokalizacji.
.

aby obsługiwać dostęp do plików multimedialnych na urządzeniach z Androidem 9 (poziom interfejsu API 28) lub poniżej, zadeklaruj READ_EXTERNAL_STORAGE i ustaw maxSdkVersion na 28.

W tym przewodniku objaśniamy różne przypadki użycia obsługiwane przez platformę pracy z plikami i innymi dokumentami. Podaje też, jak osiągnąć na wybranej przez użytkownika lokalizacji.

Przypadki użycia dostępu do dokumentów i innych plików

Platforma dostępu do pamięci masowej obsługuje poniższe przypadki użycia pliki i inne dokumenty.

Tworzenie nowego pliku
ACTION_CREATE_DOCUMENT. działanie intencji pozwala użytkownikom zapisać plik w określonej lokalizacji.
Otwieranie dokumentu lub pliku
ACTION_OPEN_DOCUMENT. działanie intencji pozwala użytkownikom wybrać konkretny dokument lub plik do otwarcia.
Przyznawanie dostępu do zawartości katalogu
ACTION_OPEN_DOCUMENT_TREE. działanie intencji, dostępne na Androidzie 5.0 (poziom interfejsu API 21) i nowszym, pozwala użytkownikom aby wybrać konkretny katalog i przyznać aplikacji dostęp do wszystkich podkatalogów w danym katalogu.

W sekcjach poniżej znajdziesz wskazówki dotyczące konfigurowania poszczególnych przypadków użycia.

Tworzenie nowego pliku

Użyj ACTION_CREATE_DOCUMENT działanie intencji, które wczytuje systemowy selektor plików i umożliwia użytkownikowi wybranie lokalizację, w której można zapisać zawartość pliku. Ten proces jest podobny do jeden używany w funkcji „zapisz jako” okien dialogowych używanych w innych systemach operacyjnych.

Uwaga: ACTION_CREATE_DOCUMENT nie może zastąpić już istniejący plik. Jeśli aplikacja spróbuje zapisać plik o tej samej nazwie, system dodaje liczbę w nawiasach na końcu nazwy pliku.

Jeśli na przykład aplikacja próbuje zapisać plik o nazwie confirmation.pdf jest w katalogu, który ma już plik z tym elementem system zapisze nowy plik o nazwie confirmation(1).pdf

Podczas konfigurowania intencji określ nazwę pliku i typ MIME. opcjonalnie podaj identyfikator URI pliku lub katalogu, który selektor plików można wyświetlić przy pierwszym wczytaniu, używając EXTRA_INITIAL_URI intencja użytkownika.

Fragment kodu poniżej pokazuje, jak utworzyć i wywołać intencję dla utworzenie pliku:

Kotlin

// Request code for creating a PDF document.
const val CREATE_FILE = 1

private fun createFile(pickerInitialUri: Uri) {
    val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
        addCategory(Intent.CATEGORY_OPENABLE)
        type = "application/pdf"
        putExtra(Intent.EXTRA_TITLE, "invoice.pdf")

        // Optionally, specify a URI for the directory that should be opened in
        // the system file picker before your app creates the document.
        putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri)
    }
    startActivityForResult(intent, CREATE_FILE)
}

Java

// Request code for creating a PDF document.
private static final int CREATE_FILE = 1;

private void createFile(Uri pickerInitialUri) {
    Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("application/pdf");
    intent.putExtra(Intent.EXTRA_TITLE, "invoice.pdf");

    // Optionally, specify a URI for the directory that should be opened in
    // the system file picker when your app creates the document.
    intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);

    startActivityForResult(intent, CREATE_FILE);
}

Otwórz plik

Aplikacja może używać dokumentów jako jednostki pamięci, w której użytkownicy zapisują dane aby udostępnić je innym lub zaimportować do innych dokumentów. Kilka Przykłady to m.in. użytkownik, który otwiera dokument dotyczący produktywności lub książkę, zapisane jako plik EPUB.

W takich przypadkach pozwól użytkownikowi wybrać plik do otwarcia, wywołując metodę ACTION_OPEN_DOCUMENT który otwiera systemową aplikację z selektorem plików. Aby wyświetlić tylko typy obsługiwanych przez aplikację, wybierz typ MIME. Opcjonalnie możesz też określ identyfikator URI pliku, który selektor plików ma wyświetlić po pierwszym otwarciu ładuje się za pomocą EXTRA_INITIAL_URI intencja użytkownika.

Fragment kodu poniżej pokazuje, jak utworzyć i wywołać intencję otwarcia dokument PDF:

Kotlin

// Request code for selecting a PDF document.
const val PICK_PDF_FILE = 2

fun openFile(pickerInitialUri: Uri) {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
        addCategory(Intent.CATEGORY_OPENABLE)
        type = "application/pdf"

        // Optionally, specify a URI for the file that should appear in the
        // system file picker when it loads.
        putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri)
    }

    startActivityForResult(intent, PICK_PDF_FILE)
}

Java

// Request code for selecting a PDF document.
private static final int PICK_PDF_FILE = 2;

private void openFile(Uri pickerInitialUri) {
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("application/pdf");

    // Optionally, specify a URI for the file that should appear in the
    // system file picker when it loads.
    intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);

    startActivityForResult(intent, PICK_PDF_FILE);
}

Ograniczenia dostępu

Na Androidzie 11 (poziom interfejsu API 30) i nowszym nie można używać funkcji ACTION_OPEN_DOCUMENT działanie zamiarowe, aby użytkownik wybrał inną osobę w następujących katalogach:

  • Katalog Android/data/ i wszystkie podkatalogi.
  • Katalog Android/obb/ i wszystkie podkatalogi.

Przyznawanie dostępu do zawartości katalogu

Aplikacje do zarządzania plikami i tworzenia multimediów zwykle zarządzają grupami plików hierarchii katalogów. Aby udostępnić tę funkcję w aplikacji, skorzystaj z ACTION_OPEN_DOCUMENT_TREE działanie intencji, które umożliwia użytkownikowi przyznanie dostępu do całego katalogu drzewo z kilkoma wyjątkami od Androida 11 (poziom interfejsu API 30). Aplikacja może a następnie uzyskać dostęp do dowolnego pliku w wybranym katalogu i jego podkatalogach.

Gdy używasz funkcji ACTION_OPEN_DOCUMENT_TREE, aplikacja uzyska dostęp tylko do w katalogu wybranym przez użytkownika. Nie masz dostępu do innych aplikacji aplikacji plików znajdujących się poza tym katalogiem wybranym przez użytkownika. Ten dostęp kontrolowany przez użytkowników pozwala użytkownikom dokładnie wybrać, jakie treści chcą oglądać udostępnianie swojej aplikacji.

Opcjonalnie możesz podać identyfikator URI katalogu, który powinien być używany przez selektor plików można wyświetlić przy pierwszym wczytaniu, używając EXTRA_INITIAL_URI intencja użytkownika.

Fragment kodu poniżej pokazuje, jak utworzyć i wywołać intencję otwarcia katalog:

Kotlin

fun openDirectory(pickerInitialUri: Uri) {
    // Choose a directory using the system's file picker.
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
        // Optionally, specify a URI for the directory that should be opened in
        // the system file picker when it loads.
        putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri)
    }

    startActivityForResult(intent, your-request-code)
}

Java

public void openDirectory(Uri uriToLoad) {
    // Choose a directory using the system's file picker.
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);

    // Optionally, specify a URI for the directory that should be opened in
    // the system file picker when it loads.
    intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, uriToLoad);

    startActivityForResult(intent, your-request-code);
}

Ograniczenia dostępu

Na Androidzie 11 (poziom interfejsu API 30) i nowszym nie można używać funkcji ACTION_OPEN_DOCUMENT_TREE działanie intencji, które prosi o dostęp do tych elementów katalogi:

  • Katalog główny woluminu pamięci wewnętrznej.
  • Katalog główny woluminu karty SD używanego przez producenta urządzenia uważany jest za niezawodny, niezależnie od tego, czy karta jest emulowana, lub ich usunięcia. Niezawodny wolumin to taki, do którego aplikacja ma dostęp do większości w określonym czasie.
  • Katalog Download.

Ponadto w Androidzie 11 (poziom interfejsu API 30) i nowszych nie można używać funkcji ACTION_OPEN_DOCUMENT_TREE działanie intencji, które prosi użytkownika o wybór z poszczególnych plików z tych katalogów:

  • Katalog Android/data/ i wszystkie podkatalogi.
  • Katalog Android/obb/ i wszystkie podkatalogi.

Wykonywanie operacji na wybranej lokalizacji

Gdy użytkownik wybierze plik lub katalog w systemowym selektorze plików, możesz pobrać identyfikator URI wybranego elementu przy użyciu poniższego kodu w sekcji onActivityResult():

Kotlin

override fun onActivityResult(
        requestCode: Int, resultCode: Int, resultData: Intent?) {
    if (requestCode == your-request-code
            && resultCode == Activity.RESULT_OK) {
        // The result data contains a URI for the document or directory that
        // the user selected.
        resultData?.data?.also { uri ->
            // Perform operations on the document using its URI.
        }
    }
}

Java

@Override
public void onActivityResult(int requestCode, int resultCode,
        Intent resultData) {
    if (requestCode == your-request-code
            && resultCode == Activity.RESULT_OK) {
        // The result data contains a URI for the document or directory that
        // the user selected.
        Uri uri = null;
        if (resultData != null) {
            uri = resultData.getData();
            // Perform operations on the document using its URI.
        }
    }
}

Dzięki odniesieniu do identyfikatora URI wybranego elementu aplikacja może wykonywać kilka na elemencie. Możesz na przykład uzyskać dostęp do metadanych elementu, edytować element w danym miejscu, a następnie go usuń.

W poniższych sekcjach znajdziesz informacje o tym, jak wykonywać działania na plikach, które użytkownik wybierze te opcje.

Określ operacje obsługiwane przez dostawcę

Różni dostawcy treści pozwalają na wykonywanie odmiennych działań dokumentów, na przykład przez skopiowanie dokumentu lub wyświetlenie jego miniatury. Do Określanie operacji obsługiwanych przez danego dostawcę, sprawdzanie wartości Document.COLUMN_FLAGS Interfejs aplikacji może wtedy wyświetlać tylko opcje obsługiwane przez dostawcę.

Zachowaj uprawnienia

Gdy aplikacja otworzy plik do odczytu lub zapisu, system udostępni jej uprawnienia do identyfikatora URI przyznane do tego pliku (do momentu, gdy urządzenie użytkownika korzysta z tego identyfikatora); uruchomi się ponownie. Załóżmy jednak, że Twoja aplikacja jest przeznaczona do edycji obrazów i chcesz użytkownicy mają dostęp do 5 ostatnio edytowanych obrazów bezpośrednio z aplikacji. Jeśli urządzenie użytkownika zostało ponownie uruchomione, musisz wysłać do niego informacje wróć do selektora systemowego, aby znaleźć pliki.

Aby zachować dostęp do plików na różnych urządzeniach po ponownym uruchomieniu i utworzyć lepsze konto użytkownika aplikacja może „przyjąć” trwałe uprawnienie identyfikatora URI przyznaje, jak w poniższym fragmencie kodu:

Kotlin

val contentResolver = applicationContext.contentResolver

val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or
        Intent.FLAG_GRANT_WRITE_URI_PERMISSION
// Check for the freshest data.
contentResolver.takePersistableUriPermission(uri, takeFlags)

Java

final int takeFlags = intent.getFlags()
            & (Intent.FLAG_GRANT_READ_URI_PERMISSION
            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// Check for the freshest data.
getContentResolver().takePersistableUriPermission(uri, takeFlags);

Sprawdzanie metadanych dokumentu

Dostęp do metadanych dokumentu uzyskasz, jeśli masz identyfikator URI dokumentu. Ten pobiera metadane dokumentu określonego przez identyfikator URI i zapisuje je w dzienniku:

Kotlin

val contentResolver = applicationContext.contentResolver

fun dumpImageMetaData(uri: Uri) {

    // The query, because it only applies to a single document, returns only
    // one row. There's no need to filter, sort, or select fields,
    // because we want all fields for one document.
    val cursor: Cursor? = contentResolver.query(
            uri, null, null, null, null, null)

    cursor?.use {
        // moveToFirst() returns false if the cursor has 0 rows. Very handy for
        // "if there's anything to look at, look at it" conditionals.
        if (it.moveToFirst()) {

            // Note it's called "Display Name". This is
            // provider-specific, and might not necessarily be the file name.
            val displayName: String =
                    it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
            Log.i(TAG, "Display Name: $displayName")

            val sizeIndex: Int = it.getColumnIndex(OpenableColumns.SIZE)
            // If the size is unknown, the value stored is null. But because an
            // int can't be null, the behavior is implementation-specific,
            // and unpredictable. So as
            // a rule, check if it's null before assigning to an int. This will
            // happen often: The storage API allows for remote files, whose
            // size might not be locally known.
            val size: String = if (!it.isNull(sizeIndex)) {
                // Technically the column stores an int, but cursor.getString()
                // will do the conversion automatically.
                it.getString(sizeIndex)
            } else {
                "Unknown"
            }
            Log.i(TAG, "Size: $size")
        }
    }
}

Java

public void dumpImageMetaData(Uri uri) {

    // The query, because it only applies to a single document, returns only
    // one row. There's no need to filter, sort, or select fields,
    // because we want all fields for one document.
    Cursor cursor = getActivity().getContentResolver()
            .query(uri, null, null, null, null, null);

    try {
        // moveToFirst() returns false if the cursor has 0 rows. Very handy for
        // "if there's anything to look at, look at it" conditionals.
        if (cursor != null && cursor.moveToFirst()) {

            // Note it's called "Display Name". This is
            // provider-specific, and might not necessarily be the file name.
            String displayName = cursor.getString(
                    cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
            Log.i(TAG, "Display Name: " + displayName);

            int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
            // If the size is unknown, the value stored is null. But because an
            // int can't be null, the behavior is implementation-specific,
            // and unpredictable. So as
            // a rule, check if it's null before assigning to an int. This will
            // happen often: The storage API allows for remote files, whose
            // size might not be locally known.
            String size = null;
            if (!cursor.isNull(sizeIndex)) {
                // Technically the column stores an int, but cursor.getString()
                // will do the conversion automatically.
                size = cursor.getString(sizeIndex);
            } else {
                size = "Unknown";
            }
            Log.i(TAG, "Size: " + size);
        }
    } finally {
        cursor.close();
    }
}

Otwieranie dokumentu

Dokument możesz otworzyć, korzystając z odniesienia do jego identyfikatora URI o przetwarzaniu danych. Ta sekcja pokazuje przykłady otwierania bitmapy i danych wejściowych .

Bitmapa

Fragment kodu poniżej pokazuje, jak otworzyć plik Bitmap z podanym identyfikatorem URI:

Kotlin

val contentResolver = applicationContext.contentResolver

@Throws(IOException::class)
private fun getBitmapFromUri(uri: Uri): Bitmap {
    val parcelFileDescriptor: ParcelFileDescriptor =
            contentResolver.openFileDescriptor(uri, "r")
    val fileDescriptor: FileDescriptor = parcelFileDescriptor.fileDescriptor
    val image: Bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor)
    parcelFileDescriptor.close()
    return image
}

Java

private Bitmap getBitmapFromUri(Uri uri) throws IOException {
    ParcelFileDescriptor parcelFileDescriptor =
            getContentResolver().openFileDescriptor(uri, "r");
    FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
    Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
    parcelFileDescriptor.close();
    return image;
}

Po otwarciu bitmapy możesz wyświetlić ją w ImageView

Strumień wejściowy

Poniższy fragment kodu pokazuje, jak otworzyć obiekt w usłudzeinputStream z uwzględnieniem jego argumentu Identyfikator URI. W tym fragmencie wiersze pliku są odczytywane w postaci ciągu znaków:

Kotlin

val contentResolver = applicationContext.contentResolver

@Throws(IOException::class)
private fun readTextFromUri(uri: Uri): String {
    val stringBuilder = StringBuilder()
    contentResolver.openInputStream(uri)?.use { inputStream ->
        BufferedReader(InputStreamReader(inputStream)).use { reader ->
            var line: String? = reader.readLine()
            while (line != null) {
                stringBuilder.append(line)
                line = reader.readLine()
            }
        }
    }
    return stringBuilder.toString()
}

Java

private String readTextFromUri(Uri uri) throws IOException {
    StringBuilder stringBuilder = new StringBuilder();
    try (InputStream inputStream =
            getContentResolver().openInputStream(uri);
            BufferedReader reader = new BufferedReader(
            new InputStreamReader(Objects.requireNonNull(inputStream)))) {
        String line;
        while ((line = reader.readLine()) != null) {
            stringBuilder.append(line);
        }
    }
    return stringBuilder.toString();
}

Edytowanie dokumentu

Dokument tekstowy możesz też edytować za pomocą platformy Storage Access Framework.

Ten fragment kodu zastępuje treść reprezentowanego dokumentu według danego identyfikatora URI:

Kotlin

val contentResolver = applicationContext.contentResolver

private fun alterDocument(uri: Uri) {
    try {
        contentResolver.openFileDescriptor(uri, "w")?.use {
            FileOutputStream(it.fileDescriptor).use {
                it.write(
                    ("Overwritten at ${System.currentTimeMillis()}\n")
                        .toByteArray()
                )
            }
        }
    } catch (e: FileNotFoundException) {
        e.printStackTrace()
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

Java

private void alterDocument(Uri uri) {
    try {
        ParcelFileDescriptor pfd = getActivity().getContentResolver().
                openFileDescriptor(uri, "w");
        FileOutputStream fileOutputStream =
                new FileOutputStream(pfd.getFileDescriptor());
        fileOutputStream.write(("Overwritten at " + System.currentTimeMillis() +
                "\n").getBytes());
        // Let the document provider know you're done by closing the stream.
        fileOutputStream.close();
        pfd.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Usuwanie dokumentu

Jeśli znasz identyfikator URI dokumentu oraz Document.COLUMN_FLAGS zawiera SUPPORTS_DELETE, możesz usunąć ten dokument. Na przykład:

Kotlin

DocumentsContract.deleteDocument(applicationContext.contentResolver, uri)

Java

DocumentsContract.deleteDocument(applicationContext.contentResolver, uri);

Pobierz równoważny identyfikator URI multimediów

getMediaUri() udostępnia identyfikator URI magazynu multimediów, który jest równoważny z podanymi dokumentami identyfikatora URI dostawcy. Oba identyfikatory URI odnoszą się do tego samego elementu podstawowego. Korzystanie z multimediów identyfikatora URI sklepu, łatwiej dostęp do plików multimedialnych z miejsca na dane.

Metoda getMediaUri() obsługuje identyfikatory URI ExternalStorageProvider. Wł. Androida 12 (poziom interfejsu API 31) lub nowszego; metoda obsługuje też Identyfikatory URI MediaDocumentsProvider.

Otwieranie pliku wirtualnego

W Androidzie 7.0 (poziom interfejsu API 25) i nowszych aplikacja może korzystać z plików wirtualnych które udostępnia platforma Storage Access Framework. Mimo że pliki wirtualne nie ma reprezentacji binarnej, aplikacja może otworzyć swoją zawartość przez przymus ich do innego typu lub wyświetlając je za pomocą Zamiar ACTION_VIEW działania.

Aby można było otwierać pliki wirtualne, aplikacja kliencka musi zawierać specjalną logikę do obsługi . Jeśli chcesz zapisać plik w postaci bajtów (podgląd pliku), na przykład – musisz poprosić o alternatywny typ MIME z dokumentów. dostawcy usług.

Gdy użytkownik dokona wyboru, użyj identyfikatora URI w danych wyników, aby określić w przypadku plików wirtualnych, zgodnie z tym fragmentem kodu:

Kotlin

private fun isVirtualFile(uri: Uri): Boolean {
    if (!DocumentsContract.isDocumentUri(this, uri)) {
        return false
    }

    val cursor: Cursor? = contentResolver.query(
            uri,
            arrayOf(DocumentsContract.Document.COLUMN_FLAGS),
            null,
            null,
            null
    )

    val flags: Int = cursor?.use {
        if (cursor.moveToFirst()) {
            cursor.getInt(0)
        } else {
            0
        }
    } ?: 0

    return flags and DocumentsContract.Document.FLAG_VIRTUAL_DOCUMENT != 0
}

Java

private boolean isVirtualFile(Uri uri) {
    if (!DocumentsContract.isDocumentUri(this, uri)) {
        return false;
    }

    Cursor cursor = getContentResolver().query(
        uri,
        new String[] { DocumentsContract.Document.COLUMN_FLAGS },
        null, null, null);

    int flags = 0;
    if (cursor.moveToFirst()) {
        flags = cursor.getInt(0);
    }
    cursor.close();

    return (flags & DocumentsContract.Document.FLAG_VIRTUAL_DOCUMENT) != 0;
}

Po potwierdzeniu, że dokument jest plikiem wirtualnym, możesz zmienić metodę do innego typu MIME, np. "image/png". Następujący kod: pokazuje, jak sprawdzić, czy plik wirtualny może być reprezentowany obrazu. Jeśli tak, pobierany jest strumień danych wejściowych z pliku wirtualnego:

Kotlin

@Throws(IOException::class)
private fun getInputStreamForVirtualFile(
        uri: Uri, mimeTypeFilter: String): InputStream {

    val openableMimeTypes: Array<String>? =
            contentResolver.getStreamTypes(uri, mimeTypeFilter)

    return if (openableMimeTypes?.isNotEmpty() == true) {
        contentResolver
                .openTypedAssetFileDescriptor(uri, openableMimeTypes[0], null)
                .createInputStream()
    } else {
        throw FileNotFoundException()
    }
}

Java

private InputStream getInputStreamForVirtualFile(Uri uri, String mimeTypeFilter)
    throws IOException {

    ContentResolver resolver = getContentResolver();

    String[] openableMimeTypes = resolver.getStreamTypes(uri, mimeTypeFilter);

    if (openableMimeTypes == null ||
        openableMimeTypes.length < 1) {
        throw new FileNotFoundException();
    }

    return resolver
        .openTypedAssetFileDescriptor(uri, openableMimeTypes[0], null)
        .createInputStream();
}

Dodatkowe materiały

Więcej informacji o przechowywaniu dokumentów i innych plikach oraz uzyskiwanie do nich dostępu zapoznaj się z tymi materiałami.

Próbki

Filmy