Paylaşılan depolama alanındaki dokümanlara ve diğer dosyalara erişme

Android 4.4 (API düzeyi 19) ve sonraki sürümleri çalıştıran cihazlarda uygulamanız, depolama erişim çerçevesini kullanarak harici depolama birimleri ve bulut tabanlı depolama alanı da dahil olmak üzere bir doküman sağlayıcı ile etkileşimde bulunabilir. Bu çerçeve, kullanıcıların bir doküman sağlayıcı seçmek ve uygulamanızın oluşturması, açması veya değiştirmesi için belirli dokümanları ve diğer dosyaları seçmek üzere bir sistem seçiciyle etkileşime girmesine olanak tanır.

Kullanıcı, uygulamanızın erişebileceği dosyaları veya dizinleri seçme işlemine dahil olduğundan bu mekanizma herhangi bir sistem izni gerektirmez ve kullanıcı kontrolü ile gizlilik iyileştirilir. Ayrıca, uygulamaya özel bir dizinin ve medya mağazasının dışında depolanan bu dosyalar, uygulamanızın kaldırılmasından sonra cihazda kalır.

Çerçeveyi kullanmak için aşağıdaki adımları uygulayın:

  1. Bir uygulama, depolamayla ilgili bir işlem içeren bir amaç çağırıyor. Bu işlem, çerçevenin sunduğu belirli bir kullanım alanına karşılık gelir.
  2. Kullanıcı, doküman sağlayıcıya göz atmasına ve depolamayla ilgili işlemin gerçekleşeceği konumu veya dokümanı seçmesine olanak tanıyan bir sistem seçici görür.
  3. Uygulama, kullanıcının seçtiği konumu veya belgeyi temsil eden bir URI'ye okuma ve yazma erişimi kazanır. Uygulama, bu URI'yi kullanarak seçilen konumda işlemler gerçekleştirebilir.

Android 9 (API düzeyi 28) veya daha eski sürümleri çalıştıran cihazlarda medya dosyası erişimini desteklemek için READ_EXTERNAL_STORAGE iznini beyan edin ve maxSdkVersion öğesini 28 olarak ayarlayın.

Bu kılavuzda, dosya ve diğer belgelerle çalışmak için çerçevenin desteklediği farklı kullanım alanları açıklanmaktadır. Ayrıca, kullanıcı tarafından seçilen konumda nasıl işlem yapılacağı da açıklanmaktadır.

Belgelere ve diğer dosyalara erişim için kullanım alanları

Depolama alanı erişim çerçevesi, dosyalara ve diğer belgelere erişmek için aşağıdaki kullanım alanlarını destekler.

Yeni dosya oluşturma
The ACTION_CREATE_DOCUMENT intent işlemi, kullanıcıların dosyaları belirli bir konuma kaydetmesine olanak tanır.
Doküman veya dosya açma
The ACTION_OPEN_DOCUMENT intent işlemi, kullanıcıların açılacak belirli bir dokümanı veya dosyayı seçmesine olanak tanır.
Bir dizinin içeriğine erişim izni verme
Android 5.0 (API düzeyi 21) ve sonraki sürümlerde kullanılabilen ACTION_OPEN_DOCUMENT_TREE amaç işlemi, kullanıcıların belirli bir dizini seçmesine olanak tanır. Bu sayede uygulamanız, söz konusu dizindeki tüm dosyalara ve alt dizinlere erişebilir.

Aşağıdaki bölümlerde, her bir kullanım alanının nasıl yapılandırılacağıyla ilgili yönergeler verilmektedir.

Yeni dosya oluşturma

Sistem dosya seçiciyi yüklemek ve kullanıcının dosya içeriklerinin yazılacağı bir konum seçmesine izin vermek için ACTION_CREATE_DOCUMENT amaç işlemini kullanın. Bu işlem, diğer işletim sistemlerinin kullandığı "Farklı kaydet" iletişim kutularında kullanılan işleme benzer.

Not: ACTION_CREATE_DOCUMENT mevcut bir dosyanın üzerine yazılamaz. Uygulamanız aynı ada sahip bir dosyayı kaydetmeye çalışırsa sistem, dosya adının sonuna parantez içinde bir sayı ekler.

Örneğin, uygulamanız confirmation.pdf adlı bir dosyayı, bu ada sahip bir dosyanın bulunduğu bir dizine kaydetmeye çalışırsa sistem yeni dosyayı confirmation(1).pdf adıyla kaydeder.

Amacı yapılandırırken dosyanın adını ve MIME türünü belirtin. Ayrıca, dosya seçicinin ilk yüklendiğinde göstermesi gereken dosyanın veya dizinin URI'sini EXTRA_INITIAL_URI intent ekstrasını kullanarak isteğe bağlı olarak belirtebilirsiniz.

Aşağıdaki kod snippet'inde, dosya oluşturma amaçlı intent'in nasıl oluşturulacağı ve çağrılacağı gösterilmektedir:

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);
}

Dosya aç

Uygulamanız, kullanıcıların verilerini girebileceği ve meslektaşlarıyla paylaşmak veya diğer dokümanlara aktarmak isteyebileceği bir depolama birimi olarak dokümanları kullanabilir. Örneğin, kullanıcının bir üretkenlik dokümanını veya EPUB dosyası olarak kaydedilmiş bir kitabı açması.

Bu gibi durumlarda, kullanıcının açılacak dosyayı seçmesine izin vermek için sistemin dosya seçici uygulamasını açan ACTION_OPEN_DOCUMENT amacını çağırın. Yalnızca uygulamanızın desteklediği dosya türlerini göstermek için bir MIME türü belirtin. Ayrıca, dosya seçicinin ilk yüklendiğinde göstermesi gereken dosyanın URI'sini EXTRA_INITIAL_URI intent extra'sını kullanarak isteğe bağlı olarak belirtebilirsiniz.

Aşağıdaki kod snippet'inde, PDF belgesi açma amacının nasıl oluşturulacağı ve çağrılacağı gösterilmektedir:

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);
}

Erişim kısıtlamaları

Android 11 (API düzeyi 30) ve sonraki sürümlerde, kullanıcının aşağıdaki dizinlerden tek tek dosya seçmesini istemek için ACTION_OPEN_DOCUMENT amaç işlemini kullanamazsınız:

  • Android/data/ dizini ve tüm alt dizinler.
  • Android/obb/ dizini ve tüm alt dizinler.

Bir dizinin içeriğine erişim izni verme

Dosya yönetimi ve medya oluşturma uygulamaları genellikle dosya gruplarını bir dizin hiyerarşisinde yönetir. Bu özelliği uygulamanızda sağlamak için ACTION_OPEN_DOCUMENT_TREE intent işlemini kullanın. Bu işlem, kullanıcının Android 11'den (API düzeyi 30) itibaren bazı istisnalar dışında, bir dizin ağacının tamamına erişim izni vermesine olanak tanır. Uygulamanız daha sonra seçilen dizindeki ve alt dizinlerindeki tüm dosyalara erişebilir.

ACTION_OPEN_DOCUMENT_TREE kullanılırken uygulamanız yalnızca kullanıcının seçtiği dizindeki dosyalara erişebilir. Bu kullanıcı tarafından seçilen dizinin dışında bulunan diğer uygulamaların dosyalarına erişemezsiniz. Kullanıcı kontrollü bu erişim, kullanıcıların uygulamanızla paylaşmaktan rahatsız olmayacakları içerikleri seçmelerine olanak tanır.

İsteğe bağlı olarak, EXTRA_INITIAL_URI intent ekstrasını kullanarak dosya seçicinin ilk yüklendiğinde göstermesi gereken dizinin URI'sini belirtebilirsiniz.

Aşağıdaki kod snippet'inde, bir dizini açma amaçlı işlemin nasıl oluşturulacağı ve çağrılacağı gösterilmektedir:

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);
}

Erişim kısıtlamaları

Android 11 (API düzeyi 30) ve sonraki sürümlerde, aşağıdaki dizinlere erişim isteğinde bulunmak için ACTION_OPEN_DOCUMENT_TREE amaç işlemini kullanamazsınız:

  • Dahili depolama biriminin kök dizini.
  • Kartın emüle edilmiş veya çıkarılabilir olup olmadığına bakılmaksızın, cihaz üreticisinin güvenilir olarak kabul ettiği her SD kart biriminin kök dizini. Güvenilir bir birim, uygulamanın çoğu zaman başarılı bir şekilde erişebildiği bir birimdir.
  • Download dizini.

Ayrıca, Android 11 (API düzeyi 30) ve sonraki sürümlerde, kullanıcının aşağıdaki dizinlerden tek tek dosyalar seçmesini istemek için ACTION_OPEN_DOCUMENT_TREE amaç işlemini kullanamazsınız:

  • Android/data/ dizini ve tüm alt dizinler.
  • Android/obb/ dizini ve tüm alt dizinler.

Seçilen konumda işlemler gerçekleştirme

Kullanıcı, sistemin dosya seçicisini kullanarak bir dosya veya dizin seçtikten sonra, onActivityResult() içinde aşağıdaki kodu kullanarak seçilen öğenin URI'sini alabilirsiniz:

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.
        }
    }
}

Uygulamanız, seçilen öğenin URI'sine referans alarak öğe üzerinde çeşitli işlemler gerçekleştirebilir. Örneğin, öğenin meta verilerine erişebilir, öğeyi yerinde düzenleyebilir ve silebilirsiniz.

Aşağıdaki bölümlerde, kullanıcının seçtiği dosyalarda işlemlerin nasıl tamamlanacağı gösterilmektedir.

Sağlayıcının desteklediği işlemleri belirleme

Farklı içerik sağlayıcılar, belgelerde farklı işlemlerin (ör. belgeyi kopyalama veya belgenin küçük resmini görüntüleme) yapılmasına izin verir. Belirli bir sağlayıcının hangi işlemleri desteklediğini belirlemek için Document.COLUMN_FLAGS değerini kontrol edin. Uygulamanızın kullanıcı arayüzünde yalnızca sağlayıcının desteklediği seçenekler gösterilebilir.

İzinleri kalıcı hale getirme

Uygulamanız okuma veya yazma için bir dosya açtığında sistem, kullanıcının cihazı yeniden başlatılana kadar geçerli olan bir URI izni verir. Ancak uygulamanızın bir resim düzenleme uygulaması olduğunu ve kullanıcıların en son düzenledikleri 5 resme doğrudan uygulamanızdan erişebilmesini istediğinizi varsayalım. Kullanıcının cihazı yeniden başlatıldıysa dosyaları bulmak için kullanıcıyı tekrar sistem seçiciye yönlendirmeniz gerekir.

Cihaz yeniden başlatıldığında dosyalara erişimi korumak ve daha iyi bir kullanıcı deneyimi oluşturmak için uygulamanız, aşağıdaki kod snippet'inde gösterildiği gibi sistemin sunduğu kalıcı URI izni verme işlemini "alabilir":

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);

Doküman meta verilerini inceleme

Bir belgenin URI'sine sahip olduğunuzda meta verilerine erişebilirsiniz. Bu snippet, URI ile belirtilen bir dokümanın meta verilerini alır ve bunları günlüğe kaydeder:

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();
    }
}

Doküman açma

Bir dokümanın URI'sine referans vererek dokümanı daha fazla işlemek üzere açabilirsiniz. Bu bölümde, bit eşlem ve giriş akışı açma örnekleri gösterilmektedir.

Bit eşlem

Aşağıdaki kod snippet'inde, URI'si verilen bir Bitmap dosyasının nasıl açılacağı gösterilmektedir:

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;
}

Bit eşlemi açtıktan sonra ImageView içinde görüntüleyebilirsiniz.

Giriş akışı

Aşağıdaki kod snippet'inde, URI'si verilen bir InputStream nesnesinin nasıl açılacağı gösterilmektedir. Bu snippet'te, dosyanın satırları bir dizeye okunuyor:

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();
}

Doküman düzenleme

Metin dokümanını yerinde düzenlemek için Depolama Erişim Çerçevesi'ni kullanabilirsiniz.

Aşağıdaki kod snippet'i, verilen URI ile temsil edilen belgenin içeriğinin üzerine yazar:

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();
    }
}

Doküman silme

Bir dokümanın URI'si varsa ve dokümanın Document.COLUMN_FLAGS içeriğinde SUPPORTS_DELETE varsa dokümanı silebilirsiniz. Örneğin:

Kotlin

DocumentsContract.deleteDocument(applicationContext.contentResolver, uri)

Java

DocumentsContract.deleteDocument(applicationContext.contentResolver, uri);

Eşdeğer bir medya URI'si alma

getMediaUri() yöntemi, belirtilen belgelerin sağlayıcı URI'sine eşdeğer bir medya deposu URI'si sağlar. 2 URI aynı temel öğeyi ifade eder. MediaStore URI'sini kullanarak paylaşılan depolama alanındaki medya dosyalarına daha kolay erişebilirsiniz.

getMediaUri() yöntemi, ExternalStorageProvider URI'lerini destekler. Android 12 (API düzeyi 31) ve sonraki sürümlerde yöntem, MediaDocumentsProvider URI'lerini de destekler.

Sanal dosya açma

Android 7.0 (API düzeyi 25) ve sonraki sürümlerde uygulamanız, Depolama Erişim Çerçevesi'nin kullanıma sunduğu sanal dosyalardan yararlanabilir. Sanal dosyaların ikili gösterimi olmasa da uygulamanız, bu dosyaları farklı bir dosya türüne dönüştürerek veya ACTION_VIEW amaç işlemini kullanarak görüntüleyerek içeriklerini açabilir.

Sanal dosyaları açmak için istemci uygulamanızın bu dosyaları işleyecek özel bir mantık içermesi gerekir. Dosyanın bayt gösterimini almak istiyorsanız (ör. dosyayı önizlemek için) doküman sağlayıcıdan alternatif bir MIME türü istemeniz gerekir.

Kullanıcı bir seçim yaptıktan sonra, aşağıdaki kod snippet'inde gösterildiği gibi, dosyanın sanal olup olmadığını belirlemek için sonuç verilerindeki URI'yi kullanın:

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;
}

Belgenin sanal dosya olduğunu doğruladıktan sonra dosyayı "image/png" gibi alternatif bir MIME türüne dönüştürebilirsiniz. Aşağıdaki kod snippet'inde, sanal bir dosyanın resim olarak gösterilip gösterilemeyeceğinin nasıl kontrol edileceği ve gösterilebiliyorsa sanal dosyadan nasıl giriş akışı alınacağı gösterilmektedir:

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();
}

Ek kaynaklar

Belgeleri ve diğer dosyaları depolama ve bunlara erişme hakkında daha fazla bilgi için aşağıdaki kaynaklara bakın.

Örnekler

Videolar