Anda di halaman 1dari 48

Fudamental Android

dengan Kotlin (Part 6)


Sunaryo Winardi, S.Kom., M.TI.

PRODI. TEKNIK INFORMATIKA (S-1)

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>

• Setiap activity yang ada pada baris ini akan


ditampilkan pertama kali ke pengguna dan akan
langsung dimasukkan ke dalam BackStack

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 Activity 2 Activity 3

BackStack Main Activity Activity 2

Main Activity
Start Intent
Activity 2

Start Intent
Activity 2
6
Navigasi
TASK

Main Activity Activity 2 Activity 3

BackStack Main Activity Activity 2

Main Activity
Klik
Back

Activity 2 Klik Back


Destroy
Activity 3
Destroy
7
Navigasi
• Untuk contoh navigasi kali ini, anda akan membuat
sebuah aplikasi, untuk memulai activity, tetapi tidak
melalui mainActivity, tetapi melalui notifikasi
(mekanisme deeplink).
• Ketika anda menekan tombol back, maka navigasi
ke atas akan dilakukan

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:

class myAdapterRecyView(private val contact: List<myContact>)


: RecyclerView.Adapter<myHolder>() {
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): myHolder {
return myHolder(LayoutInflater.from(p0.context)
.inflate(R.layout.layout_recy_view,p0,false))
}
override fun getItemCount(): Int = contact.size
override fun onBindViewHolder(p0: myHolder, p1: Int) {
p0.bindContact(contact[p1])
}
}
class myHolder(view: View):RecyclerView.ViewHolder(view){
private val contactName = view.itemName
private val contactNumber = view.itemNumber

fun bindContact(tmp: myContact){


contactName.text = "${contactName.text} ${tmp.nama}"
contactNumber.text = "${contactNumber.text} ${tmp.nomorHp}"
}
} 16
Navigasi
• Lengkapi DetailActivity.kt dengan:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail)

val myListContact = listOf(


myContact(nama = "Sunaryo",nomorHp = "08774844***4"),
myContact(nama = "Agus",nomorHp = "08774844***4")
)
val contactAdapter = myAdapterRecyView(myListContact)

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.

• Ketika anda menekan notifikasi tersebut, maka


anda akan langsung diarahkan ke detail Activity
anda

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

val myPendingIntent = TaskStackBuilder.create(this)


.addParentStack(DetailActivity::class.java)
.addNextIntent(notfyDetailIntent)
.getPendingIntent(110,PendingIntent.FLAG_UPDATE_CURRENT)

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>{

}

• Pengimplementasian ini akan mewajibkan anda


untuk mengimplementasikan 3 metode :
onCreateLoader(), onLoadFinished() dan
onLoaderReset()

34
Loader
• Ubah kode DetailActivity.kt menjadi:
class DetailActivity : AppCompatActivity(),
LoaderManager.LoaderCallbacks<Cursor>{

var DISPLAY_NAME = ContactsContract.Contacts.DISPLAY_NAME


var NUMBER = ContactsContract.CommonDataKinds.Phone.NUMBER
val myListContact : MutableList<myContact> = ArrayList();

override fun onCreateLoader(p0: Int, p1: Bundle?)


: Loader<Cursor> {
var MyContentUri = ContactsContract.CommonDataKinds.Phone
.CONTENT_URI
var myProjection = arrayOf(DISPLAY_NAME,NUMBER)
return CursorLoader(this, MyContentUri, myProjection,
null, null, DISPLAY_NAME+ " ASC")
}

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

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail)

LoaderManager.getInstance (this).initLoader(1, null, this);


}
}

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"/>

• Dan pastikan izin diberikan melalui pengaturan anda (Setting


>> apps >> MyLoaderStackBack >> Permissions)

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

LoaderManager.getInstance(this).initLoader(1, null, this);

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

override fun onCreateLoader(p0: Int, p1: Bundle?)


: Loader<Cursor> {
var MyContentUri = ContactsContract.CommonDataKinds.Phone
.CONTENT_URI
var myProjection = arrayOf(DISPLAY_NAME,NUMBER)
return CursorLoader(this, MyContentUri, myProjection,
null, null, DISPLAY_NAME+ " ASC")
}

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

override fun onLoadFinished(p0: Loader<Cursor>, p1: Cursor?) {

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

• Data yang diambil melalui query ini akan


dimasukkan sebagai objek list yang akan dijadikan
sebagai data untuk recycleView
47
Latihan 2
• Pilih salah satu dari 2 tugas ini:
a. Dari Contoh Kursor Loader, tambahakan fungsi
onClickListener, untuk melakukan panggilan.
Ketika kontak dari aplikasi anda diklik, maka
secara otomatis intent telepon akan dilakukan,
sesuai nomor telepon yang dipilih
b. Lanjutkan program Latihan 2 Pertemuan 5
dengan mengganti proses Firebase Dispatcher
dengan AsyncTaskLoader untuk membaca data
dari OpenWeatherMap.org

48

Anda mungkin juga menyukai