Android 4.4 (API düzeyi 19) ve sonraki sürümleri çalıştıran cihazlarda uygulamanız etkileşimde bulunabilir bir doküman sağlayıcı ile ve bulut tabanlı depolama da dahil olmak üzere depolama alanı Erişim Çerçevesi. 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şim kurmasına olanak tanır.
Çünkü kullanıcı, uygulamanızın indireceği dosyaları veya dizinleri bu mekanizmanın çalışması için herhangi bir sistem izinleri ve kullanıcı denetimi ve gizliliği geliştirilmiştir. Ayrıca, uygulamaya özgü bir dizin ve medya mağazasının dışındaki bir dizin takip etmeniz gerekir.
Çerçeveyi kullanmak için şu adımları izlemeniz gerekir:
- Bir uygulama, depolama alanıyla ilgili bir işlem içeren bir intent çağırır. Bu işlem belirli bir kullanım alanına karşılık gelir kullanılabilir.
- Kullanıcı, doküman sağlayıcısına göz atmasına olanak tanıyan bir sistem seçici görür. ve depolamayla ilgili işlemin gerçekleştirileceği konumu veya dokümanı seçin.
- Uygulama, kullanıcının kimliğini temsil eden bir URI'ye okuma ve yazma erişimi kazanır. seçilen konumu veya dokümanı gösterir. Uygulama, bu URI'yı kullanarak şurada işlemler gerçekleştirebilir: konum açılır.
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
değerini 28
olarak ayarlayın.
Bu kılavuzda, çerçevenin dosyalar ve diğer dokümanlarla çalışmayı öğreneceğiz. Ayrıca, kullanıcı tarafından seçilen konumda işlemlerin nasıl yapılacağı da açıklanmaktadır.
Dokümanlara ve diğer dosyalara erişmek için kullanım alanları
Depolama Erişim Çerçevesi, dosyalar ve diğer dokümanlar için de geçerlidir.
- Yeni dosya oluşturma
-
ACTION_CREATE_DOCUMENT
intent işlemi, kullanıcıların bir dosyayı belirli bir konuma kaydetmesine olanak tanır. - Doküman veya dosya açma
-
ACTION_OPEN_DOCUMENT
intent işlemi, kullanıcıların açmak için belirli bir doküman veya dosya seçmesine olanak tanır. - Bir dizinin içeriğine erişim izni verme
-
ACTION_OPEN_DOCUMENT_TREE
Android 5.0 (API düzeyi 21) ve sonraki sürümlerde kullanılabilen intent işlemi belirli bir dizini seçebilir, böylece uygulamanızın tüm dosyalara ve alt dizinlerinin altında bulunabilir.
Aşağıdaki bölümlerde, her bir kullanım alanının nasıl yapılandırılacağıyla ilgili yol gösterici bilgiler verilmektedir.
Yeni dosya oluşturma
Sistem dosya seçiciyi yüklemek ve kullanıcının bir dosyanın içeriğini yazacağı yeri seçmesine izin vermek için ACTION_CREATE_DOCUMENT
intent 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 yazamaz. Uygulamanız aynı adla dosya kaydetmeye çalışırsa sistem
dosya adının sonuna parantez içinde bir sayı ekler.
Örneğin, uygulamanız confirmation.pdf
adlı bir dosyayı, zaten bu ada sahip bir dosyanın bulunduğu bir dizinde 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 ve
isteğe bağlı olarak, dosya seçicinin eklemesi gereken dosyanın veya dizinin URI'sını belirtin
ilk yüklendiğinde
EXTRA_INITIAL_URI
düşünmelisiniz.
Aşağıdaki kod snippet'i, dosya oluşturma:
// 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) }
// 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 veri girdiği depolama birimi olarak dokümanları kullanabilir paylaşmak veya başka dokümanlara aktarmak isteyebilirler. Kullanıcının bir üretkenlik dokümanı veya EPUB dosyası olarak kaydedilmiş bir kitabı açması bu etkinliklere örnek gösterilebilir.
Bu gibi durumlarda, sistemin dosya seçici uygulamasını açan ACTION_OPEN_DOCUMENT
niyetini çağırarak kullanıcının açılacak dosyayı seçmesine izin verin. Yalnızca uygulamanızın desteklediği dosya türlerini göstermek için bir MIME türü belirtin. Ayrıca isteğe bağlı olarak
dosya seçicinin, ilk açtığınızda görüntülemesi gereken dosyanın URI'sini belirtin
Şunu kullanarak yüklenir:
EXTRA_INITIAL_URI
düşünmelisiniz.
Aşağıdaki kod snippet'i, açılış PDF dokümanı:
// 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) }
// 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 bireysel seçmesini istemek için ACTION_OPEN_DOCUMENT
intent işlemi
şu dizinlerden istediğiniz dosyaları seçin:
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 dizin hiyerarşisindeki dosya gruplarını yönetir. Uygulamanızda bu özelliği sunmak 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 şunları yapabilir:
ardından seçilen dizindeki ve bu dizinlerin herhangi bir alt dizinindeki herhangi bir dosyaya erişin.
ACTION_OPEN_DOCUMENT_TREE
kullanıldığında uygulamanız yalnızca kullanıcının seçtiği dizindeki dosyalara erişebilir. Diğer
uygulamaların bu kullanıcı tarafından seçilen dizinin dışında bulunan dosyalar. Bu
Kullanıcı tarafından kontrol edilen erişim, kullanıcıların tam olarak ne tür içerikleri seçeceklerini seçmelerine olanak tanır.
rahat bir şekilde paylaşabilmenizi sağlar.
İsteğe bağlı olarak, dosya seçicinin dizine eklemesi gereken dizinin URI'sını belirtebilirsiniz.
ilk yüklendiğinde
EXTRA_INITIAL_URI
düşünmelisiniz.
Aşağıdaki kod snippet'i, dizin:
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 ) }
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
intent işlemini kullanamazsınız:
- Dahili depolama biriminin kök dizini.
- Cihaz üreticisinin belirlediği her SD kart biriminin kök dizini Kartın emülasyonu veya kullanımı olup olmadığına bakılmaksızın güvenilir kabul edilir. çıkarılabilir. Güvenilir bir birim, uygulamanın çoğu zaman başarıyla erişebildiği bir birimdir.
Download
dizini.
Ayrıca Android 11 (API düzeyi 30) ve sonraki sürümlerde, kullanıcıdan aşağıdaki dizinlerden tek tek dosya seçmesini istemek için ACTION_OPEN_DOCUMENT_TREE
intent 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ştirin
Kullanıcı, sistemin dosya seçiciyi kullanarak bir dosya veya dizin seçtikten sonra,
aşağıdaki kodu kullanarak seçilen öğenin URI'sini alabilirsiniz:
onActivityResult()
:
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. } } }
@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'sına başvurarak birkaç işlem yapabilir işlemleri gerçekleştirmelerini sağlar. Örneğin, öğenin meta verilerine erişebilir, öğeyi yerinde düzenleyebilir ve silebilir.
Aşağıdaki bölümlerde, kullanıcının seçtiği dosyalarda işlemlerin nasıl tamamlanacağı gösterilmektedir.
Bir sağlayıcının desteklediği işlemleri belirleme
Farklı içerik sağlayıcılar, farklı işlemlerin
doküman kopyalama veya dokümanın küçük resmini görüntüleme gibi yöntemlerle ilgili dokümanları oynayabilirsiniz. Belirli bir sağlayıcının hangi işlemleri desteklediğini belirlemek için Document.COLUMN_FLAGS
değerini kontrol edin.
Bu işlemin ardından uygulamanızın kullanıcı arayüzü yalnızca sağlayıcının desteklediği seçenekleri gösterebilir.
İzinleri sürdür
Uygulamanız bir dosyayı okuma veya yazmak için açtığında sistem, uygulamanıza söz konusu dosya için URI izni verir. Bu izin, kullanıcının cihazı yeniden başlatılana kadar geçerlidir. Ancak, uygulamanızın bir resim düzenleme uygulaması olduğunu ve kullanıcıların en son düzenledikleri 5 resme doğrudan erişmesini sağlayarak kaldırın. Kullanıcının cihazı yeniden başlatıldıysa kullanıcıya sistem seçiciye dönüp dosyaları bulun.
Cihaz yeniden başlatmaları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 izin vermeyi "alabilir":
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)
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);
Belge meta verilerini inceleme
Bir dokümanın URI'sına sahip olduğunuzda, dokümanın meta verilerine erişim sağlarsınız. Bu snippet, URI ile belirtilen bir dokümanın meta verilerini alır ve günlüğe kaydeder:
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") } } }
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 sahip olarak daha fazla işlem için dokümanı açabilirsiniz. Bu bölümde, bir bitmap ve giriş akışı açma örnekleri gösterilmektedir.
Bit eşlem
Aşağıdaki kod snippet'i,
Bitmap
dosyasına verilen URI:
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 }
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, bir
ImageView
.
Akış girişi
Aşağıdaki kod snippet'inde, URI'si verilen bir InputStream nesnesinin nasıl açılacağı gösterilmektedir. Bu snippet'te, dosya satırları bir dizeye okunmaktadır:
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() }
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
Bir metin dokümanındaki verileri yerinde düzenlemek için Depolama Aksesuar Çerçevesi'ni kullanabilirsiniz.
Aşağıdaki kod snippet'inde, belirtilen URI ile temsil edilen belgenin içeriğinin üzerine yazılır:
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() } }
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'sına sahipseniz ve dokümanın
Document.COLUMN_FLAGS
içerir
SUPPORTS_DELETE
,
dokümanı silebilirsiniz. Örnek:
DocumentsContract.deleteDocument(applicationContext.contentResolver, uri)
DocumentsContract.deleteDocument(applicationContext.contentResolver, uri);
Eşdeğer bir medya URI'si alma
İlgili içeriği oluşturmak için kullanılan
getMediaUri()
yöntemi, belirtilen belgelere eşdeğer bir medya mağazası URI'si sağlar
sağlayıcı URI'si. 2 URI, aynı temel öğeye işaret eder. Medya mağazası URI'sini kullanarak paylaşılan depolama alanındaki medya dosyalarına daha kolay erişebilirsiniz.
getMediaUri()
yöntemi ExternalStorageProvider
URI'ları destekler. Şu tarihte:
Android 12 (API düzeyi 31) ve sonraki sürümlere sahip yöntem, aşağıdaki sürümleri de destekler:
MediaDocumentsProvider
URI.
Sanal dosya açın
Uygulamanız, Android 7.0 (API düzeyi 25) ve sonraki sürümlerde sanal dosyaları kullanabilir
depolama alanı erişim çerçevesinin kullanılabilir hale getirdiğini doğrulayın. Sanal dosyaların ikili temsili olmasa da uygulamanız, bu dosyaları farklı bir dosya türüne zorlayarak veya ACTION_VIEW
intent işlemini kullanarak dosyaların içeriğini açabilir.
Sanal dosyaları açmak için istemci uygulamanızın, işlenecek özel bir mantık içermesi gerekir. oluşturabilirsiniz. Dosyanın bayt cinsinden gösterimini elde etmek için dosyayı önizlemek üzere örneğin, dokümanlardan alternatif bir MIME türü istemeniz gerekiyorsa için kullanılır.
Kullanıcı bir seçim yaptıktan sonra, aşağıdaki kod snippet'inde gösterildiği gibi dosyanın sanal olup olmadığını belirtin:
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 }
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 bir dosya olduğunu doğruladıktan sonra dosyayı "image/png"
gibi alternatif bir MIME türüne zorlayabilirsiniz. Aşağıdaki kod snippet'inde, bir sanal dosyanın resim olarak temsil edilip edilemeyeceğinin nasıl kontrol edileceği ve edilebildiği takdirde sanal dosyadan giriş akışı alınması gösterilmektedir:
@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() } }
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
Dokümanları ve diğer dosyaları depolama ve bunlara erişme hakkında daha fazla bilgi için aşağıdaki kaynaklara bakın.
Örnekler
- GitHub'da bulunan ActionOpenDocument.
- ActionOpenDocumentTree, GitHub'da bulabilirsiniz.