Lianda Ramadhana
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # BELAJAR ANDROID ## MATERI : 1. Instalasi Android Studio 1. Pengenalan Android Studio 3. Mulai membuat tampilan antar muka tingkat dasar 4. Mulai berinteraksi dengan aplikasi 5. Mulai membuat tampilan antar muka tingkat tinggi 6. Sharedpreferences 7. Model View Presenter ## INSTALASI ANDROID STUDIO Android Studio adalah perangkat lunak buatan Google untuk para developer android dalam membuat dan mengembangkan aplikasi android. Android Studio merupakan IDE resmi untuk pengembangan aplikasi Android, berdasarkan InteliiJ IDEA. Android Studio menawarkan banyak fitur yang memungkinkan alur kerja pengembangan yang akan dibuat menjadi lebih mudah dan menyenangkan dalam satu set. 1. Instalasi Android Studio Integrated Development Environment (IDE) Berikut langkah-langkah untuk menginstal Android Studio IDE (Pada sistem operasi Windows): 1) Setelah selesai download Andorid Studio, cari file Android Studio instalasi executable (bernama android-studio-bundle-<version>.exe) pada jendela Windows Explorer, klik dua kali untuk memulai proses instalasi 2) Klik tombol Yes paada dialog User Account Control jika muncul – klik Next ![](https://i.imgur.com/mWmhPuY.png) 3) Klik Next ketika layar seperti gambar dibawah ini ![](https://i.imgur.com/YmrU4Fb.png) 4) Pada layar di gambar bawah ini adalah perjanjian lisensi. Jika setuju maka klik pada tombol I Agree ![](https://i.imgur.com/3hixZHe.png) 5) Lalu akan muncul layar pengaturan konfigurasi semua jalur instalasi yang akan ditampilkan. Jika perlu di ubah maka ubah lah,kemudian klik Next ![](https://i.imgur.com/hur2AIj.png) 6) Layar berikutnya adalah untuk menciptakan sebuah shourcuts pada start menu – biarkan saja pengaturan ini deafult dan klik Install. Maka proses instalasi yang sebenarnya dari Android Studio akan mulai dan tunggu hingga instalasi selesai ![](https://i.imgur.com/Gnaj0Pk.png) 7) Jika proses instalasi telah selesai, maka layar seperti dibawah ini akan muncul. Lalu klik Next ![](https://i.imgur.com/5RETroA.png) 8) Setelah itu masuk ke halaman Finish. Centang Start Android Studio jika ingin memulai membuka Android Studio untuk pertama kali – klik Finish ![](https://i.imgur.com/5ovB4cQ.png) Pertama kali Android Studio diluncurkan setelah diinstal, dialog akan muncul menyediakan opsi untuk megimpor pengaturan dari versi Android Studio sebelumnya. ![](https://i.imgur.com/hd7B6Hj.png) Jika memiliki pengaturan versi sebelumnya dan ingin mengimpor kedlaam instalasi terbaru, pilih opsi yang sesuai lokasi atau menunjukan bahwa tidak diperlukan impor pengaturan sebelumnya. Jika baru pertama kali menginstal Android Studio, pilih I do not have a previous version of Android Studio or I do not want to import my settings dan klik OK Kemudian akan muncul halaman berikutnya untuk mendownload dan menginstall komponen Android SDK Tools. Pastikan komputer terhubung dengan internet. Tunggulah proses download dan menginstall Android SDK tools hingga selesai. ![](https://i.imgur.com/QyOb6Ua.jpg) Setelah proses download dan install komponen telah selesai. Klik Finish. ![](https://i.imgur.com/Hi5sh9x.jpg) Apabila proses setup pada Android Studio telah selesai, maka akan tampil layar Selamat Datang Android Studio . Sampai disini proses instalasi Android Studio sudah selesai. Android studio sudah dapat membuat project baru untuk mengembangkan aplikasi berbasis Android dengan Anndroid Studio. Namun masih dibutuhkan untuk instalasi paket SDK Android terbaru yang akan dijelaskan pada pembahasan selanjutnya. 2. Instalasi Android SDK Android SDK adalah sekumpulan custom images yang digunakan untuk mengetest bahwa aplikasi Android yang telah dibuat dapat berjalan di berbagai macam versi Android. Android SDK juga mempunyai tools lainnya yang dibutuhkan dalam pengembangan aplikasi Android. Langkah-langkah dalam menginstal Android SDK, sebagai berikut : 1) Pada main window Android Studio, pilih menu Tools pada toolbar, kemudian pilih Android > SDK Manager 2) Akan muncul jendela seperti berikut ![](https://i.imgur.com/yDcEXw0.png) 3) Pilih SDK yang ingin di download dan instal dengan cara menandai checkbox yang ada di sebelah nama SDK dan klik install*packages 4) Pilih Accept All > Install 5) Tunggu hingga proses download dan installasi selesai Setelah Android Studio dan SDK nya telah selesai di instal, maka layar Android Studio akan mengarahkan kepada layar Selamat Datang Andorid Studio seperti gambar dibawah ini: ![](https://i.imgur.com/yfpDrr0.png) Sampai disini proses instalasi Android Studio sudah selesai dan Android Studio sudah dapat digunakan untuk membuat project baru untuk mengembangkan aplikasi berbasiis Android dengan Android Studio. ## PENGENALAN ANDROID STUDIO Sebelum memulai membuat proyek aplikasi android, ada beberapa langkah yang sebaiknya dilakukan untuk pengaturan sistem Android sehingga memudahkan penggunaan. 1. Pengaturan Android Software Development Kit (SDK) Manager 1) Klik Configure > SDK Manager sehingga muncul gambar berikut ![](https://i.imgur.com/gC1uePv.png) Disini kita bisa memasang tools dan paket yang diperlukan uuntuk membangun aplikasi android, termasuk mendownload dan memasang versi android yang berbeda-beda. Proses download membutuhkan akses internet yang baik dan stabil dan juga butuh waktu yang cukup lama tergantuung banyaknya tools dan pakeyt yang dipasang dengan kecepatan akses internetnya. Silahkan pilih tools dan paket yang akan dipasang lalu klik butoon Install Packages dan tunggu sampai download dan pemasangan selesai. 2) Jika sudah masuk ke layar IDE Android Studio langkah akses SDK Manager juga dapat dilakukan yaitu dengan cara klik menu Tools > Android > SDK Manager, sehingga muncul gambar seperti di atas . Lakukan hal yang sama seperti di atas. 2. Pengaturan Android Virtual Devices (AVD) Manager Setelah mendownload paket android beberapa versi dan tools yang dibtuhkan melalui SDK Manager, langkah selanjutnya adalah memasang AVD sehingga dapat dijalankan sebagai emulator android. Caranya sebagai berikut : 1) Jalankan SDK Manager seperti langkah sebelumnya di atas, baik melalui layar Welcome Android Studio maupun layar IDE Android Studio 2) Di layar Android SDK Manager pilih menu Tools > Manage AVDs .. sehingga muncul gambar berikut: ![](https://i.imgur.com/sGgHdfh.png) 3) Jika belum pernah dilakukan pengaturan sebelumnya maka layar AVD Manager masih kosong. Untuk menambhkan AVD makan pilih/klik Device Definitions sehingga muncul gambar berikut: ![](https://i.imgur.com/h8Yfqyc.png) 4) Pilih lah device yang diinginkan dengan mempertimbangkan kemampuan laptop. Sebaiknya pilih spesifikasi yangg rendah dulu misalnya Nexus S by Google dnegan layar 4 inchi dan resolusi layar 480 x 800 (tegak), RAM 343 MiB. Klik di Nexus S by Google sehingga button Create AVD disebelah kanan ON. ![](https://i.imgur.com/z2DNMQ6.png) 5) Klik button Create AVD sehingga muncul gambar berikut ![](https://i.imgur.com/IRLHrP4.png) 6) Isilah seperti contoh gambar di bawah ini untuk Target Android 2.3.3 (Ginger Bread) – API level 10 ![](https://i.imgur.com/fsMIF8G.png) 7) Setelah selesai mengisi dan button OK sudah ON yang berarti tidak ada error maka klik-lah button OK itu sheingga di bagian Android Virtual Devices akan muncul AVD yang telah disetting 8) Lakukan langkah pemasangan nomer 3 s/d 7 Nexus S by Google untuk android versi lain, misal android 4.2.2 (Jelly Bean) dan android 4.4.2 (KitKat) , sehingga akan terpasang 4 versi android, termasuk android 5.0 (Lollipop) yang sudah terpasang default. Lihat gambar dibawah ini ![](https://i.imgur.com/SioU5OL.png) 9) Untuk menjalankan android yang kita inginkan maka pilihlah android itu lalu klik button Start disebelah kanan ![](https://i.imgur.com/jz7VI7w.png) Maka muncul gambar berikut ![](https://i.imgur.com/caq6kt4.png) 10) Klik button Launch sehingga muncul gambar Starting Android Emulator seperti dibawah ini. ![](https://i.imgur.com/PMPtbXD.png) Jika tidak ada keterangan lain, termasuk kata error maka kemungkinan emulator android akan sukses muncul di layar. Tunggu beberapa tergantung spesifikasi laptop/komputernya.   ## MULAI MEMBUAT TAMPILAN ANTARMUKA TINGKAT DASAR Dalam membuat tampilan antar muka di Android Studio maka yang harus dikenali pertama kali adalah View dan ViewGroup. View group merupakan komponen yang berperan mengkoordinasi komponen-komponen view lainnya. Beberapa contoh komponen View dan ViewGroup disajikan pada tabel berikut. | View | ViewGroup | | -------- | -------- | | TextView | LinearLayout | | Button | RelativeLayout | | ImageView | ListView | | EditText | GridView | Secara hierarki, dapat dijelaskan seperti Gambar berikut : ![](https://i.imgur.com/o88UbhS.png) Secara umum, layout Android ada 4 jenis yaitu LinearLayout, RelativeLayout, AbsoluteLayout dan FrameLayout. Namun, untuk kali ini kita akan bahas hanya LinearLayout dan RelativeLayout. 1. LinearLayout LinearLayout yaitu tampilan dimana user hanya menempatkan 1(satu) widget per baris/kolom. Jika ingin 1 widget/baris, maka harus menggunakan orientation: vertical, dan jika 1 widget/kolom harus menggunakan orientation:horizontal. ```android <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal | vertical"> <!-- widget2 disini--> </LinearLayout> ``` Contoh hasil dari tampilan LinearLayout adalah sebagai berikut: ![](https://i.imgur.com/ncnK3IC.png) Source: http://developer.android.com/resources/tutorials/views/images/hello-linearlayout.png 2. RelativeLayout RelativeLayout adalah tampilan dimana user dapat menempatkan widget-widget didalamnya seperti layer, sehingga sebuah widget dapat berada di atas/di bawah widget lainnya. Layout ini biasanya berguna untuk membuat tampilan yang lebih universal sehingga dapat dibuka dengan baik di segala resolusi ponsel Android. ```android <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <!-- widget2 disini--> <TextView android:id="@+id/label1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:text="This is label1"/> <TextView android:id="@+id/label2" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/label1" android:text="This is label2"/> <TextView android:id="@+id/label3" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_toRightOf="@id/label2" android:text="This is label3"/> </RelativeLayout> ``` Contoh dari RelativeLayout adalah sebagai berikut: ![](https://i.imgur.com/B9x25Kd.png) Source: http://developer.android.com/resources/tutorials/views/images/hello-relativelayout.png   Dalam latihan kali ini, mari membuat aplikasi penghitung Luas Persegi. 1) Buat layout pada activity_main.xml 2) Ganti viewgroup dengan LinearLayout 3) Tambahkan view : a. 2 TextView untuk label ‘Panjang’ dan ‘Lebar’ b. 2 EditText untuk mengisi nilai ‘Panjang’ dan ‘Lebar’ c. 1 Button untuk menghitung luas persegi 4) Adapun code pada xml sebagai berikut: ```android <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.project.lianda.luaspersegi.MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:text="Panjang" /> <EditText android:id="@+id/edt_panjang" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="numberDecimal" android:layout_marginBottom="5dp"/> <TextView android:text="Lebar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp"/> <EditText android:id="@+id/edt_lebar" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="numberDecimal" android:layout_marginBottom="5dp"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btn_hitung" android:text="Hitung" android:layout_marginBottom="8dp"/> </LinearLayout> ```   Bedah Kode: 1. LinearLayout a. Digunakan untuk menjadi parent view layout agar menyusun view-view didalamnya secara berurutan b. Menggunakan attribute ‘Orientation = Vertical” menandakan bahwa urutan yang dibentuk LinearLayout tersusun secara vertical dari atas ke bawah 2. TextView a. Digunakan untuk memberi label pada sebuah text b. Attribute ‘Text = value” berfungsi untuk memberikan tulisan pada TextView c. Attribute ‘MarginBottom = value” berfungsi untuk memberikan jarak antara view tersebut dengan view yang ada dibawahnya 3. EditText a. Digunakan untuk memberikan input box yang dapat diisi oleh user b. Attribute ‘InputType = value’ berfungsi untuk memberikan tipe inputan yang diberikan user pada box tersebut, dalam hal ini ‘NumberDecimal’ digunakan untuk membuat user memberi tipe nilai angka decimal 4. Button a. Digunakan untuk memberi tombol yang dapat menghubungkan interaksi antara user dan aplikasi b. Menambahkan attribute ‘Id’ sangat dianjurkan agar button dapat di identifikasi saat hendak menambahkan aksi pada tombol tersebut   ## MULAI BERINTERAKSI DENGAN APLIKASI 1. Interaksi Dasar Dalam Android, untuk menambahkan interaksi antara user dan aplikasi hanya cukup dengan menambahkan metode “OnClickListener’ bawaan default dari Android Studio. Adapun penulisan code : ``` {idView}.setOnClickListener{ //TODO: Set action here } ``` Code diatas bermaksud untuk menambahkan aksi saat user menekan view tersebut hingga menjalankan aksi yang sudah ditentukan. 2. Interaksi dengan Intent Dalam Android, ada class yang bernama ‘Intent’ bawaan Android yang digunakan untuk perpindahan halaman. Intent juga merupakan suatu objek yang terdapat dalam suatu activity dimana objek tersebut dapat komunikasi dengan activity yang lain, baik activity pada fungsi internal android misal seperti memanggil activity dalam satu package atau beda package yang masih berada dalam satu project. Intent merupakan objek tipe android.content.Intent. Melalui metode startActivity() yang digunakan untuk memulai sebuah activity lain. Intent dibagi menjadi 2, yaitu : 1. Explicit Intent berfungsi untuk mengaktifkan komponen-komponen dalam satu aplikasi yang sama. Misalnya seperti : Berpindah Activity. 2. Implicit Intent berfungsi untuk memanggil fungsi activity yang sudah ada di fungsi internal android seperti Dial Number, Open Browser, Share dan lainnya. Lanjutkan latihan, 1. Buka MainActivity.Kt 2. Di dalam function OnCreate, tambahkan code sebagai berikut : ```kotlin btnHitung.setOnClickListener{ val panjang = edtPanjang.text.trim().toString() val lebar = edtLebar.text.trim().toString() val result = panjang.toDouble()*lebar.toDouble() Toast.makeText(this, “Hasilnya$result”, Toast.LENGTH_SHORT).show() } ``` 3. Buat Activity baru untuk menampilkan hasil perhitungan melalui halaman lain. Adapun cara membuat activity baru: a. Klik kanan pada package utama b. Klik menu ‘New’ c. Klik ‘Activity’ lalu pilih ‘EmptyActivity’ d. Tuliskan nama activity ‘ResultActivity’ 4. Pada activity_result.xml tambahkan TextView untuk menampilkan hasil 5. Pada MainActivity.Kt, Tambahkan Explicit Intent a. Intent tanpa data ```kotlin btnHitung.setOnClickListener{ val panjang = edtPanjang.text.trim().toString() val lebar = edtLebar.text.trim().toString() val result = panjang.toDouble()*lebar.toDouble() val intent = Intent() startActivity(intent, ResultActivity::class.java) } ``` b. Intent dengan data - Masukkan code berikut di dalam MainActivity.Kt sebagai pengirim data ```kotlin btnHitung.setOnClickListener{ val panjang = edtPanjang.text.trim().toString() val lebar = edtLebar.text.trim().toString() val result = panjang.toDouble()*lebar.toDouble() val intent = Intent() intent.putExtra(“resultKey”, result) startActivity(intent, ResultActivity::class.java) } ``` - Masukkan code berikut di dalam ResultActivity.Kt sebagai penerima data di dalam function OnCreate ```kotlin val result = intent.getBooleanExtra(“resultKey”) tvResult.text = result.toString() ``` 6. Untuk menggunakan Implicit Intent, tambahkan 3 button di activity_result.xml 7. Buat Buat beberapa fungsi didalam ResultActivity.Kt sebagai berikut: ```kotlin fun showWebPage(){ val intent = Intent(Intent.ACTION_VIEW, Uri.parse(“http://www..com”)) startActivity(intent) } fun share(){ val intent = Intent() intent.action = Intent.ACTION_SEND intent.type = “text/plain” intent.putExtra(Intent.EXTRA_TEXT, “this is text to send”) statrActivity(intent) } fun showDialPage(){ val intent = Intent(Intent.ACTION_CALL) intent.data = Uri.parse(“tel:” + phoneNumber) startActivity(intent) } ``` 8. Tambahkan code berikut di dalam function OnCreate ```kotlin btnWebPage.setOnClickListener{ showWebPage() } btnShare.setOnClickListener{ share() } btnDial.setOnClickListener{ showDialPage() } ``` Bedah Kode: Dalam melakukan perpindahan halaman dengan membawa data, perlu diperhatikan pada code berikut: ```kotlin intent.putExtra(“resultKey”, result) ``` resultKey : Merupakan key untuk mengirim data yang harus bersifat unik ```kotlin val result = intent.getBooleanExtra(“resultKey”) ``` getBooleanExtra : Merupakan function untuk mengambil data dengan mengikuti tipe data yang dikirim   ## MULAI MEMBUAT TAMPILAN ANTARMUKA TINGKAT TINGGI ### Menggunakan Fragment Fragment adalah salah satu komponen di android yang memiliki sifat dan fungsi yang sama dengan Activity. Namun fragment tidak bisa berdiri sendiri tanpa adanya Activity. Lanjutkan Latihan: 1. Buat Activity baru dengan nama “MainActivity” yang digunakan untuk menampung fragment 2. Klik kanan pada package app utama 3. Klik “New” 4. Klik “Fragment” pilih “BlankFragment” 1. Beri nama fragment "HomeFragment" 5. Tambahkan kode berikut pada activity_main.xml ```android <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" android:padding="16dp" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" android:layout_marginBottom="16dp"/> <FrameLayout android:id="@+id/containerHome" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout> ``` 6. Tambahkan kode berikut pada MainActivity.Kt ```kotlin class MainActivity : AppCompatActivity(), OnIncreaseNumberListener { var counter: Int = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val bundle = Bundle() bundle.putString("name", "Sidiq Permana") val homeFragment = HomeFragment() homeFragment.onIncreaseNumberListener = this homeFragment.arguments = bundle supportFragmentManager.beginTransaction() .replace(R.id.containerHome, homeFragment, HomeFragment::class.java.simpleName) .commit() } override fun onNumberIncreased() { counter += 1 Toast.makeText(this, "Dipanggil dari fragment, counter $counter", Toast.LENGTH_LONG) .show() } } ``` 7. Tambahkan kode berikut pada home_fragment.xml ```kotlin= class HomeFragment : Fragment() { var onIncreaseNumberListener: OnIncreaseNumberListener? = null override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? = inflater.inflate(R.layout.fragment_home, container, false) override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) if (arguments != null){ val name = arguments?.getString("name") tvHello.text = "Hai $name" } btnProfile.setOnClickListener { val intent = Intent(context, ProfileActivity::class.java) startActivity(intent) } btnUpdateCounter.setOnClickListener { onIncreaseNumberListener?.onNumberIncreased() } Picasso.get().load("https://www.partyrama.co.uk/wp-content/uploads/2017/06/minions-kevin-lifesize-cardboard-cutout-180cms-product-image.jpg") .into(imgMinions) } } ``` 8. Buat satu buah interface seperti kode dibawah ini: ```kotlin interface OnIncreaseNumberListener { fun onNumberIncreased() } ``` 9. Jalankan aplikasi Aplikasi anda akan tampak seperti gambar dibawah ini: ![](https://i.imgur.com/3Ym8BrD.jpg) Dan apabila di klik button update counter akan tampak seperti gamabr dibawah ini: ![](https://i.imgur.com/vobtOcC.jpg) Bedah Kode: ```kotlin val homeFragment = HomeFragment() supportFragmentManager.beginTransaction() .replace(R.id.containerHome, homeFragment, HomeFragment::class.java.simpleName) .commit() ``` Kode diatas merupakan kode untuk memanggil sebuah fragment ke dalam activity ```kotlin val bundle = Bundle() bundle.putString("name", "Sidiq Permana") val homeFragment = HomeFragment() homeFragment.arguments = bundle ``` Kode diatas digunakan untuk mengirim sebuah data ke dalam fragment ```kotlin if (arguments != null){ val name = arguments?.getString("name") tvHello.text = "Hai $name" } ``` Untuk mengambil data yang sudah dikirim ke fragment, maka kode diatas digunakan fragment untuk menerima data dalam bentuk argument. Selanjutnya merupakan kode untuk interaksi dari fragment ke activity dengan menggunakan interface ```kotlin interface OnIncreaseNumberListener { fun onNumberIncreased() } ``` Kode diatas merupakan sebuah interface yang akan menghubungkan fragment dengan activity yang mengimplementasikan interface tersebut ```kotlin= var onIncreaseNumberListener: OnIncreaseNumberListener? = null btnUpdateCounter.setOnClickListener { onIncreaseNumberListener?.onNumberIncreased() } ``` Kode diatas merupakan cara untuk menggunakan interface pada fragment yaitu dengan membuat sebuah objek interface dan memanggil fungsinya saat button update counter di klik oleh user ```kotlin class MainActivity : AppCompatActivity(), OnIncreaseNumberListener { var counter: Int = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val homeFragment = HomeFragment() homeFragment.onIncreaseNumberListener = this } override fun onNumberIncreased() { counter += 1 Toast.makeText(this, "Dipanggil dari fragment, counter $counter", Toast.LENGTH_LONG) .show() } } ``` Sedangkan kode diatas digunakan activity untuk mengimplement interface dan kemudian melakukan sesuatu pada function onNumberIncreased. ### Menggunakan RecyclerView Recyclerview adalah salah satu komponen dasar dalam android untuk menampilkan banyak data yang dapat di gulir dalam bentuk list. RecyclerView merupakan versi ListView yang telah ditingkatkan dan lebih fleksibel. Jadi recyclerview memungkinkan kita untuk menambah data secara dinamis kedalam tampilan. Terdapat 4 komponen utama pada Recyclerview : • Data • Layout • ViewHolder • Adapter Layout adalah tampilan yang akan dibuat untuk setiap item yang akan ditampilkan kedalam recyclerview. ViewHolder berisi tampilan informasi untuk menampilkan satu item dari layout. Adapter digunakan untuk menghubungkan data dengan recyclerview dan menyiapkan data dengan menampilkan data dalam viewholder. Hubungan keempat komponen tersebut dapat digambarkan sebagai berikut: ![](https://i.imgur.com/mDq2GlX.png) Latihan: 1. Langkah pertama adalah tambahkan dependency baru untuk menggunakan RecyclerView a. Pada project structure, pilih “build.gradle(Module:app)” b. Tambahkan code berikut di dalam tag ```android dependencies{ implementation ‘com.android.support:recyclerview-v7:x.x.x’ } ``` 2. Buat activity baru dengan nama “SimpleListActivity” 3. Pada acitivity_simple_list.xml tambahkan view berikut ```android <android.support.v7.widget.RecyclerView android:id="@+id/rvList" android:layout_width="match_parent" android:layout_height="match_parent"/> ``` 4. Buat layout baru dengan nama “item_list.xml” a. Klik kanan pada folder “res” b. Pilih “New” c. Pilih “Layout Resource File” d. Beri nama “item_list” e. Klik finish f. Tunggu sampai layout terbuat 5. Tambahkan kode berikut pada “item_list.xml” ```android <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <TextView android:id="@+id/txtName" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout> ``` 6. Buat kelas Adapter dengan nama “SimpleAdapter”. Bila ada penanda error yang muncul, abaikan dulu sementara. ```kotlin class SimpleAdapter() : RecyclerView.Adapter<SimpleHolder.ViewHolder>() { } ``` 7. Buat kelas ViewHolder sebagai inner class dari kelas adapter yang sudah dibuat. ```kotlin class SimpleAdapter() : RecyclerView.Adapter<SimpleAdapter.ViewHolder>() { //Viewholder = item object manipulator inner class Viewholder(itemView: View) : RecyclerView.ViewHolder(itemView) { //bind data to item view fun bind(item: String){ itemView.tvItem.text = item } } } ``` 8. Tambahkan kode dibawah ini untuk melengkapi kelas SimpleAdapter. ```kotlin class SimpleAdapter(): RecyclerView.Adapter<SimpleAdapter.Viewholder>() { val itemList = mutableListOf<String>() //purpose of this method is to inflate the itemView layout in xml //and convert it into itemView object override fun onCreateViewHolder(viewGroup: ViewGroup, position: Int): Viewholder { val itemView = LayoutInflater .from(viewGroup.context) .inflate(R.layout.item_list, viewGroup, false) return Viewholder(itemView) } //purpose of this method is to get total numbers of //items will be iterated override fun getItemCount() = itemList.size //purpose of this method is to bind the data into //list item object (ViewHolder) override fun onBindViewHolder(viewholder: Viewholder, position: Int) { viewholder.bind(itemList[position]) } //Viewholder = item object manipulator inner class Viewholder(itemView: View) : RecyclerView.ViewHolder(itemView) { //bind data to item view fun bind(item: String){ itemView.tvItem.text = item } } } ``` Penjelasan mengenai kode pada SimpleAdapter: a. Kelas Viewholder: Kelas ini bertujuan untuk menampilkan data yang telah ditambakan ke adapter kepada user. Setiap view holder menampung satu rangkaian data dari list. Terdapat fungsi bind() yang bertujuan untuk mengikat data pada masing-masing objek tampilan untuk ditampilkan kepada pengguna. b. getItemCount(): Fungsi ini bertujuan untuk mendapatkan jumlah data yang telah ditambakan untuk ditampilkan. c. onCreateViewHolder(): Fungsi ini bertujuan untuk mengisi layout xml yang telah dibuat kedalam ViewHolder, mengubahnya menjadi object ItemView, dan mengembalikan nilainya. d. onBindViewHolder(): Fungsi ini bertujuan untuk menghubungkan data dengan viewholder pada posisi yang ditentukan oleh recyclerview. 9. Tambahkan kode berikut pada SimpleListActivity.Kt di dalam fungsi onCreate ```kotlin val list = mutableListOf( “Thor”, “Captain America”, “Iron Man”) //configure the recyclerview rvMovie.setHasFixedSize(true) rvMovie.layoutManager = LinearLayoutManager(this) rvMovie.addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL)) //create an adapter instance val adapter = SimpleAdapter(this) adapter.itemList.addAll(listMovie) //set adapter to RecyclerView rvMovie.adapter = adapter = adapter } ``` Pada Recyclerview, terdapat 3 layout manager yang dapat digunakan, yaitu: - **LinearLayoutManager**: Menampilkan item dalam bentuk list secara vertikal atau horizontal - **GridLayoutManager**: Menampilkan item dalam kumpulan petak - **StaggeredGridLayoutManager**: Menampilkan item dalam kumpulan petak dengan bentuk yang zigzag Pada latihan kali ini, kita menggunakan LinearLayoutManager. Setelah itu coba jalankan kode anda pada device/emulator yang digunakan. Hasilnya adalah sebagai berikut ![](https://i.imgur.com/e7HvPw1.png) 10. Lalu bagaimana caranya agar user dapat berinteraksi dengan list data yang ditampilkan dengan recyclerview, contohnya melakukan klik pada suatu data? Untuk melakukan hal tersebut diperlukan suatu *callback* yang menangani tindakan klik data. *Callback* disini bertujuan sebagai penghubung antara kelas Adapter dan Activity dimana reaksi dari suatu data yang mendapatkan tindakan klik dalam adapter akan diproses pada Activity sehingga kelihatan oleh pengguna. Tambahkan suatu interface dan tambahkan clickListener pada itemView pada kelas SimpleAdapter sehingga kodenya menjadi seperti berikut ```kotlin class SimpleAdapter(val onItemClickListener: OnItemClickListener): RecyclerView.Adapter<SimpleAdapter.Viewholder>() { val itemList = mutableListOf<String>() //this method is to inflate the itemView layout in xml // and convert //it into itemView object override fun onCreateViewHolder(viewGroup: ViewGroup, position: Int): Viewholder { val itemView = LayoutInflater .from(viewGroup.context) .inflate(R.layout.item_list, viewGroup, false) return Viewholder(itemView) } //this method is to get total numbers of //items will be iterated override fun getItemCount() = itemList.size //this method is to bind the data into //list item object (ViewHolder) override fun onBindViewHolder(viewholder: Viewholder, position: Int) { viewholder.bind(itemList[position]) } //Viewholder = item object manipulator inner class Viewholder(itemView: View) : RecyclerView.ViewHolder(itemView) { //bind data to item view fun bind(item: String){ itemView.tvItem.text = item itemView.itemList.setOnClickListener { onItemClickListener.onItemClicked(item) } } } //Callback action listener interface OnItemClickListener{ fun onItemClicked(item: String) } } ``` 11. Implementasikan fungsi pada interface OnItemClickListener pada kelas SimpleListActivity dan tambahkan kode yang akan dijalankan yang akan kita tentukan untuk menampilkan sebuah Toast mengenai judul film yang diklik sehingga kelas SimpleListActivity menjadi: ```kotlin class SimpleListActivity : AppCompatActivity(), SimpleAdapter.OnItemClickListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_simple_list) //set the data val listMovie = mutableListOf( "Thor", "Captain America", "Iron Man") //configure the recyclerview rvMovie.setHasFixedSize(true) rvMovie.layoutManager = LinearLayoutManager(this) rvMovie .addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL)) //create an adapter instance val adapter = SimpleAdapter(this) adapter.itemList.addAll(listMovie) //set adapter to RecyclerView rvMovie.adapter = adapter } override fun onItemClicked(item: String) { Toast .makeText(this, "$item clicked", Toast.LENGTH_LONG) .show() startActivity(Intent(this, MovieGalleryActivity::class.java)) } } ``` ## SHAREDPREFERENCES ***SharedPreferences*** adalah salah satu jenis penyimpanan yang disediakan Android untuk menyimpan suatu data dalam tempat penyimpanan perangkat dalam ukuran kecil dengan tipe data primitif. Dalam proses penyimpanan data, sharedpreferences menggunakan kombinasi *key-value*. Latihan: 1. Buat Project baru dan pilih *Empty Activity* 2. Buat sebuah *file* Kotlin dengan nama *PreferenceKey* 3. Tambahkan konstanta yang akan digunakan sebagai *key* untuk mengakses *sharedpreferences* sebagai berikut: ```kotlin const val PREF_KEY_NAME = "key_name" const val PREF_KEY_EMAIL = "key_email" const val PREF_KEY_PHONE = "key_phone" const val PREF_KEY_AGE = "key_age" const val PREFERENCE_NAME = "PREF_USERDATA" ``` 4. Buat sebuah kelas dengan nama *AppPreference* dengan parameter context. Kelas ini bertujuan untuk menampung semua perintah untuk menyimpan dan mengambil data dari *sharedpreferences* ```kotlin class AppPreference(context: Context) { var userPreference: SharedPreferences ?= null init { userPreference = context .getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE) } fun setValue(key: String, value: String){ userPreference?.edit()?.putString(key, value)?.apply() } fun getStringValue(key: String): String? = userPreference?.getString(key, null) fun setValue(key: String, value: Int){ userPreference?.edit()?.putInt(key, value)?.apply() } fun getIntValue(key: String): Int? = userPreference?.getInt(key, 0) fun clear(){ userPreference?.edit()?.clear()?.apply() } } ``` Ketika kelas tersebut di inisialisasi, kelas tersebut akan membuat sebuah objek sharedpreferences dengan nama berdasarkan konstanta PREFERENCE_NAME dimana *preferences* tersebut hanya bisa diakses oleh aplikasi ini saja (Context.MODE_PRIVATE). Untuk menyimpan suatu data dalam *sharedpreferences*, diguanakan metode edit() disertai dengen nilai key dan value yang akan disimpan berdasarkan tipe datanya. Contohnya pada hal ini adalah ketika ingin menyimpan nilai bertipe string digunakan perintah > userPreference?.edit()?.putString(key, value)?.apply(). Fungsi apply() berarti proses penyimpanan data dilakukan secara *asynchronus* Lalu untuk memgambil suatu data dalam *sharedpreferences*, digunakan metode *get* berdasartkan tipe data yang di inginkan dengan nilai *key* yang dimaksud beserta melampirkan nilai *default* yang di inginkan. > userPreference?.getInt(key, 0) Terdapat fungsi clear yang digunakan untuk menghapus semua data yang tersimpan pada *sharedpreferences* tersebut >userPreference?.edit()?.clear()?.apply() 5. Ubah tampilan *activity_main.xml* menjadi seperti berikut ```android <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" android:orientation="vertical" android:padding="16dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Name" android:layout_marginBottom="4dp"/> <EditText android:id="@+id/edtName" android:layout_width="match_parent" android:layout_height="wrap_content" android:maxLines="1" android:inputType="textPersonName" android:hint="Eg: John Doe" android:layout_marginBottom="16dp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Email" android:layout_marginBottom="4dp"/> <EditText android:id="@+id/edtEmail" android:layout_width="match_parent" android:layout_height="wrap_content" android:maxLines="1" android:inputType="textEmailAddress" android:hint="Eg: user@foo.com" android:layout_marginBottom="16dp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Phone Number" android:layout_marginBottom="4dp"/> <EditText android:id="@+id/edtPhoneNumber" android:layout_width="match_parent" android:layout_height="wrap_content" android:maxLines="1" android:inputType="phone" android:hint="Eg: 081210841382" android:layout_marginBottom="16dp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Age" android:layout_marginBottom="4dp"/> <EditText android:id="@+id/edtAge" android:layout_width="match_parent" android:layout_height="wrap_content" android:maxLines="1" android:inputType="number" android:layout_marginBottom="16dp"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/btnSave" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Simpan"/> <Button android:id="@+id/btnClear" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Hapus"/> </LinearLayout> </LinearLayout> ``` 6. Pada kelas *MainActivity* tambahkan kode berikut: ```kotlin class MainActivity : AppCompatActivity() { private lateinit var appPreference: AppPreference override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) appPreference = AppPreference(this) if (!TextUtils.isEmpty(appPreference.getStringValue(PREF_KEY_NAME))){ edtName.setText(appPreference.getStringValue(PREF_KEY_NAME)) } if (!TextUtils.isEmpty(appPreference.getStringValue(PREF_KEY_PHONE))){ edtPhoneNumber.setText(appPreference.getStringValue(PREF_KEY_PHONE)) } if (!TextUtils.isEmpty(appPreference.getStringValue(PREF_KEY_EMAIL))){ edtEmail.setText(appPreference.getStringValue(PREF_KEY_EMAIL)) } edtAge.setText(appPreference.getIntValue(PREF_KEY_AGE).toString()) btnSave.setOnClickListener { val name = edtName.text.toString().trim() val email = edtEmail.text.toString().trim() val phone = edtPhoneNumber.text.toString().trim() val age = edtAge.text.toString().trim() appPreference.setValue(PREF_KEY_NAME, name) appPreference.setValue(PREF_KEY_EMAIL, email) appPreference.setValue(PREF_KEY_PHONE, phone) appPreference.setValue(PREF_KEY_AGE, age.toInt()) Toast.makeText(this, "Data saved", Toast.LENGTH_LONG).show() } btnClear.setOnClickListener { appPreference.clear() edtName.setText("") edtEmail.setText("") edtPhoneNumber.setText("") edtAge.setText("0") } } } ``` Penjelasan kode pada MainActivity: a. Pada objek *appPreference*, terdapat *keyword lateinit* ketika mendeklarasikan objek tersebut. Pada Kotlin, *lateinit* berfungsi untuk melakukan inisialisasi nilai yang bersifat telat pada suatu objek ketika tidak mungkin dilakukan inisialisasi nilai pada saat kelas tersebut dipanggil. Nilai dari objek *lateinit* tidak boleh null, harus di inisialisasi pada suatu titik, dan tidak boleh berupa tipe data primitif. b. Dalam metode *onCreate()*, objek appPreference di inisialisasi dengan parameter konteks *MainActivity*. Artinya objek *AppPreference* dapat digunakan dalam kelas *MainActivity* untuk mengakses *sharedpreference*. c. Pada *EditText* nama, dilakukan pengecekan apakah terdapat nilai untuk nama pada *sharedpreferences*. Jika ada, nilai tersebut akan diisi pada *editText* nama. > Fungsi dari *appPreference.getStringValue(PREF_KEY_NAME)* adalah untuk mengembalikan nilai preference dengan *key* *PREF_KEY_NAME* bertipe data *String*. Hal yang sama juga dilakukan pada EditText nomor telepon, email, dan umur. tetapi pada EditText umur tidak perlu dilakukan pengecekan karena secara *default* nilai yang dikembalikan oleh *preferences* dengan tipe data *integer* adalah 0. d. ketika tombol simpan ditekan, akan terjadi proses peyimpanan data dari masing-masing *EditText* ke sharedpreference berdasarkan *key* dan *value* yang telah ditentukan. Lalu sebuah *toast* akan dimunculkan ketika proses penyimpanan data berhasil. > *appPreference.setValue(key,value)* berfungsi untuk menyimpan data pada *sharedpreferences* sesuai dengan nilai *key* dan *value* yang diberikan. e. Tombol Hapus digunakan untuk mengosongkan semua data pada form dalam MainActivity serta menghapus semua data yang tersimpan pada *sharedpreferences* melalui *appPreference.clear()* Ketika pertama kali kode dijalankan, tampilannya adalah sebagai berikut: ![](https://i.imgur.com/PB7PbIu.png) Lalu silahkan mengisi data pada setiap *EditText*. Setelah itu tekan tombol simpan dan tutup aplikasi tersebut lalu buka kembali aplikasi tersebut. Maka nilai yang sudah tersimpan akan ditampilkan kembali pada aplikasi. Hasil tampilannya adalah: ![](https://i.imgur.com/JJoISqY.png) ## MODEL-VIEW-PRESENTER ### Pengertian ***Model-View-Presenter*** (MVP) adalah sebuah arsitektur dalam membangun sebuah aplikasi yang memisahkan antara proses bisnis dengan tampilan. Tujuan menggunakan MVP adalah untuk membuat kode yang dibangun menjadi lebih terstruktur, lebih mudah dilakukan pengujian dan lebih mudah dipelihara. Terdapat 3 komponen layer pada MVP, yaitu: 1. **Model**: Layer yang berhubungan secara langsung dengan data dari *API*, *cache*, *preference*, dan *database*. Dengan kata lain, pada layer ini terjadi proses pengambilan data dan melakukan manipulasi data yang berasal dari penyimpanan pada perangkat ataupun dari *API*. 2. **View**: Layer tampilan yang dilihat oleh pengguna yang hanya berfungsi untuk menampilkan data saja. 3. **Presenter**: Layer yang menghubungkan antara layer *View* dengan *Model*. Presenter mengambil data yang berasal dari *Model* untuk ditampilkan pada *View*. Setiap proses bisnis yang terjadi dilakukan pada layer ini. Secara sederhana proses kerja MVP dapat digambarkan sebagai berikut: ![](https://i.imgur.com/v1MZJSA.png) ### Menerapkan MVP dalam pengembangan aplikasi android Pada latihan kali ini kita akan mencoba untuk menerapakan arsitektur Model-View-Presenter dalam pengembangan aplikasi android. Untuk layer *Model* kita akan mengakses API yaitu melalui TheMovieDb API untuk mendapatkan data. Selain itu, untuk berinteraksi dengan API, kita akan menggunakan salah satu library yang populer digunakan yaitu Retrofit 2. Pertama-tama buat projek baru pada Android Studio lalu pilih *Empty Activity*. Setelah itu modifikasi Build.Gradle pada Module app pada bagian buildTypes dan dependencies menjadi seperti berikut: ```gradle buildTypes { debug { buildConfigField("String", "BASE_URL", "\"https://api.themoviedb.org/3/\"") buildConfigField("String", "BASE_IMAGE_URL", "\"https://image.tmdb.org/t/p/w200\"") buildConfigField("String", "BASE_BACKDROP_IMAGE_URL", "\"https://image.tmdb.org/t/p/w500\"") buildConfigField("String", "API_KEY", "\"7012fc3c96c9f6f707e4edb9c9725718\"") } release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' buildConfigField("String", "BASE_URL", "\"https://api.themoviedb.org/3/\"") buildConfigField("String", "BASE_IMAGE_URL", "\"https://image.tmdb.org/t/p/w200\"") buildConfigField("String", "BASE_BACKDROP_IMAGE_URL", "\"https://image.tmdb.org/t/p/w500\"") buildConfigField("String", "API_KEY", "\"7012fc3c96c9f6f707e4edb9c9725718\"") } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' implementation 'com.squareup.picasso:picasso:2.71828' implementation 'com.squareup.retrofit2:retrofit:2.4.0' implementation 'com.squareup.retrofit2:converter-gson:2.4.0' implementation 'com.squareup.okhttp3:okhttp:3.11.0' implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0' implementation 'com.android.support:recyclerview-v7:28.0.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' } ``` Pada Build.Gradle, pertama kita telah menambahkan library yang akan digunakan. Library tersebut adalah Retrofit 2, OkHttp sebagai REST Client untuk berinteraksi dengan API, RecyclerView untuk menggunakan recyclerview dan Picasso untuk proses memuat gambar. Selain itu pada buildTypes, kita telah menambahkan 1 varian baru yaitu debug yang akan gunakan dalam pengembangan aplikasi kali ini. Di dalam tiap varian, kita juga menambahkan beberapa konstanta yang akan digunakan untuk mengakses API MovieDb dengan menggunakan buildConfigField. Keunntungan kita menambahkan konstanta dalam varian adalah kita dapat memanggil Konstanta-konstanta tersebut dengan mudah pada file apapun. Lalu pada AndroidManifest, tambahkan sebuah permision diluar tag <application> supaya aplikasi dapat mengakses internet. ```android <uses-permission android:name="android.permission.INTERNET"/> ``` Selanjutnya, pada package utama, tambahkan beberapa package seperti berikut: ![](https://i.imgur.com/hQjyXx8.png) Supaya dapat berinteraksi dengan API, kita perlu menyiapkan beberapa file untuk mempersiapkan Retrofit dan OkHttp3 supaya dapat digunakan. Pertama-tama buat sebuah Object baru didalam package data->lib dengan nama OkHttpClientFactory. lalu isi file tersebut sebagai berikut: ```kotlin object OkHttpClientFactory { private const val DEFAULT_MAX_REQUEST = 30 fun create(): OkHttpClient { val builder = OkHttpClient.Builder() .readTimeout(120, TimeUnit.SECONDS) .connectTimeout(120, TimeUnit.SECONDS) .retryOnConnectionFailure(true) .addInterceptor(Interceptor { val request = it.request().newBuilder() .url(it.request() .url() .newBuilder() .addQueryParameter("api_key", BuildConfig.API_KEY).build()) .build() it.proceed(request) }) if (BuildConfig.DEBUG) { val interceptor = HttpLoggingInterceptor() interceptor.level = HttpLoggingInterceptor.Level.BODY builder.addInterceptor(interceptor).build() } val dispatcher = Dispatcher() dispatcher.maxRequests = DEFAULT_MAX_REQUEST builder.dispatcher(dispatcher) return builder.build() } } ``` Object OkHttpClientFactory digunakan sebagai HttpClient yang akan kita gunakan untuk me-request data ke API. Pada object tersebut, kita membuat suatu interceptor untuk menambahkan api key dari theMovieDB sehingga pada setiap metode request nilai api key akan selalu terlampir/ Lalu buat sebuah objek baru dengan nama ApiService. Object ini bertujuan untuk membuat Retrofit client yang akan membentuk URL ketika diakses. Gson disini bertujuan untuk menkonversi respon yang diberikan dari bentuk JSON menjadi bentuk sebuah object sehingga dapat digunakan oleh aplikasi. ```kotlin object ApiService { fun <S> createService(serviceClass: Class<S>, okhttpClient: OkHttpClient, baseURl: String): S { val gson = GsonBuilder() .create() val retrofit = Retrofit.Builder() .baseUrl(baseURl) .client(okhttpClient) .addConverterFactory(GsonConverterFactory .create(gson)) .build() return retrofit.create(serviceClass) } } ``` Buat sebuah kelas dengan nama UseCase. Kelas ini bertujuan sebagai perantara antara layer Presenter dengan layer Model. Kelas ini dibuat abstract karena kita akan mendefinisikan fungsi callApi pada kelas UseCase tiap endpoint. ```kotlin abstract class UseCase { abstract fun callApi() companion object{ val apiRequest: Repository by lazy { ApiService.createService( Repository::class.java, OkHttpClientFactory.create(), BuildConfig.BASE_URL ) } } } ``` Terakhir, buat tampilan beserta recylerview adapter nya. Kita akan menggunakan GridLayoutManager untuk menampilkan gambar dari list film tersebut. Modifikasi activity_main.xml menjadi: ```android <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".view.popularmovie.MainActivity"> <ProgressBar android:id="@+id/progressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true"/> <android.support.v7.widget.RecyclerView android:id="@+id/rvMovie" android:layout_width="match_parent" android:layout_height="match_parent"/> </RelativeLayout> ``` Lalu buat layout untuk digunakan pada recyclerview dengan nama item_movie_list.xml. ```android <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/imgMovie" android:layout_width="match_parent" android:layout_height="match_parent" android:adjustViewBounds="true" android:layout_gravity="center"/> </LinearLayout> ``` Buat kelas MovieAdater untuk menampung data MovieItem ```kotlin class MovieAdapter: RecyclerView.Adapter<MovieAdapter.MovieViewholder>() { val list = mutableListOf<MovieItem>() var onMovieItemClickListener: OnMovieItemClickListener ?= null override fun onCreateViewHolder(viewGroup: ViewGroup, position: Int): MovieViewholder { val view = LayoutInflater .from(viewGroup.context) .inflate(R.layout.item_movie_list, viewGroup, false) return MovieViewholder(view) } override fun getItemCount() = list.size override fun onBindViewHolder(viewholder: MovieViewholder, position: Int) { viewholder.bind(list[position]) } inner class MovieViewholder(itemView: View) : RecyclerView.ViewHolder(itemView) { fun bind(movieItem: MovieItem){ Picasso.get() .load(BuildConfig.BASE_IMAGE_URL + movieItem.poster) .into(itemView.imgMovie) itemView.imgMovie.setOnClickListener { onMovieItemClickListener?.onMovieItemClicked(movieItem) } } } interface OnMovieItemClickListener{ fun onMovieItemClicked(movieItem: MovieItem) } } ``` Terakhir, modifikasi kelas MainActivity menjadi seperti berikut: ```kotlin class MainActivity : AppCompatActivity(), MainView, MovieAdapter.OnMovieItemClickListener{ var adapter: MovieAdapter?= null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) supportActionBar?.apply { title = "Popular Movie" } rvMovie.setHasFixedSize(true) rvMovie.layoutManager = GridLayoutManager(this, 2) adapter = MovieAdapter() adapter?.onMovieItemClickListener = this rvMovie.adapter = adapter } override fun onMovieItemClicked(movieItem: MovieItem){ } } ``` Setelah seleasi, waktunya untuk menerapkan arsitektur MVP dalam aplikasi kita. Tahap yang akan kita lakukan adalah sebagai berikut: ![](https://i.imgur.com/BqeN3aI.png) Sekarang, kita akan membuat suatu request untuk mendapatkan daftar film populer untuk ditampilkan pada tampilan. #### 1. Create Repository Pertama, buat sebuah interface dengan nama Repository pada package data->lib. Interface ini akan kita gunakan untuk memuat semua endpoint API yang akan kita akses. lalu tambahkan sebuah fungsi sebagai berikut ```kotlin @GET("discover/movie?sort_by=popularity.desc") fun getListPopularMovie(): Call<MovieResponse> ``` Fungsi tersebut akan membuat aplikasi berinteraksi dengan endpoint https://api.themoviedb.org/3/discover/movie?api_key=7012fc3c96c9f6f707e4edb9c9725718&sort_by=popularity.desc dengan metode GET() dan mengembalikan data dengan tipe MovieResponse. Oleh sebab itu kita perlu membuat sebuah response model untuk menampung data dengan tipe MovieResponse. Respon yang dikembalikan berupa: ```json { page: 1, total_results: 431334, total_pages: 21567, results: [ { vote_count: 581, id: 384018, video: false, vote_average: 6.5, title: "Fast & Furious Presents: Hobbs & Shaw", popularity: 456.135, poster_path: "/keym7MPn1icW1wWfzMnW3HeuzWU.jpg", original_language: "en", original_title: "Fast & Furious Presents: Hobbs & Shaw", genre_ids: [ 28 ], backdrop_path: "/hpgda6P9GutvdkDX5MUJ92QG9aj.jpg", adult: false, overview: "A spinoff of The Fate of the Furious, focusing on Johnson's US Diplomatic Security Agent Luke Hobbs forming an unlikely alliance with Statham's Deckard Shaw.", release_date: "2019-08-01" }, { vote_count: 1739, id: 420818, video: false, vote_average: 7.1, title: "The Lion King", popularity: 265.913, poster_path: "/2bXbqYdUdNVa8VIWXVfclP2ICtT.jpg", original_language: "en", original_title: "The Lion King", genre_ids: [ 12, 16, 10751, 18, 28 ], backdrop_path: "/1TUg5pO1VZ4B0Q1amk3OlXvlpXV.jpg", adult: false, overview: "Simba idolises his father, King Mufasa, and takes to heart his own royal destiny. But not everyone in the kingdom celebrates the new cub's arrival. Scar, Mufasa's brother—and former heir to the throne—has plans of his own. The battle for Pride Rock is ravaged with betrayal, tragedy and drama, ultimately resulting in Simba's exile. With help from a curious pair of newfound friends, Simba will have to figure out how to grow up and take back what is rightfully his.", release_date: "2019-07-12" } ] } ``` Pada respon tersebut terdapat object results yang isinya adalah array dari object sebuah film. kita akan mengubah object results beserta isinya menjadi sebuah kelas objek yang dapat digunakan oleh aplikasi. Pada package model buat sebuah Data Class dengan nama MovieResponse dan MovieItem. Data Class pada kotlin berfungsi sebagai kelas untuk menampung suatu data. isi kedua Data Class tersebut dengan kode berikut: ```kotlin data class MovieResponse( @SerializedName("results") val result: List<MovieItem> ) ``` ```kotlin data class MovieItem( @SerializedName("original_title") val title: String?, @SerializedName("poster_path") val poster: String?, @SerializedName("id") val id: String?, @SerializedName("overview") val overview: String?, @SerializedName("homepage") val homePage: String?, @SerializedName("backdrop_path") val backdrop: String?, @SerializedName("original_language") val originalLanguage: String?, @SerializedName("genres") val genres: MutableList<Genre> ) data class Genre( @SerializedName("id") val id: String?, @SerializedName("name") val name: String? ) ``` #### 2. Create Use Case Pada tahap ini, kita akan membuat sebuah kelas UseCase yang bertindak sebagai interactor antara Presenter dan Model. Pada package Domain->Movie buat sebuah kelas dengan nama GetPopularMovieUseCase lalu isi kelas tersebut sebagai berikut: ```kotlin class GetPopularMovieUseCase: UseCase() { var onPopularMovieCallback: OnPopularMovieCallback ?= null override fun callApi() { val request = apiRequest.getListPopularMovie() request.enqueue(object: Callback<MovieResponse>{ override fun onResponse(call: Call<MovieResponse>, response: Response<MovieResponse>) { if (response.isSuccessful){ onPopularMovieCallback?. onPopularMovieSuccess(response .body()?.result) }else{ onPopularMovieCallback?. onPopularMovieFailed("Request gagal") } } override fun onFailure(call: Call<MovieResponse>, t: Throwable) { onPopularMovieCallback?. onPopularMovieFailed("Request gagal") } }) } interface OnPopularMovieCallback{ fun onPopularMovieSuccess(movies: List<MovieItem>?) fun onPopularMovieFailed(message: String) } } ``` Pada kelas GetPopularMovieUseCase, terjadi request data dari aplikasi dengan API getListPopularMovie yang ditunjukan dengan perintah: ```kotlin val request = apiRequest.getListPopularMovie() ``` Proses request data tersebut berlangsung secara asynchronus, ditunjukkan dengan perintah enqueue dan akan menghasilkan 1 dari 2 kemungkinan yaitu apakah proses tersebut berhasil atau gagal yang ditunjukan oleh: ```kotlin override fun onResponse(call: Call<MovieResponse>, response: Response<MovieResponse>) { if (response.isSuccessful){ onPopularMovieCallback?. onPopularMovieSuccess(response .body()?.result) }else{ onPopularMovieCallback?. onPopularMovieFailed("Request gagal") } } override fun onFailure(call: Call<MovieResponse>, t: Throwable) { onPopularMovieCallback?. onPopularMovieFailed("Request gagal") } ``` Lalu untuk mengembalikan respon ke presenter, dibutuhkan sebuah callback yang menangani ketika proses tersebut berhasil atau gagal. Maka dibuatlah sebuah interface bernama OnPopularMovieCallback yang memiliki 2 fungsi yaitu onPopularMovieSuccess() yang membawa data array MovieItem dan onPopularMovieFailed() yang membawa data String. ```kotlin interface OnPopularMovieCallback{ fun onPopularMovieSuccess(movies: List<MovieItem>?) fun onPopularMovieFailed(message: String) } ``` Setelah itu callback tersebut dipasang bila proses request data berhasil dan gagal. Bila respon tersebut berhasil maka akan mengembalikan nilai data array MovieItem ke presenter, dan bila gagal akan mengembalikan nilai String yaitu pesan Request Gagal. #### 3. Create Interface for View Buat satu kelas interface baru dengan nama MainView dalam package view->popularmovie. Pada kelas ini, kita akan membuat fungsi-fungsi yang nantinya akan dipanggil oleh presenter untuk melakukan perubahan pada tampilan. ```kotlin interface MainView { fun showMovieList(movies: List<MovieItem>?) fun showErrorMessage(message: String) fun showHideProgressBar(isShown: Boolean) } ``` #### 4. Implement View Interface to Activity/Fragment Sekarang, implementasikan MainView pada kelas MainActivity. lalu implementasikan ketiga fungsi tersebut pada MainActivity ```kotlin override fun showMovieList(movies: List<MovieItem>?) { if (movies != null){ adapter?.list?.addAll(movies.toMutableList()) adapter?.notifyDataSetChanged() } } override fun showErrorMessage(message: String) { Toast.makeText(this, message, Toast.LENGTH_LONG).show() } override fun showHideProgressBar(isShown: Boolean) { if (isShown){ progressBar.visibility = View.VISIBLE }else{ progressBar.visibility = View.GONE } } ``` Fungsi showMovieList digunakan untuk mengisi data adapter dengan list dari MovieItem ketika proses request data dengan API berhasil dilakukan. setelah itu wajib memanggil fungsi notifyDataSSetChanged() untuk memberi tahu pada adapter jika data pada adapter sudah berubah dan adapter akan menampilkan data terbaru. Fungsi showErrorMessage digunakan untuk menampilkan pesan error ketika interaksi dengan API gagal. Fungsi showHideProgressBar digunakan untuk menampilkan dan menyembunyikan progress bar. #### 5. Create Interface for Presenter Tahap selanjutnya adalah membuat Interface untuk presenter yang akan digunakan. disini kita akan membuat fungsi fungsi yang akan dapat dipanggil oleh View untuk berinteraksi dengan Presenter. Buat interface baru dengan nama IMainPresenter pada package view->popularmovie ```kotlin interface IMainPresenter { fun getMovieList() } ``` #### 6. Create Presenter Class Buat kelas Presenter dengan nama MainPresenter dengan konstruktor utamanya interface MainView. ```kotlin class MainPresenter(val mainView: MainView){ } ``` #### 7. Implement Presenter Interface to Presenter Class Lalu, implementasikan IMainPresenter pada MainPresenter ```kotlin class MainPresenter(val mainView: MainView): IMainPresenter, override fun getMovieList() { mainView.showHideProgressBar(true) } override fun onPopularMovieSuccess(movies: List<MovieItem>?) { mainView.showHideProgressBar(false) mainView.showMovieList(movies) } override fun onPopularMovieFailed(message: String) { mainView.showHideProgressBar(false) mainView.showErrorMessage(message) } } ``` #### 8. Implement Use Case on Presenter Inisialisasi GetPopularMovieUseCase pada Presenter, lalu implementasikan callback yang terdapat pada GetPopularMovieUseCase pada Presenter ```kotlin class MainPresenter(val mainView: MainView): IMainPresenter, GetPopularMovieUseCase.OnPopularMovieCallback{ var getPopularMovieUseCase: GetPopularMovieUseCase ?= null init { getPopularMovieUseCase = GetPopularMovieUseCase() getPopularMovieUseCase?.onPopularMovieCallback = this } override fun getMovieList() { mainView.showHideProgressBar(true) getPopularMovieUseCase?.callApi() } override fun onPopularMovieSuccess(movies: List<MovieItem>?) { mainView.showHideProgressBar(false) mainView.showMovieList(movies) } override fun onPopularMovieFailed(message: String) { mainView.showHideProgressBar(false) mainView.showErrorMessage(message) } } ``` Pada fungsi getMovieList, akan dilakukan proses request data dengan API popular movie, oleh karena itu untuk menunjukan ke user bahwa proses sedang berlangsung, aplikasi akan menampilkan progress bar. Ketika proses tersebut berhasil, pada onPopularMovieSuccess, nilai list MovieItem akan dikembalikan lalu nilai tersebut akan diisi kepada adapter pada View. Lalu progress bar dihilangkan untuk menunjukan bahwa proses telah berhasil. Sebaliknya, jika proses request data gagal, Progress bar akan dihilangkan dan akan memunculkan pesan error pada view dari nilai string yang dibawa dimana pada kasus ini pesan tersebut akan ditampilkan dengan sebuah toast. #### 9. Integrate View to Presenter Tahap terakhir pada proses ini adalah mengintegrasikan View dengan Presenter lalu View melakukan request data popular movie melalui presenter. Pada kelas MainActivity inisialisasi kelas MainPresenter lalu lakukan request data melalui objek mainPresenter. Lalu tambahkan perintah didalam fungsi onMovieItemClicked untuk menampilkan judul film ketika film tersebut dipencet. Modifikasi fungsi onCreate dan onMovieItemClicked sehingga menjadi seperti berikut: ```kotlin var mainPresenter: IMainPresenter?= null var adapter: MovieAdapter?= null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) supportActionBar?.apply { title = "Popular Movie" } rvMovie.setHasFixedSize(true) rvMovie.layoutManager = GridLayoutManager(this, 2) adapter = MovieAdapter() adapter?.onMovieItemClickListener = this rvMovie.adapter = adapter mainPresenter = MainPresenter(this) mainPresenter?.getMovieList() } override fun onMovieItemClicked(movieItem: MovieItem) { Toast.makeText(this, movieItem.title, Toast.LENGTH_LONG).show() } ``` Setelah semuanya selesai, jalankan kode yang telah dibuat pada device/emulator yang digunakan. Hasilnya akan seperti ini: ![](https://i.imgur.com/5wmXDzj.png) ![](https://i.imgur.com/qT1vKGL.png)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully