Belajar Memakai Implicit Intent Di Android
10 Februari 2015 3 Komentar
Sebagai seorang pendatang baru di pemograman Android, salah satu hal unik yang saya temui adalah sebuah Activity
dapat memanggil Activity
lain di aplikasi berbeda dengan mudah melalui apa yang disebut implicit intent. Hal ini mirip seperti late binding pada DLL. Bedanya, pada sebuah perangkat Android, bisa jadi ada lebih dari satu Activity
dari aplikasi berbeda yang bisa menangani sebuah implicit intent yang sama. Pengguna bisa menentukan sendiri Activity
mana yang akan dipakai.
Sebagai latihan, saya akan membuat sebuah aplikasi Android dengan Groovy untuk menampilkan isi sebuah file dalam bentuk hexadecimal. Langkah pertama yang saya lakukan adalah membuat sebuah proyek baru Android seperti yang saya lakukan pada artikel Membuat Aplikasi Android Dengan Groovy.
Setelah itu, saya membuat sebuah Activity
dengan nama MainActivity
yang isinya seperti berikut ini:
package snake.com.myhexviewer import ... @CompileStatic public class MainActivity extends Activity { private static final int READ_REQUEST_CODE = 42 private static final int OUTPUT_VIEW_ID = View.generateViewId() @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState) TextView output = new TextView(this) output.setHorizontallyScrolling(true) output.setMovementMethod(new ScrollingMovementMethod()) output.setTypeface(Typeface.MONOSPACE) output.setTextColor(Color.GREEN) output.setId(OUTPUT_VIEW_ID) setContentView(output) } @Override boolean onCreateOptionsMenu(Menu menu) { MenuItem menuItem = menu.add("Buka File") menuItem.setIcon(android.R.drawable.ic_menu_edit) menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM) menuItem.onMenuItemClickListener = { MenuItem m -> // Pilih file yang hendak dibaca Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT) intent.addCategory(Intent.CATEGORY_OPENABLE) intent.setType('*/*') startActivityForResult(intent, READ_REQUEST_CODE) true } as MenuItem.OnMenuItemClickListener true } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if ((requestCode == READ_REQUEST_CODE) && (resultCode == Activity.RESULT_OK)) { tampilkan(data) } } private void tampilkan(Intent data) { // proses disini! } }
Karena ini adalah Activity
yang dijalankan pertama kali secara otomatis, maka saya menambahkan isi berikut ini pada AndroidManifest.xml
:
<application android:allowBackup="true" android:label="@string/app_name" android:icon="@drawable/ic_launcher"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>
Sekarang, bila saya menjalankan aplikasi, saya akan memperoleh sebuah menu di action bar yang saya buat di onCreateOptionsMenu()
. Tampilannya akan terlihat seperti pada gambar berikut ini:
Bila saya men-klik menu di action bar, maka closure yang saya berikan di onMenuItemClickListener
akan dikerjakan. Kode program ini akan memakai Storage Access Framework melalui implicit intent Intent.ACTION_OPEN_DOCUMENT
. Ini adalah fitur baru sejak Android 4.4 (KitKat) yang memungkinkan pengguna memilih file yang ada di perangkat termasuk dari Google Drive, seperti yang terlihat pada gambar berikut ini:
Walaupun activity untuk memilih file ini bukan bawaan dari aplikasi yang saya buat, ia tetap dapat dipanggil dengan menggunakan Intent.ACTION_OPEN_DOCUMENT
. Android menyediakan banyak implicit intent lainnya seperti Intent.ACTION_IMAGE_CAPTURE
, Intent.ACTION_SEND
, Intent.ACTION_VIEW
dan sebagainya. Jangan lupa bahwa bisa saja pada perangkat tertentu, tidak ada activity yang dapat menangani implicit intent yang diberikan.
Setelah activity untuk memilih file ditampilkan dan user memilih sebuah file, maka kode program di onActivityResult()
akan dikerjakan. Pada event listener tersebut, saya akan memanggil tampilkan()
untuk mengisi TextView
yang ada. Untuk itu, saya mengubah isi method tampilkan()
menjadi seperti berikut ini:
private void tampilkan(Intent data) { Uri uri = data.getData() byte[] bytes = getContentResolver().openInputStream(uri).bytes StringBuilder hexdump = new StringBuilder() StringBuilder ascii = new StringBuilder() int i for (i=0; i<bytes.length; i++) { hexdump.append(String.format("%02x", bytes[i])) hexdump.append(' ') ascii.append(Character.isLetterOrDigit(bytes[i])?(char)bytes[i]: '.') if ((i > 0) && (((i+1) % 8) == 0)) { hexdump.append(ascii.toString()) hexdump.append('\n') ascii = new StringBuilder() } } if (ascii) { (1..(8-((i-1)%8))).each { hexdump.append(' ') } hexdump.append(ascii.toString()) } TextView output = (TextView) findViewById(OUTPUT_VIEW_ID) output.setText(hexdump.toString()) }
Pada kode program di atas, saya memakai getBytes()
dari Groovy untuk langsung memperoleh byte[]
dari sebuah InputStream
. Versi yang memakai Java akan lebih panjang lagi. Bila saya menjalankan program ini dan memilih sebuah file, saya akan memperoleh hasil seperti pada gambar berikut ini:
Kode program ini belum memakai thread terpisah sehingga program akan terlihat seperti hang dan tidak responsif bila dipakai untuk membuka file dengan ukuran besar. Perhatikan juga berkat Intent.ACTION_OPEN_DOCUMENT
, saya bisa menampilkan isi dari file yang tersimpan di Google Drive.
Selain berperan untuk memakai implicit intent, sebuah aplikasi juga bisa memiliki activity yang akan menangani implicit intent dari activity lain di aplikasi yang sama maupun aplikasi berbeda yang dibuat orang lain. Sebagai latihan, saya akan menambahkan sebuah activity yang akan menangani Intent.ACTION_SEND
dari aplikasi lain. Untuk itu, saya membuat activity baru seperti berikut ini:
package snake.com.myhexviewer import ... @CompileStatic public class SendHandlerActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState) Intent mainActivityIntent = new Intent(this, MainActivity) mainActivityIntent.data = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM) startActivity(mainActivityIntent) } }
Kode program di atas akan memanggil MainActivity
dan mengirimkan Uri
kepadanya melalui setData()
. Oleh sebab itu, saya perlu menambahkan sedikit baris di MainActivity.onCreate()
di bagian akhir:
if (intent.data) { tampilkan(intent) }
Setelah itu, saya mendaftarkan activity baru ini di AndroidManifest.xml
seperti berikut:
<activity android:name=".SendHandlerActivity"> <intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="*/*" /> </intent-filter> </activity>
Untuk mengujinya, saya akan membuka sebuah gambar yang dikirimkan kepada saya melalui aplikasi BBM dan memilih menu share. Kini, aplikasi latihan yang saya buat akan muncul seperti yang terlihat pada gambar berikut ini:
Walaupun demikian, proses pengiriman data tidak berlangsung dengan sukses. Saya memperoleh pesan kesalahan seperti berikut ini:
Caused by: java.io.FileNotFoundException: /storage/emulated/0/Pictures/BBM/IMG_20150210_120722.jpg: open failed: EACCES (Permission denied)
Hal ini terjadi karena aplikasi yang saya buat tidak memiliki akses untuk membaca file di penyimpanan eksternal. Setiap aplikasi Android harus mendaftarkan permission
yang dibutuhkannya pada AndroidManifest.xml
dan nantinya pengguna perangkat yang akan menentukan apakah akan men-install aplikasi tersebut. Setelah di-install, permission
sebuah aplikasi tidak bisa diubah lagi. Untuk itu, saya menambahkan baris berikut ini pada AndroidManifest.xml
:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Sekarang, aplikasi saya bisa menerima file yang dikirim dari aplikasi lain dengan baik.
Sebagai latihan lebih lanjut, saya akan menambahkan sebuah fasilitas untuk mengirim hasil hexdump ke aplikasi lainnya yang bisa menerima data dalam bentuk plain/text
. Untuk itu, saya menambahkan kode program berikut ini pada MainActivity.onCreateOptionsMenu()
sebelum mengembalikan nilai true
:
menuItem = menu.add("Bagikan") menuItem.setIcon(android.R.drawable.ic_menu_share) menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM) menuItem.onMenuItemClickListener = { MenuItem m -> // Kirim hasil hexdump melalui Intent.ACTION_SEND String hexdump = ((TextView) findViewById(OUTPUT_VIEW_ID)).getText() Intent sendIntent = new Intent(Intent.ACTION_SEND) sendIntent.putExtra(Intent.EXTRA_TEXT, hexdump) sendIntent.setType('text/plain') startActivity(sendIntent) true } as MenuItem.OnMenuItemClickListener
Kode program di atas akan membuat sebuah icon baru di action bar seperti yang terlihat pada gambar berikut ini:
Bila saya menyentuh icon tersebut, saya bisa memilih aplikasi yang menangani Intent.ACTION_SEND
untuk tipe data text/plain
seperti yang terlihat pada gambar berikut ini:
Selain membuat menu sendiri, saya juga bisa menggunakan ShareActionProvider
yang tersedia sejak Android 4.0. Sebagai contoh, saya bisa menambahkan sebuah property pada class MainActivity
seperti:
private ShareActionProvider shareActionProvider
Setelah itu, saya mengubah kode program yang membuat menu bagikan menjadi seperti berikut ini:
menuItem = menu.add('Bagikan') menuItem.setIcon(android.R.drawable.ic_menu_share) menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM) shareActionProvider = new ShareActionProvider(this) menuItem.setActionProvider(shareActionProvider)
Terakhir, saya perlu senantiasa memperbaharui intent yang diasosiasikan dengan ShareActionProvider
. Karena hasil hexdump akan berubah setiap kali tampilkan()
dipanggil, maka saya menambahkan baris program berikut ini di akhir method tersebut:
Intent sendIntent = new Intent(Intent.ACTION_SEND) sendIntent.putExtra(Intent.EXTRA_TEXT, hexdump.toString()) sendIntent.setType('text/plain') shareActionProvider.setShareIntent(sendIntent)
Sekarang, setelah menjalankan program dan menampilkan hexdump, bila saya menyentuh icon bagikan, saya akan memperoleh hasil seperti berikut ini:
Bila saya memilih menu Lihat Semua, akan ada lebih banyak submenu yang muncul yang berisi daftar activity yang bisa menangani implicit intent yang saya buat. Terlihat bahwa penggunaan implicit intent memudahkan aplikasi saya dalam berkomunikasi dengan aplikasi lain.
Ping-balik: Multithreading Di Android | The Solid Snake
Ping-balik: Melakukan Unit Testing Di Android | The Solid Snake
Misal ada url WA Kalau biar langsung jalan ke aplikasi gimana gan?