1
Apa yang Anda Pelajari di Fudamental
Android dengan Kotlin (Part 6)
• You will learn to:
• Navigasi
• Loader
2
Navigasi
• Anda telah mempelajari navigasi pada semester
sebelumnya, yaitu navigasi naik, navigasi turun dan
navigasi tetangga.
• Ketika anda tidak menggunakan pengaturan
navigasi diatas, maka setiap kali aktivitas memulai
intent,maka aktivitas pemanggil akan disimpan ke
dalam stack, dan intent yang anda mulai akan
ditampilkan untuk anda.
• Ketika anda menekan tombol back, maka Aktifitas
teratas pada stack akan ditampilkan untuk
pengguna anda.
3
Navigasi
• Pengaturan penggunaan stack ini (biasanya disebut
BackStack) dilakukan pada saat anda membuat
menentukan Main Activity anda melalui
AndroidManifest.xml.
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
4
Navigasi
• Activity dengan tipe action MAIN dan Category
Launcher ini akan dijadikan sebagai aplikasi running
pertama anda dan menjadi RootActivity di dalam
BackStack, dan berada bagian paling atas BackStack
• Setiap anda memulai sebuah intent, maka Aktivitas
yang aktif akan berada pada lifecycle onStop(),
memulai intent dan intent terbaru akan berada di
bagian teratas BackStack
• Ketika anda menekan tombol back, maka intent teratas
akan berada dalam lifecycle onDestroy(), dan
menghapus BackStack teratas, dan menampilkan
aktivitas teratasnya.
5
Navigasi
Proses BackStack
TASK
Main Activity
Start Intent
Activity 2
Start Intent
Activity 2
6
Navigasi
TASK
Main Activity
Klik
Back
8
Navigasi
• Buat projek baru dengan nama myloaderstackback,
dan buat Empty Activity dengan nama MainActivty.
• Buat activity_main.xml dengan tampilan berikut:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/showDetail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Mulai Activity"/>
</RelativeLayout>
9
Navigasi
• Tambahkan implementasi RecyclerView dan ANKO
pada Build.Gradle anda :
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'org.jetbrains.anko:anko-common:0.9'
10
Navigasi
• Buat Activity baru (“Empty Activity”) dengan nama
DetailActivity
• Buat activity_detail.xml dengan tampilan berikut:
<android.support.v7.widget.RecyclerView
android:id="@+id/myRecyView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
11
Navigasi
• Buat Layout
XML dari klik
kanan >> New
>> XML >>
Layout_XML
12
Navigasi
• Beri nama Layout XML anda dengan layout_recy_view
• Pastikan Root Tag adalah LinearLayout
13
Navigasi
• Isi layout_recy_view.xml dengan :
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/itemName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="Nama :"
style="@style/Base.TextAppearance.AppCompat.Headline"/>
<TextView
android:id="@+id/itemNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:text="Nomor Hp :"
style="@style/Base.TextAppearance.AppCompat.Body2"/>
</LinearLayout> 14
Navigasi
• Buat kelas POJO dengan Kotlin, untuk menampung
data dari Kontak anda, dengan nama kelas
myContact.kt, dan isi kelas dengan :
class myContact (
val nama : String,
val nomorHp : String )
15
Navigasi
• Buat kelas myAdapterRecyView.kt, sebagai kelas ViewHolder dan
Adapter untuk Recycle View, dengan isi:
myRecyView.apply {
layoutManager = LinearLayoutManager(this@DetailActivity)
adapter = contactAdapter
}
}
17
Navigasi
• Buka AndroidManifest.xml anda dan tambahkan
attribut berikut
<activity android:name=".MainActivity"
android:launchMode="singleTop"
android:label="Main Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".DetailActivity"
android:parentActivityName=".MainActivity"
android:label="Detail Activity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity"/>
</activity>
18
Navigasi
• Buka MainActivity.kt anda lengkapi kode menjadi:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
showDetail.setOnClickListener {
var myDetailIntent = Intent(this, DetailActivity::class.java)
startActivity(myDetailIntent)
}
doAsync {
Thread.sleep(5000L)
uiThread {
showNotivy();
}
}
}
19
private fun showNotivy() {
val notfyDetailIntent = Intent(this@MainActivity,
DetailActivity::class.java)
val myPendingIntent = TaskStackBuilder.create(this)
.addParentStack(DetailActivity::class.java)
.addNextIntent(notfyDetailIntent)
.getPendingIntent(110,PendingIntent.FLAG_UPDATE_CURRENT)
val myNotfyManager = this.getSystemService
(android.content.Context.NOTIFICATION_SERVICE)
as NotificationManager
val myBuilder = NotificationCompat.Builder(this)
.setContentTitle("Show Detail Contact")
.setContentText("Klik Me")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(myPendingIntent)
.setAutoCancel(true)
myNotfyManager.notify(1101,myBuilder.build())
}
20
Navigasi
• Jalankan Aplikasi anda, dan tunggu beberapa detik,
Notifikasi akan ditampilkan.
21
Navigasi
• Ketika anda menekan tombol UpButton ataupun
tombol back, anda akan diarahkan kembali ke
MainActivity anda
22
Navigasi
Bedah Program
• Pada baris ini, anda telah memanfaatkan API dari
TaskStackBuilder untuk mengatur BackStack anda sendiri.
• TaskStackBuilder dibentuk dengan fungsi create()
• Ketika anda menakan tombol back dari Detail Activity, maka
pengguna akan diarahkan ke ParentActivity dari Detail
Activty yang anda buat pada AndroidManifest.xml
23
Navigasi
Bedah Program
• addParentStack() berfungsi untuk menambahkan induk
aktivitas yang ditentukan oleh manifes <meta-data> elemen
ke pembangun back Stack.
• addNextIntent() berfungsi untuk menambahkan isi dari
BackStack dari MainActivity, yaitusebuah Intent Detail
Activity
• getPendingIntent() digunakan untuk meluncurkan task yang
telah kita buat, dengan mengirimkan kode unik dan sebuah
nilai konstant
val myPendingIntent = TaskStackBuilder.create(this)
.addParentStack(DetailActivity::class.java)
.addNextIntent(notfyDetailIntent)
.getPendingIntent(110,PendingIntent.FLAG_UPDATE_CURRENT)
24
Navigasi
Bedah Program
• Pada AndroidManifest.xml, anda telah menandai bahwa
parent dari DetailActivity adalah MainActivity dengan
menggunakan attribut android:parentActivityName
<activity android:name=".DetailActivity"
android:parentActivityName=".MainActivity"
android:label="Detail Activity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity"/>
</activity>
25
Navigasi
Bedah Program
• Penambahan android:launchMode digunakan agar main
activity tidak selalu membentuk dirinya sendiri, tetapi akan
langsung diarahkan ke instance mainActivity yang telah
terdapat di memori
<activity android:name=".MainActivity"
android:launchMode="singleTop"
android:label="Main Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
26
Latihan 1
• Dari contoh, tambahkan sebuah aktivitas baru
untuk memasukkan nomor telepon
27
Latihan 1
• Ketika notifikasi di klik, maka aplikasi akan langsung
menampilkan aktivitas menambah kontak
• Anda dapat mengisikan contact pada activity, yang akan
secara otomatis tersimpan pada Detail Activity
• Detail Activity ditampilkan ketika anda menekan tombol
back, ataupun upBotton
28
Data di “Add” dan menekan tombol back
Latihan 1
Klik Notifikasi
29
Loader
• API Loader merupakansebuah API yang berfungsi
untuk memuat (load) data yang bersumber dari
internet ataupun memory internal/ekstrnal anda.
• Penggunaa API Loader akan melakukan proses
memuat data secara asynchronous
30
Loader
• Karakter Loader adalah :
• Sudah tersedia secara default untuk fragment
dan activity
• Dapat bekerja secara asynchronous
• Mempunyai observer untuk memantau
perubahan data
• Terkoneksi secara otomatis ketika terjadi
perubahan pengaturan.
31
Loader
• Loader API yang dapat anda gunakan terdiri atas:
• LoaderManager : Kelas utama yang digunakan untuk
mengatur semua loader
• LoaderManager.LoaderCallbacks : Metode Callback yang
mengatur siklus hidup Loader, yang terdiri atas 3 metode
utama onCreateLoader(), onLoadFinished(), dan
onLoaderReset()
• Loader : Kelas dasar dari semua Loader
• AsyncTaskLoader : Loader yang bekerja secara asynchronous
• CursorLoader : bagian dari AsyncTaskLoader yang
diperuntukkan untuk query terhadap data lokal.
32
Loader
• Anda sudah pernah menggunakan loader pada
pertemuan sebelumnya, yaitu AsyncTaskLoader,
oleh karena itu, pada contoh kali ini, kita akan
mencoba untuk menggunakan CursorLoader, untuk
membaca dan menampilkan nomor kontak yang
tersimpan.
33
Loader
• Buka kelas DetailActivity.kt anda dan tambahkan
implementasi
LoaderManager.LoaderCallbacks<Cursor>
class DetailActivity : AppCompatActivity(),
LoaderManager.LoaderCallbacks<Cursor>{
…
}
34
Loader
• Ubah kode DetailActivity.kt menjadi:
class DetailActivity : AppCompatActivity(),
LoaderManager.LoaderCallbacks<Cursor>{
35
override fun onLoadFinished(p0: Loader<Cursor>, p1: Cursor?) {
myListContact.clear()
if(p1!=null){
p1.moveToFirst()
while (!p1.isAfterLast()){
myListContact.add(myContact(
nama = p1.getString(p1.getColumnIndex(DISPLAY_NAME)),
nomorHp = p1.getString(p1.getColumnIndex(NUMBER))))
p1.moveToNext()
}
}
val contactAdapter = myAdapterRecyView(myListContact)
myRecyView.apply {
layoutManager = LinearLayoutManager(this@DetailActivity)
adapter = contactAdapter
}
}
36
override fun onLoaderReset(p0: Loader<Cursor>) {
val contactAdapter = myAdapterRecyView(myListContact)
myRecyView.apply {
layoutManager = LinearLayoutManager(this@DetailActivity)
adapter = contactAdapter
}
}
37
Loader
• Karena anda akan membaca kontak dari perangkat, maka
pastikan anda memberikan permisi pada perangkat anda
dalam membaca kontak anda.
• Buka AndroidManifest.xml anda dan tambahkan:
<uses-permission android:name="android.permission.READ_CONTACTS"/>
38
Jalankan aplikasi anda dan perhatikan bahwa aplikasi yang
anda buat telah berhasil membaca semua contacts anda
39
Loader
Bedah Program
• DISPLAY_NAME dan NUMBER merupakan
variable yang akan digunakan untuk
menentukan attribute yang perlu diambil
pada CursorLoader
var DISPLAY_NAME = ContactsContract.Contacts.DISPLAY_NAME
var NUMBER = ContactsContract.CommonDataKinds.Phone.NUMBER
40
Loader
Bedah Program
• Untuk Menjalankan Loader, anda akan
menggunakan initLoader
• getInstance(this) menyatakan dari mana context
yang menjalankan loader
41
Loader
Bedah Program
• InitLoader memiliki 3 parameter, yaitu :
• nilai id, yang merupakan sebuah nilai integer unik
yang anda kirimkan onCreateLoader di variable p0
• Objek bundle, yang dapat anda gunakan untuk
mengirimkan sebuah data ke onCreateLoader() di
variable p1
• Kelas LoaderManager.LoaderCallbacks<Cursor>
yang anda gunakan untuk membuat Loader
42
Loader
Bedah Program
• InitLoader akan menjalankan onCreateLoader()
yang akan mengembalikan objek CursorLoader()
• CursorLoader ini berfungsi untuk membaca data
secara ascyn
43
Loader
Bedah Program
• CursorLoader memiliki 6 parameter, yaitu
1. Context, menandakan dari mana loader dijalankan
2. Uri,mentukan reference uri (alamat) pembacaan
data, pada contoh, uri yang digunakan adalah uri dari
kontak phone anda
3. Projection, menetukan attribut kolom yang akan
dipilih
4. Selection, menetukan kondisi data yang akan diambil
5. selectionArgs, nilai argument untuk selection
6. sortOrder, menentukan pengurutan data, apakah
secara asc atau des
44
Loader
Bedah Program
• onLoadFinished() dijalankan setelah pembacaan
selesai.
• Hasil pembacaan query akan disimpan pada Cursor
pada val p0, yang dapat anda baca menggunakan
p1
45
Loader
Bedah Program
• p1 akan bertindak sebagai pointer dalam membaca data,
sehingga anda dapat memanfaatkan pointer ini dalam
membaca data
• p1.isAfterLast() digunakan untuk mengcek apakah cursor
telah berada tepat sebelum baris terakhir
• p1.moveToNext() digunakan untuk melanjukan kursor pada
baris berikutnya
myListContact.clear()
if(p1!=null){
p1.moveToFirst()
while (!p1.isAfterLast()){
myListContact.add(myContact(
nama = p1.getString(p1.getColumnIndex(DISPLAY_NAME)),
nomorHp = p1.getString(p1.getColumnIndex(NUMBER))))
p1.moveToNext()
}
46
Loader
Bedah Program
• Fungsi dari p1.getString(p1.getColumnIndex())
digunakan untuk mengambil nilai string didalam
baris table hasil query berdasarkan nama attribute
yang digunakan
nama = p1.getString(p1.getColumnIndex(DISPLAY_NAME)),
nomorHp = p1.getString(p1.getColumnIndex(NUMBER))))
48