Android Kotlin #6: Menghubungkan Aplikasi ke API dengan Retrofit (GET)


Android Kotlin #6: Menghubungkan Aplikasi ke API dengan Retrofit (GET)

Halo lagi, calon developer aplikasi wisata!

Di artikel sebelumnya kita sudah bisa menampilkan daftar kategori wisata, tapi datanya masih dummy (buatan sendiri). Padahal kita sudah punya API keren yang menyediakan data kategori asli. Nah, sekarang saatnya kita menghubungkan aplikasi Android dengan API tersebut menggunakan Retrofit, sebuah library (pustaka) yang membuat komunikasi dengan API jadi semudah memesan bakso.

🤣 Kenapa Retrofit disebut Retrofit? Karena dia retro (kembali) dan fit (cocok) — dia membuat aplikasi kita cocok kembali dengan server! 😆

Apa itu Retrofit?

Retrofit adalah library buatan Square yang memudahkan kita melakukan request HTTP (GET, POST, PUT, DELETE) ke server. Dia akan mengubah response JSON menjadi objek Kotlin secara otomatis. Kita cuma perlu mendefinisikan interface dan data class, sisanya Retrofit yang urus.

Langkah 0: Pastikan API Berjalan

Sebelum mulai, pastikan API Wisata yang sudah kita buat di seri sebelumnya masih berjalan. Jalankan project API di Visual Studio (F5). Catat URL-nya, misal https://localhost:7000. Tapi karena emulator Android tidak bisa mengakses localhost di komputer (karena localhost-nya emulator berbeda), kita perlu menggunakan IP khusus: 10.0.2.2 untuk mengakses localhost komputer dari emulator Android.

Jadi base URL yang akan kita gunakan di Retrofit adalah: http://10.0.2.2:7000/ (gunakan http, bukan https, karena sertifikat development tidak dikenali). Kalau pakai HP sungguhan, pakai IP komputer di jaringan yang sama.

Langkah 1: Tambahkan Dependency Retrofit

Buka file build.gradle (Module: app). Di bagian dependencies, tambahkan baris berikut:

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.11.0' // optional, untuk melihat log

Klik Sync Now di pojok kanan atas.

Langkah 2: Data Class (Sudah Ada)

Kita sudah punya KategoriWisata dari artikel sebelumnya. Pastikan data class-nya sesuai dengan response API. Response API kita berbentuk array JSON dengan field id, nama, deskripsi. Data class kita sudah tepat:

data class KategoriWisata(
    val id: Int,
    val nama: String,
    val deskripsi: String?
)

Langkah 3: Membuat Interface API Service

Buat interface Kotlin baru di package yang sama, beri nama ApiService.kt. Isinya:

package com.example.wisataapp

import retrofit2.Call
import retrofit2.http.GET

interface ApiService {
    @GET("api/kategori")
    fun getKategori(): Call<List<KategoriWisata>>
}

Penjelasan: @GET("api/kategori") menunjukkan method ini akan melakukan request GET ke endpoint api/kategori (di belakang base URL). Return type-nya adalah Call<List<KategoriWisata>> yang berarti kita mengharapkan response berupa list objek KategoriWisata.

Langkah 4: Membuat Instance Retrofit

Kita perlu membuat objek Retrofit yang mengatur base URL dan converter. Biasanya kita buat dalam satu object (singleton) agar tidak dibuat berulang-ulang. Buat file Kotlin baru: RetrofitInstance.kt (pilih Object).

package com.example.wisataapp

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object RetrofitInstance {
    private const val BASE_URL = "http://10.0.2.2:7000/" // ganti dengan IP/domain server

    private val retrofit by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    val api: ApiService by lazy {
        retrofit.create(ApiService::class.java)
    }
}

Penjelasan:

  • BASE_URL diakhiri dengan slash (/).
  • lazy artinya objek baru dibuat saat pertama kali diakses (hemat memori).
  • retrofit.create(ApiService::class.java) menghasilkan implementasi otomatis dari interface ApiService.

Langkah 5: Izin Internet di Manifest

Aplikasi Android butuh izin untuk mengakses internet. Buka AndroidManifest.xml (di folder manifests). Tambahkan baris berikut di atas tag <application>:

<uses-permission android:name="android.permission.INTERNET" />

Juga, karena kita pakai http (bukan https) untuk development, kita perlu mengaktifkan cleartext traffic. Di dalam tag <application>, tambahkan atribut:

android:usesCleartextTraffic="true"

Sehingga manifest akan seperti ini (sebagian):

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:usesCleartextTraffic="true"
    android:theme="@style/Theme.WisataApp">
    ...

Langkah 6: Memanggil API di MainActivity

Sekarang kita akan mengganti data dummy dengan data asli dari API. Karena request API butuh waktu (asynchronous), kita tidak bisa langsung mengisi RecyclerView di thread utama. Kita akan menggunakan Coroutine (cara modern di Kotlin) untuk menjalankan request di background.

Tambahkan dependency Coroutine di build.gradle (Module: app) jika belum ada:

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'

Sync lagi.

Sekarang, ubah MainActivity.kt menjadi:

package com.example.wisataapp

import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.launch
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class MainActivity : AppCompatActivity() {

    private lateinit var recyclerView: RecyclerView
    private lateinit var adapter: KategoriAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        recyclerView = findViewById(R.id.recyclerViewKategori)
        recyclerView.layoutManager = LinearLayoutManager(this)

        // Panggil API
        fetchKategori()
    }

    private fun fetchKategori() {
        // Menggunakan Coroutine untuk memanggil API di background
        lifecycleScope.launch {
            try {
                // Panggil API secara synchronous di dalam coroutine
                val response = RetrofitInstance.api.getKategori().execute()
                if (response.isSuccessful) {
                    val listKategori = response.body()
                    if (listKategori != null) {
                        // Pasang adapter dengan data dari API
                        adapter = KategoriAdapter(listKategori) { kategori ->
                            Toast.makeText(this@MainActivity, "Memilih: ${kategori.nama}", Toast.LENGTH_SHORT).show()
                        }
                        recyclerView.adapter = adapter
                    }
                } else {
                    Toast.makeText(this@MainActivity, "Gagal mengambil data: ${response.code()}", Toast.LENGTH_SHORT).show()
                }
            } catch (e: Exception) {
                Toast.makeText(this@MainActivity, "Error: ${e.message}", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

Penjelasan:

  • lifecycleScope.launch: menjalankan coroutine yang aman dengan lifecycle Activity (akan dibatalkan jika Activity dihancurkan).
  • execute(): menjalankan request secara synchronous (blokir) di dalam coroutine. Karena kita sudah di background, ini aman.
  • response.isSuccessful: cek apakah response 200 OK.
  • Jika sukses, data diambil dan dipasang ke adapter.
  • Jika gagal, tampilkan pesan error dengan Toast.

Alternatif: Bisa juga pakai enqueue untuk callback, tapi coroutine lebih enak.

Langkah 7: (Opsional) Menambahkan Logging Interceptor

Untuk melihat request dan response di Logcat, kita bisa menambahkan interceptor. Di RetrofitInstance.kt, ubah menjadi:

import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor

private val loggingInterceptor = HttpLoggingInterceptor().apply {
    level = HttpLoggingInterceptor.Level.BODY
}

private val client = OkHttpClient.Builder()
    .addInterceptor(loggingInterceptor)
    .build()

private val retrofit by lazy {
    Retrofit.Builder()
        .baseUrl(BASE_URL)
        .client(client)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
}

Pastikan dependency logging-interceptor sudah ditambahkan di gradle.

Langkah 8: Jalankan Aplikasi

Pastikan API Wisata sedang berjalan di Visual Studio. Lalu jalankan aplikasi Android dari Android Studio. Jika berhasil, RecyclerView akan menampilkan data kategori dari API. Coba klik salah satu item, akan muncul Toast.

💡 Jika muncul error Failed to connect to /10.0.2.2:7000, pastikan:
  • API berjalan (bisa diakses dari browser komputer dengan http://localhost:7000/api/kategori).
  • Emulator menggunakan 10.0.2.2 untuk localhost komputer.
  • Izin internet dan cleartext traffic sudah diset.
  • Firewall tidak memblokir port 7000.

Selamat! Aplikasi Sudah Terhubung ke API

Sekarang aplikasi Android-mu bisa mengambil data langsung dari server. Ini adalah langkah besar menuju aplikasi yang dinamis. Kamu bisa mengganti base URL dengan domain sungguhan jika sudah di-deploy.

Rangkuman

  • Retrofit: library untuk networking yang mengubah response JSON menjadi objek Kotlin.
  • Data class: harus sesuai dengan response API.
  • Interface ApiService: mendefinisikan endpoint dan tipe request.
  • RetrofitInstance: singleton untuk membuat instance Retrofit.
  • Coroutine: menjalankan request di background tanpa membekukan UI.
  • Izin Internet dan cleartext traffic harus diatur di manifest.

Selanjutnya?

Di artikel berikutnya (Android Kotlin #7: Menampilkan Gambar dengan Glide/Coil), kita akan belajar menampilkan gambar dari URL yang dikirim API (misal foto tempat wisata). Sampai jumpa!

😎 Kalau masih error, cek lagi base URL-nya. Jangan sampai salah tulis atau lupa kasih slash di akhir. Ingat, Retrofit itu canggih tapi juga sensitif kayak gebetan!

Ditulis oleh Kakak programmer yang dulu juga sering lupa kasih izin internet. Kalau ada pertanyaan, tulis di komentar ya!

Lebih baru Lebih lama

نموذج الاتصال