Proses transfer file Android Beam akan menyalin file ke direktori khusus di perangkat penerima. Proses tersebut juga memindai file yang disalin menggunakan Android Media Scanner dan menambahkan entri untuk file media ke penyedia MediaStore
. Pelajaran ini menunjukkan cara memberikan respons ketika proses penyalinan file selesai, dan cara menemukan file salinan di perangkat penerima.
Merespons permintaan untuk menampilkan data
Setelah transfer file Android Beam selesai menyalin file ke perangkat penerima, akan muncul notifikasi yang memuat Intent
dengan tindakan ACTION_VIEW
, jenis MIME file pertama yang ditransfer, dan URI yang mengarah ke file pertama. Ketika pengguna mengklik notifikasi tersebut, intent ini akan dikirim ke sistem. Agar aplikasi merespons intent ini, tambahkan elemen <intent-filter>
untuk elemen <activity>
dari Activity
yang harus merespons.
Di elemen <intent-filter>
, tambahkan elemen turunan berikut:
-
<action android:name="android.intent.action.VIEW" />
-
Mencocokkan inten
ACTION_VIEW
yang dikirim dari notifikasi. -
<category android:name="android.intent.category.CATEGORY_DEFAULT" />
-
Mencocokkan
Intent
yang tidak memiliki kategori eksplisit. -
<data android:mimeType="mime-type" />
- Mencocokkan jenis MIME. Hanya menentukan jenis MIME yang dapat ditangani aplikasi Anda.
Sebagai contoh, cuplikan berikut ini menunjukkan cara menambahkan filter intent yang memicu aktivitas com.example.android.nfctransfer.ViewActivity
:
<activity android:name="com.example.android.nfctransfer.ViewActivity" android:label="Android Beam Viewer" > ... <intent-filter> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> ... </intent-filter> </activity>
Catatan: Transfer file Android Beam bukanlah satu-satunya sumber intent ACTION_VIEW
. Aplikasi lain di perangkat penerima juga dapat mengirimkan Intent
dengan tindakan ini.
Penanganan situasi ini dibahas di bagian Mendapatkan direktori dari URI konten.
Meminta izin file
Untuk membaca file yang ditransfer oleh file Android Beam ke perangkat, minta izin READ_EXTERNAL_STORAGE
. Contoh:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Jika ingin menyalin file yang ditransfer ke area penyimpanan aplikasi Anda sendiri, minta izin WRITE_EXTERNAL_STORAGE
sebagai gantinya.
WRITE_EXTERNAL_STORAGE
mencakup READ_EXTERNAL_STORAGE
.
Catatan: Mulai Android 4.2.2 (API level 17), izin READ_EXTERNAL_STORAGE
hanya diberlakukan jika pengguna memilih untuk melakukannya. Versi platform selanjutnya mungkin memerlukan izin ini dalam semua situasi. Untuk memastikan kompatibilitas maju, minta izin tersebut sekarang sebelum diminta.
Karena aplikasi Anda dapat mengontrol area penyimpanan internalnya, Anda tidak perlu meminta izin tulis untuk menyalin file yang ditransfer ke area penyimpanan internal.
Mendapatkan direktori untuk file yang disalin
Transfer file Android Beam menyalin semua file dalam sekali transfer ke satu direktori di perangkat penerima. URI dalam Intent
konten yang dikirim oleh notifikasi transfer file Android Beam mengarah ke file pertama yang ditransfer. Namun, aplikasi Anda juga dapat menerima intent ACTION_VIEW
dari sumber selain transfer file Android Beam. Untuk menentukan bagaimana Anda harus menangani Intent
yang masuk, periksa skema dan otoritasnya.
Untuk mendapatkan skema URI, panggil Uri.getScheme()
. Cuplikan kode berikut menunjukkan cara menentukan skema dan menangani URI setelahnya:
Kotlin
class MainActivity : Activity() { ... // A File object containing the path to the transferred files private var parentPath: File? = null ... /* * Called from onNewIntent() for a SINGLE_TOP Activity * or onCreate() for a new Activity. For onNewIntent(), * remember to call setIntent() to store the most * current Intent * */ private fun handleViewIntent() { ... /* * For ACTION_VIEW, the Activity is being asked to display data. * Get the URI. */ if (TextUtils.equals(intent.action, Intent.ACTION_VIEW)) { // Get the URI from the Intent intent.data?.also { beamUri -> /* * Test for the type of URI, by getting its scheme value */ parentPath = when (beamUri.scheme) { "file" -> handleFileUri(beamUri) "content" -> handleContentUri(beamUri) else -> null } } } ... } ... }
Java
public class MainActivity extends Activity { ... // A File object containing the path to the transferred files private File parentPath; // Incoming Intent private Intent intent; ... /* * Called from onNewIntent() for a SINGLE_TOP Activity * or onCreate() for a new Activity. For onNewIntent(), * remember to call setIntent() to store the most * current Intent * */ private void handleViewIntent() { ... // Get the Intent action intent = getIntent(); String action = intent.getAction(); /* * For ACTION_VIEW, the Activity is being asked to display data. * Get the URI. */ if (TextUtils.equals(action, Intent.ACTION_VIEW)) { // Get the URI from the Intent Uri beamUri = intent.getData(); /* * Test for the type of URI, by getting its scheme value */ if (TextUtils.equals(beamUri.getScheme(), "file")) { parentPath = handleFileUri(beamUri); } else if (TextUtils.equals( beamUri.getScheme(), "content")) { parentPath = handleContentUri(beamUri); } } ... } ... }
Mendapatkan direktori dari URI file
Jika Intent
yang masuk berisi URI file, URI tersebut berisi nama absolut suatu file, termasuk jalur direktori lengkap dan nama file tersebut. Untuk transfer file Android Beam, lokasi direktorinya mengarah ke lokasi file lain yang ditransfer, jika ada. Untuk mendapatkan jalur direktori, dapatkan bagian jaluri URI, yang berisi semua URI kecuali awalan file:
. Buat File
dari bagian jalur, lalu dapatkan jalur induk File
:
Kotlin
... fun handleFileUri(beamUri: Uri): File? = // Get the path part of the URI beamUri.path.let { fileName -> // Create a File object for this filename File(fileName) // Get the file's parent directory .parentFile } ...
Java
... public File handleFileUri(Uri beamUri) { // Get the path part of the URI String fileName = beamUri.getPath(); // Create a File object for this filename File copiedFile = new File(fileName); // Get the file's parent directory return copiedFile.getParentFile(); } ...
Mendapatkan direktori dari URI konten
Jika Intent
yang masuk berisi URI konten, URI dapat mengarah ke salah satu direktori dan nama file yang tersimpan dalam penyedia konten MediaStore
. Anda dapat mendeteksi URI konten untuk MediaStore
dengan menguji nilai otoritas URI. URI konten untuk MediaStore
dapat berasal dari transfer file Android Beam atau dari aplikasi lain, tetapi dalam kedua situasi ini, Anda dapat memperoleh direktori dan nama file untuk URI konten.
Anda juga dapat menerima intent ACTION_VIEW
masuk yang berisi URI konten untuk penyedia konten selain MediaStore
. Dalam hal ini, URI konten tidak berisi nilai otoritas MediaStore
, dan URI konten biasanya tidak mengarah ke suatu direktori.
Catatan: Untuk transfer file Android Beam, Anda menerima URI konten dalam intent ACTION_VIEW
jika file pertama yang masuk memiliki jenis MIME untuk "audio/*", "image/*", atau "video/*", yang menunjukkan bahwa file tersebut terkait dengan media. Transfer file Android Beam mengindeks file media yang ditransfernya dengan menjalankan Pemindai Media pada direktori tempatnya menyimpan file yang ditransfer. Pemindai Media akan menulis hasilnya ke penyedia konten MediaStore
, lalu mengembalikan URI konten untuk file pertama ke transfer file Android Beam. URI konten ini adalah URI yang Anda terima dalam Intent
notifikasi. Untuk mendapatkan direktori file pertama, ambil dari MediaStore
menggunakan URI konten.
Menentukan penyedia konten
Untuk menentukan apakah Anda dapat mengambil direktori file dari URI konten, tentukan penyedia konten yang terkait dengan URI dengan memanggil Uri.getAuthority()
guna mendapatkan otoritas URI. Terdapat dua kemungkinan nilai untuk hasilnya:
-
MediaStore.AUTHORITY
-
URI tersebut ditujukan bagi satu atau beberapa file yang dilacak oleh
MediaStore
. Ambil nama file lengkap dariMediaStore
dan dapatkan direktori dari nama file tersebut. - Nilai otoritas lainnya
- URI konten dari penyedia konten lain. Tampilkan data yang terkait dengan URI konten, tetapi jangan dapatkan direktori file.
Guna mendapatkan direktori untuk URI konten MediaStore
, jalankan kueri yang menentukan URI konten yang masuk untuk argumen Uri
dan kolom MediaColumns.DATA
untuk proyeksi. Cursor
yang ditampilkan berisi jalur dan nama lengkap untuk file yang direpresentasikan oleh URI. Jalur ini juga berisi semua file lain yang baru saja disalin oleh transfer file Android Beam ke perangkat.
Cuplikan berikut menunjukkan cara menguji otoritas URI konten serta mendapatkan jalur dan nama file untuk file yang ditransfer:
Kotlin
... private fun handleContentUri(beamUri: Uri): File? = // Test the authority of the URI if (beamUri.authority == MediaStore.AUTHORITY) { /* * Handle content URIs for other content providers */ ... // For a MediaStore content URI } else { // Get the column that contains the file name val projection = arrayOf(MediaStore.MediaColumns.DATA) val pathCursor = contentResolver.query(beamUri, projection, null, null, null) // Check for a valid cursor if (pathCursor?.moveToFirst() == true) { // Get the column index in the Cursor pathCursor.getColumnIndex(MediaStore.MediaColumns.DATA).let { filenameIndex -> // Get the full file name including path pathCursor.getString(filenameIndex).let { fileName -> // Create a File object for the filename File(fileName) }.parentFile // Return the parent directory of the file } } else { // The query didn't work; return null null } } ...
Java
... public String handleContentUri(Uri beamUri) { // Position of the filename in the query Cursor int filenameIndex; // File object for the filename File copiedFile; // The filename stored in MediaStore String fileName; // Test the authority of the URI if (!TextUtils.equals(beamUri.getAuthority(), MediaStore.AUTHORITY)) { /* * Handle content URIs for other content providers */ // For a MediaStore content URI } else { // Get the column that contains the file name String[] projection = { MediaStore.MediaColumns.DATA }; Cursor pathCursor = getContentResolver().query(beamUri, projection, null, null, null); // Check for a valid cursor if (pathCursor != null && pathCursor.moveToFirst()) { // Get the column index in the Cursor filenameIndex = pathCursor.getColumnIndex( MediaStore.MediaColumns.DATA); // Get the full file name including path fileName = pathCursor.getString(filenameIndex); // Create a File object for the filename copiedFile = new File(fileName); // Return the parent directory of the file return copiedFile.getParentFile(); } else { // The query didn't work; return null return null; } } } ...
Untuk mempelajari lebih lanjut cara mengambil data dari penyedia konten, lihat bagian Mengambil data dari penyedia.
Untuk informasi terkait lainnya, lihat: