Mochamad Kolbi Nuron_5025231183_NEWSPPB
Nama: Mochamad Kolbi Nuron
NRP: 5025231183
Kelas: PPB B
BAB I — PENDAHULUAN
1.1 Latar Belakang
Di era digital yang terus berkembang, kebutuhan masyarakat terhadap informasi berita yang cepat, akurat, dan mudah diakses semakin meningkat. Smartphone dengan sistem operasi Android menjadi salah satu perangkat utama yang digunakan masyarakat untuk mengonsumsi berita setiap harinya. Oleh karena itu, pengembangan aplikasi berita berbasis Android yang modern dan responsif menjadi kebutuhan yang relevan untuk dipelajari dan diimplementasikan dalam konteks perkuliahan Pemrograman Perangkat Bergerak.
Aplikasi ini dikembangkan dengan nama NewsUpdate, sebuah aplikasi Android yang memanfaatkan REST API dari layanan NewsAPI.org untuk menampilkan berita terkini dari berbagai sumber di seluruh dunia. Pengguna dapat menelusuri headline utama berdasarkan kategori, maupun melakukan pencarian berita dengan kata kunci bebas secara real-time.
1.2 Tujuan Proyek
Proyek ini bertujuan untuk mengimplementasikan konsep-konsep utama dalam pengembangan aplikasi Android modern, yaitu:
Pertama, menerapkan arsitektur MVVM (Model-View-ViewModel) sebagai pola desain yang memisahkan logika bisnis dari tampilan antarmuka pengguna, sehingga kode menjadi lebih terstruktur, mudah diuji, dan mudah dipelihara.
Kedua, menggunakan Jetpack Compose sebagai framework UI deklaratif resmi Android untuk membangun antarmuka pengguna yang modern dan responsif.
Ketiga, mengintegrasikan Retrofit sebagai HTTP client untuk melakukan komunikasi dengan REST API secara asinkron, disertai OkHttp sebagai lapisan jaringan dan Gson sebagai parser data JSON.
Keempat, menerapkan manajemen state berbasis StateFlow dari Kotlin Coroutines untuk memastikan tampilan selalu tersinkronisasi dengan kondisi data terkini.
Kelima, menjaga keamanan kunci API dengan memanfaatkan mekanisme BuildConfig yang membaca nilai dari local.properties, sehingga kunci tidak pernah disertakan dalam repositori kode.
Keenam, menulis unit test yang terstruktur menggunakan JUnit4, MockK, dan Coroutines Test untuk memverifikasi perilaku ViewModel dan Repository secara otomatis.
1.3 Ruang Lingkup
Aplikasi ini mencakup dua layar utama yakni layar beranda dan layar detail berita, fitur pencarian kata kunci global, filter kategori berita, pull-to-refresh, tampilan loading dan error, serta tombol untuk membaca artikel lengkap di browser dan berbagi berita.
BAB II — TEKNOLOGI DAN DEPENDENSI
2.1 Bahasa Pemrograman
Aplikasi dikembangkan sepenuhnya menggunakan bahasa Kotlin, bahasa pemrograman resmi Android yang mendukung pemrograman fungsional, null safety, dan coroutines secara native.
2.2 Framework dan Library
Jetpack Compose dengan Material Design 3 digunakan sebagai fondasi seluruh tampilan antarmuka. Compose merupakan toolkit UI deklaratif milik Android yang memungkinkan pembuatan komponen antarmuka menggunakan fungsi Kotlin biasa yang disebut Composable.
Retrofit 2.11.0 digunakan sebagai HTTP client berbasis anotasi. Retrofit menyederhanakan proses pembuatan permintaan HTTP dengan mendefinisikan antarmuka Kotlin yang secara otomatis diterjemahkan menjadi permintaan jaringan.
OkHttp 4.12.0 berfungsi sebagai lapisan HTTP yang mendasari Retrofit. OkHttp juga dilengkapi dengan HttpLoggingInterceptor yang diaktifkan pada build debug untuk memudahkan pemantauan lalu lintas jaringan.
Gson 2.11.0 digunakan bersama konverter Retrofit untuk mengurai respons JSON dari server menjadi objek data Kotlin secara otomatis.
Coil 2.7.0 (Coroutine Image Loader) digunakan untuk memuat dan menampilkan gambar dari URL secara asinkron. Coil terintegrasi secara native dengan Jetpack Compose melalui composable AsyncImage.
Kotlin Coroutines dengan StateFlow digunakan untuk manajemen operasi asinkron dan aliran data reaktif antara ViewModel dan tampilan.
MockK 1.13.12 dan kotlinx-coroutines-test digunakan sebagai alat pengujian unit untuk melakukan mocking terhadap dependensi dan menjalankan coroutines secara terkontrol dalam lingkungan pengujian.
2.3 Versi Platform
Proyek ini dikonfigurasi dengan compileSdk versi 36.1, targetSdk versi 36, dan minSdk versi 26 yang berarti aplikasi mendukung perangkat Android mulai dari versi 8.0 (Oreo) ke atas. Build tools menggunakan Android Gradle Plugin versi 9.1.1.
BAB III — ARSITEKTUR APLIKASI
3.1 Pola Arsitektur MVVM
Aplikasi ini mengikuti pola arsitektur MVVM (Model-View-ViewModel) yang direkomendasikan oleh Google untuk pengembangan Android modern. Pola ini membagi tanggung jawab kode ke dalam tiga lapisan utama.
Lapisan Model (Data Layer) bertugas mengambil, menyimpan, dan menyediakan data kepada lapisan ViewModel. Lapisan ini terdiri dari kelas data (Article, NewsResponse, Source), antarmuka API (NewsApiService), konfigurasi Retrofit (RetrofitInstance), dan kelas repository (NewsRepository).
Lapisan ViewModel berfungsi sebagai jembatan antara data dan tampilan. ViewModel mengambil data dari repository, mengolahnya, dan mengeksposnya kepada View dalam bentuk StateFlow yang dapat diamati. ViewModel tidak memiliki referensi langsung ke komponen UI, sehingga dapat hidup melewati perubahan konfigurasi seperti rotasi layar.
Lapisan View (UI Layer) adalah seluruh kode Compose yang bertanggung jawab menampilkan data dan merespons interaksi pengguna. View hanya mengamati state dari ViewModel dan tidak pernah mengakses data secara langsung.
3.2 Struktur Paket
Struktur direktori proyek diorganisasi sebagai berikut dalam paket com.example.newsupdate:
MainActivity.kt
data/
api/
NewsApiService.kt
RetrofitInstance.kt
model/
Article.kt
NewsResponse.kt
repository/
NewsRepository.kt
viewmodel/
NewsViewModel.kt
ui/
components/
NewsCard.kt
CategoryChipRow.kt
screen/
HomeScreen.kt
DetailScreen.kt
navigation/
AppNavigation.kt
theme/
Color.kt
Theme.kt
Type.kt
util/
DateUtil.kt
3.3 Alur Data
Alur data dalam aplikasi ini bersifat satu arah dan dapat dijelaskan sebagai berikut. Ketika aplikasi pertama kali dibuka, MainActivity menginisialisasi AppNavigation yang kemudian menampilkan HomeScreen. HomeScreen mendapatkan instance NewsViewModel dan mengamati newsState sebagai StateFlow. Pada saat yang sama, NewsViewModel secara otomatis memanggil fetchNews() di dalam blok init. Fungsi ini memanggil repository.getTopHeadlines() yang pada gilirannya memanggil endpoint Retrofit yang sesuai. Respons JSON dari server diurai oleh Gson menjadi objek List<Article>, kemudian dibungkus dalam Result.success() dan dikembalikan ke ViewModel. ViewModel memperbarui _newsState menjadi NewsState.Success(articles). HomeScreen mendeteksi perubahan state ini dan merender ulang daftar berita menggunakan LazyColumn.
BAB IV — PENJELASAN KODE SUMBER
4.1 Data Layer
4.1.1 Article.kt dan NewsResponse.kt
File Article.kt mendefinisikan dua data class yakni Article dan Source. Kelas Article merepresentasikan satu entitas berita dengan properti source, author, title, description, url, urlToImage, publishedAt, dan content. Properti urlToImage dan publishedAt menggunakan anotasi @SerializedName dari Gson karena nama field JSON menggunakan camelCase yang berbeda dari konvensi penamaan Kotlin. Semua properti bertipe nullable (?) untuk mengantisipasi kondisi di mana server tidak menyertakan nilai tertentu.
File NewsResponse.kt mendefinisikan struktur wrapper respons API yang terdiri dari status (string penanda keberhasilan), totalResults (jumlah total artikel yang ditemukan), dan articles (daftar objek Article).
4.1.2 NewsApiService.kt
NewsApiService adalah antarmuka Retrofit yang mendefinisikan dua endpoint berbeda dari NewsAPI. Pemisahan ini merupakan keputusan arsitektur penting karena kedua endpoint memiliki kapabilitas yang berbeda.
Fungsi getTopHeadlines dipetakan ke endpoint GET v2/top-headlines dan menerima parameter country, category, pageSize, page, dan apiKey. Endpoint ini digunakan untuk menampilkan berita utama yang difilter berdasarkan negara dan kategori.
Fungsi searchEverything dipetakan ke endpoint GET v2/everything dan menerima parameter q (kata kunci), language, sortBy, pageSize, page, dan apiKey. Endpoint ini digunakan ketika pengguna memasukkan kata kunci pencarian. Endpoint /everything jauh lebih luas cakupannya dibanding /top-headlines karena mencakup seluruh sumber berita secara global tanpa pembatasan negara, sehingga hasil pencarian keyword seperti "donald trump" akan memberikan hasil yang lebih kaya dan relevan.
Semua fungsi ditandai dengan kata kunci suspend karena dijalankan secara asinkron dalam konteks Kotlin Coroutines.
4.1.3 RetrofitInstance.kt
RetrofitInstance adalah objek singleton yang mengkonfigurasi dan menyediakan instance NewsApiService. Kelas ini menggunakan lazy initialization melalui delegate by lazy sehingga instance Retrofit hanya dibuat saat pertama kali dibutuhkan.
Konfigurasi mencakup pengaturan BASE_URL ke https://newsapi.org/, penambahan HttpLoggingInterceptor pada level BODY untuk keperluan debugging, serta batas waktu koneksi dan baca masing-masing 30 detik melalui OkHttpClient. Konverter Gson ditambahkan agar Retrofit dapat secara otomatis mengurai respons JSON.
4.1.4 NewsRepository.kt
NewsRepository adalah lapisan abstraksi antara sumber data (API) dan ViewModel. Repository menerima NewsApiService melalui konstruktornya sehingga dapat di-mock dengan mudah dalam pengujian.
Fungsi utama getTopHeadlines menerapkan logika routing yang cerdas: apabila parameter query tidak kosong, repository akan memanggil api.searchEverything() menggunakan endpoint /v2/everything; sebaliknya jika query kosong, repository akan memanggil api.getTopHeadlines() dengan filter negara dan kategori. Dalam kedua kasus, API key diambil dari BuildConfig.NEWS_API_KEY dan tidak pernah ditulis secara hardcoded.
Seluruh panggilan API dibungkus dalam blok try-catch dan hasilnya dikembalikan menggunakan tipe Result<List<Article>> dari Kotlin standard library. Ini memungkinkan ViewModel menangani kondisi sukses dan gagal dengan cara yang elegan menggunakan fungsi fold().
4.2 ViewModel Layer
4.2.1 NewsState
NewsState adalah sealed class yang merepresentasikan seluruh kemungkinan kondisi UI yang berkaitan dengan pengambilan data berita. Terdiri dari tiga kondisi: Loading sebagai data object yang ditampilkan saat permintaan sedang berjalan, Success yang membawa daftar artikel ketika data berhasil dimuat, dan Error yang membawa pesan kesalahan ketika terjadi kegagalan.
Penggunaan sealed class memberikan keamanan tipe (type safety) yang kuat karena compiler Kotlin dapat memastikan semua kondisi telah ditangani dalam ekspresi when di lapisan UI.
4.2.2 NewsViewModel.kt
NewsViewModel mewarisi ViewModel dari Android Architecture Components dan menggunakan viewModelScope untuk menjalankan coroutines yang secara otomatis dibatalkan ketika ViewModel dihancurkan.
ViewModel memiliki tiga StateFlow yang dapat diamati oleh UI. _newsState menyimpan kondisi UI terkini sebagai NewsState. _selectedCategory menyimpan kategori yang sedang dipilih dan bernilai null apabila belum ada kategori yang dipilih. _searchQuery menyimpan teks yang diketik pengguna di kotak pencarian.
Fungsi fetchNews() adalah fungsi inti yang membaca nilai kategori dan query dari state saat ini, kemudian memanggil repository, dan memperbarui _newsState berdasarkan hasilnya. Jika daftar artikel kosong, state diubah menjadi NewsState.Error dengan pesan informatif.
Fungsi selectCategory() memperbarui kategori terpilih dan langsung memanggil ulang fetchNews() agar daftar berita diperbarui secara reaktif. Fungsi search() memicu pencarian dengan query terkini. Fungsi clearSearch() membersihkan query dan mengembalikan tampilan ke headline utama. Fungsi refresh() memanggil ulang fetchNews() dengan kondisi saat ini, digunakan oleh pull-to-refresh.
Kelas Factory dalam companion object menyediakan cara untuk membuat instance ViewModel tanpa parameter tambahan, karena viewModel() di Compose memerlukan factory ketika ViewModel tidak menggunakan konstruktor default.
4.3 UI Layer
4.3.1 AppNavigation.kt
AppNavigation adalah composable yang bertindak sebagai pengontrol navigasi sederhana berbasis state. Ia menyimpan satu variabel selectedArticle bertipe Article?. Ketika nilai ini null, HomeScreen ditampilkan. Ketika pengguna mengetuk sebuah artikel, nilai diisi dan DetailScreen ditampilkan. Ketika pengguna menekan tombol kembali, nilai dikembalikan menjadi null sehingga tampilan kembali ke HomeScreen. Pendekatan ini lebih ringan dibanding menggunakan Navigation Compose penuh untuk navigasi dua layar.
4.3.2 HomeScreen.kt
HomeScreen adalah composable utama yang menjadi layar beranda aplikasi. Ia mengamati tiga StateFlow dari ViewModel menggunakan collectAsStateWithLifecycle() yang merupakan cara yang lifecycle-aware untuk mengumpulkan StateFlow di Compose.
Struktur layout menggunakan Scaffold dengan TopAppBar di bagian atas. Di dalam area konten, digunakan Column dengan tiga anak: kotak pencarian NewsSearchBar, baris filter kategori CategoryChipRow yang disembunyikan saat pencarian aktif, dan PullToRefreshBox yang mengisi sisa ruang menggunakan Modifier.weight(1f).
Penggunaan weight(1f) pada PullToRefreshBox adalah perbaikan kritis untuk fungsionalitas scroll. Apabila fillMaxSize() digunakan di dalam Column, tinggi PullToRefreshBox menjadi tidak terbatas sehingga LazyColumn di dalamnya tidak dapat mengukur dirinya sendiri dan tidak dapat di-scroll. Dengan weight(1f), PullToRefreshBox mengisi tepat sisa ruang yang tersedia setelah SearchBar dan CategoryChips, memberikan tinggi yang terukur kepada LazyColumn sehingga scroll berfungsi dengan benar.
Di dalam PullToRefreshBox, kondisi newsState dievaluasi menggunakan ekspresi when. Saat Loading, sebuah CircularProgressIndicator ditampilkan di tengah layar. Saat Success, LazyColumn merender setiap artikel menggunakan composable NewsCard dengan key berdasarkan URL artikel untuk optimasi rekomposisi. Saat Error, pesan kesalahan dan tombol "Coba Lagi" ditampilkan.
Composable privat NewsSearchBar mengimplementasikan OutlinedTextField dengan ImeAction.Search dan KeyboardActions sehingga pengguna dapat langsung menekan tombol cari di keyboard tanpa harus mengetuk ikon. Ikon Clear di sisi kanan muncul ketika kotak pencarian tidak kosong dan memicu clearSearch() di ViewModel.
4.3.3 DetailScreen.kt
DetailScreen menampilkan konten lengkap dari satu artikel berita yang dipilih. Layar ini menggunakan Scaffold dengan TopAppBar yang menampilkan nama sumber berita, tombol kembali di sebelah kiri, dan tombol bagikan di sebelah kanan.
Konten layar dibungkus dalam Column yang dapat di-scroll secara vertikal menggunakan verticalScroll(rememberScrollState()). Gambar artikel ditampilkan pertama dengan tinggi 250dp. Kemudian informasi metadata seperti nama sumber dan tanggal ditampilkan dalam baris horizontal. Judul ditampilkan dengan gaya tipografi headline. Nama penulis ditampilkan apabila tersedia. Konten artikel ditampilkan setelah pemrosesan regex untuk menghapus notasi [+N chars] yang biasa ditambahkan NewsAPI pada konten yang terpotong. Di bagian bawah, tombol "Baca Artikel Lengkap" membuka URL artikel di browser sistem menggunakan Intent.ACTION_VIEW.
4.3.4 NewsCard.kt
NewsCard adalah composable yang merepresentasikan satu kartu berita dalam daftar. Kartu memiliki sudut membulat 16dp dan elevasi 4dp. Gambar thumbnail ditampilkan dengan tinggi 200dp menggunakan AsyncImage dari Coil dengan gambar placeholder berupa vektor yang ditampilkan saat gambar sedang dimuat atau gagal dimuat. Informasi sumber berita ditampilkan sebagai badge di sudut kiri bawah gambar, diikuti tanggal di sudut kanan. Judul dibatasi dua baris dan deskripsi dibatasi tiga baris dengan TextOverflow.Ellipsis.
4.3.5 CategoryChipRow.kt
CategoryChipRow merender deretan FilterChip untuk setiap kategori yang tersedia. Kategori yang tersedia adalah business, entertainment, health, science, sports, dan technology, ditambah opsi "Semua" yang merepresentasikan nilai null. Chip yang dipilih ditampilkan dengan warna primer untuk memberikan umpan balik visual yang jelas kepada pengguna.
4.4 Utilitas dan Tema
4.4.1 DateUtil.kt
Fungsi formatDate() mengonversi string tanggal berformat ISO 8601 (contoh: 2025-06-12T14:00:00Z) menjadi format yang lebih ramah pengguna dalam bahasa Indonesia (contoh: 12 Jun 2025, 21:00). Fungsi ini menggunakan SimpleDateFormat dengan Locale.forLanguageTag("id-ID") dan dilindungi blok try-catch untuk menghindari crash apabila format tanggal tidak sesuai.
4.4.2 Tema Aplikasi
Sistem warna aplikasi menggunakan palet navy/biru yang memberikan kesan premium dan profesional, sesuai dengan karakter aplikasi berita. Pada mode terang, warna primer adalah biru tua #1565C0 dengan container biru muda. Pada mode gelap, warna primer adalah biru terang #42A5F5 dengan background abu-abu gelap. Kedua skema mendukung Material Design 3 dan secara otomatis dipilih berdasarkan preferensi sistem pengguna.
Komentar
Posting Komentar