Memahami Fundamental Android Java: Activity, Fragment, XML, Intent, RecyclerView, Adapter, dan ViewHolder
Ketika pertama kali mempelajari pengembangan aplikasi Android menggunakan Java dan Android Studio, salah satu hal yang cukup mengejutkan adalah banyaknya konsep yang harus dipahami hanya untuk membuat aplikasi sederhana.
Misalnya, sebuah aplikasi Todo sederhana yang memiliki daftar Todo dan halaman untuk menambah atau mengedit Todo dapat melibatkan:
- Activity
- Fragment
- XML
- Intent
- RecyclerView
- Adapter
- ViewHolder
Pada awalnya, konsep-konsep tersebut terlihat seperti bagian-bagian yang berdiri sendiri. Namun sebenarnya semuanya saling berhubungan dan masing-masing memiliki tanggung jawab yang cukup jelas.
Artikel ini membangun mental model tersebut dari dasar sampai ViewHolder, kemudian mengimplementasikannya menjadi aplikasi Todo sederhana yang dapat dijalankan.
1. Activity
Activity dapat dipahami sebagai komponen yang merepresentasikan sebuah screen-level UI dan lifecycle dalam aplikasi Android.
Misalnya aplikasi Todo memiliki:
MainActivityAddEditTodoActivity
Secara sederhana:
Todo App
│
├── MainActivity
│
└── AddEditTodoActivity
MainActivity menjadi layar utama untuk melihat daftar Todo, sedangkan AddEditTodoActivity digunakan untuk menambah atau mengedit Todo.
Contoh Activity:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
Activity juga memiliki lifecycle:
onCreate()
↓
onStart()
↓
onResume()
↓
[ Activity sedang digunakan ]
↓
onPause()
↓
onStop()
↓
onDestroy()
Lifecycle ini penting karena Android OS mengatur lifecycle Activity berdasarkan kondisi aplikasi dan device.
2. Fragment
Fragment adalah komponen UI yang hidup di dalam sebuah Activity.
Misalnya halaman utama Todo memiliki daftar Todo:
MainActivity
│
└── TodoFragment
│
├── TODO
├── DOING
└── DONE
Fragment membantu memecah UI menjadi bagian-bagian yang lebih modular.
Contoh:
public class TodoFragment extends Fragment {
@Override
public View onCreateView(
LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(
R.layout.fragment_todo,
container,
false
);
}
}
Yang penting, Fragment bukan sesuatu yang wajib ada di setiap Activity.
Activity dapat langsung memiliki UI tanpa Fragment.
Misalnya:
MainActivity
└── TodoFragment
tetapi:
AddEditTodoActivity
└── XML Layout
juga valid.
3. XML sebagai definisi UI
Dalam Android tradisional berbasis Java/XML, XML digunakan untuk mendefinisikan struktur dan konfigurasi UI.
Misalnya:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="Todo List"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:text="Add"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
XML tersebut belum menjadi object Java. Android akan melakukan proses yang disebut inflation, yaitu mengubah deklarasi XML menjadi object View.
Secara konseptual:
XML
│
│ inflate
▼
View Objects
│
├── LinearLayout
├── TextView
└── Button
Activity dapat menghubungkan dirinya dengan XML menggunakan:
setContentView(R.layout.activity_main);
Misalnya:
MainActivity.java
│
│ setContentView()
▼
activity_main.xml
│
▼
UI Views
Fragment juga dapat menggunakan XML:
TodoFragment.java
│
▼
fragment_todo.xml
│
▼
UI Views
Namun tidak ada aturan bahwa satu Activity atau Fragment harus memiliki tepat satu XML.
XML juga dapat digunakan sebagai template komponen UI yang lebih kecil.
4. Contoh XML untuk Todo Item
Misalnya kita memiliki:
item_todo.xml
yang mendefinisikan tampilan satu Todo:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/todoTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/todoStatus"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
XML ini tidak mewakili Activity.
Ia hanya mendefinisikan bentuk satu Todo item.
Kemudian layout tersebut dapat digunakan berkali-kali untuk menampilkan banyak Todo.
5. Intent
Intent adalah mekanisme Android untuk mengirimkan sebuah request atau message kepada komponen Android.
Penggunaan yang paling mudah dipahami adalah untuk melakukan navigation antar-Activity.
Misalnya user memilih Todo:
TodoFragment
│
│ user clicks Todo #123
▼
AddEditTodoActivity
Kita dapat menggunakan:
Intent intent = new Intent(
requireContext(),
AddEditTodoActivity.class
);
intent.putExtra("mode", "EDIT");
intent.putExtra("todoId", 123);
startActivity(intent);
Ada tiga hal yang terjadi:
Membuat Intent
Intent intent = new Intent(...);
Memberikan data
intent.putExtra("mode", "EDIT");
intent.putExtra("todoId", 123);
Meminta Android menjalankannya
startActivity(intent);
Jadi Intent sendiri bukan sesuatu yang "menjalankan Activity".
Secara konseptual:
Your Java code
│
│ new Intent()
▼
Intent object
│
│ startActivity()
▼
Android Framework
│
▼
AddEditTodoActivity
6. Intent dapat membawa data
Pada Todo App, AddEditTodoActivity dapat digunakan untuk dua mode:
AddEditTodoActivity
│
├── ADD mode
│
└── EDIT mode
Ketika membuat Todo baru:
Intent intent = new Intent(
this,
AddEditTodoActivity.class
);
intent.putExtra("mode", "ADD");
startActivity(intent);
Ketika mengedit:
Intent intent = new Intent(
this,
AddEditTodoActivity.class
);
intent.putExtra("mode", "EDIT");
intent.putExtra("todoId", 123);
startActivity(intent);
Activity tujuan dapat membaca data tersebut:
String mode =
getIntent().getStringExtra("mode");
int todoId =
getIntent().getIntExtra("todoId", -1);
Sehingga:
ADD
AddEditTodoActivity
│
├── form kosong
└── Add button
sedangkan:
EDIT
AddEditTodoActivity
│
├── load Todo #123
├── tampilkan data Todo
└── Update / Cancel
Satu Activity dapat menangani kedua use case tersebut karena perbedaannya hanya pada state atau mode.
7. Siapa yang memicu Intent?
User sebenarnya tidak secara langsung menjalankan Intent.
User melakukan aksi:
User clicks Todo
↓
Android dispatches click event
↓
OnClickListener
↓
Java code
↓
create Intent
↓
startActivity()
Misalnya:
todoView.setOnClickListener(view -> {
Intent intent = new Intent(
requireContext(),
AddEditTodoActivity.class
);
intent.putExtra("mode", "EDIT");
intent.putExtra("todoId", todo.getId());
startActivity(intent);
});
Lambda:
view -> { ... }
adalah event listener.
Sedangkan:
Intent
adalah mekanisme navigation/communication.
Keduanya memiliki tanggung jawab yang berbeda.
8. Membaca data dari UI
UI component yang didefinisikan melalui XML dapat diakses dari Java.
Misalnya:
<EditText
android:id="@+id/todoText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Java dapat mengambil object tersebut:
EditText todoText =
findViewById(R.id.todoText);
Kemudian membaca isinya:
String text =
todoText.getText().toString();
atau mengubahnya:
todoText.setText("Buy milk");
Secara konseptual:
XML
│
│ inflate
▼
EditText object
│
├── getText()
├── setText()
└── setOnClickListener()
Jadi XML mendefinisikan UI, sedangkan Java berinteraksi dengan object UI tersebut.
9. RecyclerView
Sekarang kita kembali ke halaman Todo.
Kita memiliki banyak Todo:
TODO
├── Buy milk
├── Study Android
├── Read book
└── ...
Untuk menampilkan list seperti ini, salah satu komponen Android yang umum digunakan adalah RecyclerView.
Secara sederhana:
TodoFragment
│
▼
RecyclerView
│
├── Todo #1
├── Todo #2
├── Todo #3
└── ...
Masalahnya, aplikasi mungkin memiliki ribuan Todo.
Kita tidak ingin Android membuat ribuan View sekaligus.
RecyclerView menggunakan konsep recycling.
Jika layar hanya dapat menampilkan sekitar 10 item:
Screen
┌───────────────────┐
│ Todo #1 │
│ Todo #2 │
│ Todo #3 │
│ ... │
│ Todo #10 │
└───────────────────┘
ketika user melakukan scroll, View yang keluar dari layar dapat digunakan kembali untuk item berikutnya:
Todo #1 keluar layar
│
▼
ViewHolder
│
│ recycled
▼
Todo #11
Inilah alasan RecyclerView menggunakan konsep Adapter dan ViewHolder.
10. Adapter
Adapter bertugas menghubungkan data dengan UI item.
Misalnya kita memiliki:
List<Todo> todos;
Adapter mengambil data berdasarkan posisi:
Todo todo = todos.get(position);
kemudian memasukkannya ke ViewHolder:
holder.todoTitle.setText(todo.getTitle());
holder.todoStatus.setText(todo.getStatus());
Secara konseptual:
Todo data
│
▼
Adapter
│
▼
ViewHolder
│
▼
UI
11. ViewHolder
ViewHolder adalah object yang menyimpan reference terhadap View untuk satu item RecyclerView.
Misalnya item_todo.xml memiliki:
TextView → todoTitle
TextView → todoStatus
ViewHolder dapat menyimpan reference tersebut:
public class TodoViewHolder
extends RecyclerView.ViewHolder {
TextView todoTitle;
TextView todoStatus;
public TodoViewHolder(View itemView) {
super(itemView);
todoTitle =
itemView.findViewById(
R.id.todoTitle
);
todoStatus =
itemView.findViewById(
R.id.todoStatus
);
}
}
Jadi:
item_todo.xml
│
│ inflate
▼
View objects
│
▼
TodoViewHolder
│
├── todoTitle
└── todoStatus
Nama ViewHolder sebenarnya cukup literal:
Object yang "memegang" Views.
12. Bagaimana RecyclerView, Adapter, ViewHolder, dan XML bekerja bersama?
Keempat konsep ini lebih mudah dipahami sebagai satu sistem.
Todo Data
│
▼
Adapter
│
▼
ViewHolder
│
▼
item_todo.xml
│
▼
RecyclerView
│
▼
User sees UI
Secara lebih tepat:
XML
│
│ defines
▼
UI structure
│
│ inflate
▼
View objects
│
│ held by
▼
ViewHolder
│
│ populated by
▼
Adapter
│
│ managed/recycled by
▼
RecyclerView
13. Complete Working Example
Sekarang semua konsep tersebut dapat digabungkan menjadi sebuah aplikasi Todo sederhana.
Aplikasi ini memiliki:
- Halaman utama dengan daftar Todo.
- Tombol
Add. - Klik Todo untuk membuka halaman edit.
AddEditTodoActivityyang digunakan untuk ADD maupun EDIT.- Tombol
UpdatedanCancelpada mode EDIT. RecyclerViewuntuk menampilkan Todo.AdapterdanViewHolderuntuk setiap item.
Contoh ini sengaja menggunakan in-memory data agar fokus pada konsep Android UI, bukan database atau API.
13.1 Struktur project
Struktur sederhananya:
app/
└── src/
└── main/
├── java/
│ └── com/example/todo/
│ ├── MainActivity.java
│ ├── TodoFragment.java
│ ├── AddEditTodoActivity.java
│ ├── Todo.java
│ ├── TodoAdapter.java
│ └── TodoViewHolder.java
│
├── res/
│ └── layout/
│ ├── activity_main.xml
│ ├── fragment_todo.xml
│ ├── activity_add_edit_todo.xml
│ └── item_todo.xml
│
└── AndroidManifest.xml
13.2 Model Todo
Pertama, kita membutuhkan object untuk merepresentasikan Todo.
Todo.java:
package com.example.todo;
public class Todo {
private int id;
private String title;
private String status;
public Todo(int id, String title, String status) {
this.id = id;
this.title = title;
this.status = status;
}
public int getId() {
return id;
}
public String getTitle() {
return title;
}
public String getStatus() {
return status;
}
public void setTitle(String title) {
this.title = title;
}
public void setStatus(String status) {
this.status = status;
}
}
Model ini sederhana:
Todo
├── id
├── title
└── status
14. MainActivity
MainActivity menjadi container utama untuk TodoFragment.
MainActivity.java:
package com.example.todo;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
Layout:
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Container ini akan menjadi tempat TodoFragment.
15. TodoFragment
TodoFragment.java:
package com.example.todo;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class TodoFragment extends Fragment {
private final List<Todo> todos = new ArrayList<>();
@Nullable
@Override
public View onCreateView(
@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(
R.layout.fragment_todo,
container,
false
);
initializeTodos();
RecyclerView recyclerView =
view.findViewById(R.id.todoRecyclerView);
recyclerView.setLayoutManager(
new LinearLayoutManager(requireContext())
);
TodoAdapter adapter = new TodoAdapter(
todos,
todo -> openEditTodo(todo)
);
recyclerView.setAdapter(adapter);
return view;
}
private void initializeTodos() {
todos.add(
new Todo(
1,
"Buy milk",
"TODO"
)
);
todos.add(
new Todo(
2,
"Study Android",
"DOING"
)
);
todos.add(
new Todo(
3,
"Read Java book",
"DONE"
)
);
}
private void openEditTodo(Todo todo) {
// Intent akan ditambahkan di sini.
}
}
Layout:
fragment_todo.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="16dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/addTodoButton"
android:text="Add Todo"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/todoRecyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
16. TodoViewHolder
Sekarang kita membuat ViewHolder.
TodoViewHolder.java:
package com.example.todo;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class TodoViewHolder
extends RecyclerView.ViewHolder {
final TextView todoTitle;
final TextView todoStatus;
public TodoViewHolder(
@NonNull View itemView) {
super(itemView);
todoTitle = itemView.findViewById(
R.id.todoTitle
);
todoStatus = itemView.findViewById(
R.id.todoStatus
);
}
}
ViewHolder hanya mengetahui UI untuk satu item:
TodoViewHolder
├── todoTitle
└── todoStatus
17. Todo item XML
item_todo.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/todoTitle"
android:textSize="18sp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/todoStatus"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
XML ini adalah template untuk satu Todo.
18. TodoAdapter
Sekarang kita menghubungkan Todo dengan ViewHolder.
TodoAdapter.java:
package com.example.todo;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class TodoAdapter
extends RecyclerView.Adapter<TodoViewHolder> {
public interface OnTodoClickListener {
void onTodoClick(Todo todo);
}
private final List<Todo> todos;
private final OnTodoClickListener listener;
public TodoAdapter(
List<Todo> todos,
OnTodoClickListener listener) {
this.todos = todos;
this.listener = listener;
}
@NonNull
@Override
public TodoViewHolder onCreateViewHolder(
@NonNull ViewGroup parent,
int viewType) {
View view = LayoutInflater.from(
parent.getContext()
).inflate(
R.layout.item_todo,
parent,
false
);
return new TodoViewHolder(view);
}
@Override
public void onBindViewHolder(
@NonNull TodoViewHolder holder,
int position) {
Todo todo = todos.get(position);
holder.todoTitle.setText(
todo.getTitle()
);
holder.todoStatus.setText(
todo.getStatus()
);
holder.itemView.setOnClickListener(
view -> listener.onTodoClick(todo)
);
}
@Override
public int getItemCount() {
return todos.size();
}
}
Sekarang alurnya menjadi sangat jelas.
Ketika RecyclerView membutuhkan sebuah item:
RecyclerView
│
▼
onCreateViewHolder()
│
▼
inflate item_todo.xml
│
▼
TodoViewHolder
Kemudian ketika data harus dimasukkan:
onBindViewHolder()
│
▼
Todo data
│
▼
TodoViewHolder
│
├── todoTitle
└── todoStatus
19. Menambahkan Intent
Sekarang kita kembali ke TodoFragment.
Tambahkan import:
import android.content.Intent;
Kemudian ubah:
private void openEditTodo(Todo todo) {
// Intent akan ditambahkan di sini.
}
menjadi:
private void openEditTodo(Todo todo) {
Intent intent = new Intent(
requireContext(),
AddEditTodoActivity.class
);
intent.putExtra(
"mode",
"EDIT"
);
intent.putExtra(
"todoId",
todo.getId()
);
startActivity(intent);
}
Sekarang alurnya:
User
│
│ click Todo
▼
TodoViewHolder
│
│ listener.onTodoClick(todo)
▼
TodoAdapter
│
▼
TodoFragment
│
│ new Intent()
│ todoId = 123
▼
Android
│
▼
AddEditTodoActivity
Perhatikan bahwa TodoAdapter tidak membuat Intent.
Adapter hanya memberitahu Fragment:
listener.onTodoClick(todo);
Fragment yang bertanggung jawab melakukan navigation.
20. Menambahkan tombol Add
Kita juga ingin tombol Add Todo.
Di TodoFragment:
Button addTodoButton =
view.findViewById(R.id.addTodoButton);
addTodoButton.setOnClickListener(
button -> openAddTodo()
);
Kemudian:
private void openAddTodo() {
Intent intent = new Intent(
requireContext(),
AddEditTodoActivity.class
);
intent.putExtra(
"mode",
"ADD"
);
startActivity(intent);
}
Sekarang kita memiliki dua jenis Intent:
ADD
TodoFragment
│
│ mode = ADD
▼
AddEditTodoActivity
EDIT
TodoFragment
│
│ mode = EDIT
│ todoId = 123
▼
AddEditTodoActivity
21. AddEditTodoActivity
Sekarang kita membuat Activity yang menangani dua mode tersebut.
AddEditTodoActivity.java:
package com.example.todo;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import androidx.appcompat.app.AppCompatActivity;
public class AddEditTodoActivity
extends AppCompatActivity {
private EditText todoText;
private Spinner statusSpinner;
private boolean isEditMode;
private int todoId;
@Override
protected void onCreate(
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(
R.layout.activity_add_edit_todo
);
todoText = findViewById(
R.id.todoText
);
statusSpinner = findViewById(
R.id.statusSpinner
);
Button primaryButton = findViewById(
R.id.primaryButton
);
Button cancelButton = findViewById(
R.id.cancelButton
);
String mode = getIntent()
.getStringExtra("mode");
isEditMode = "EDIT".equals(mode);
if (isEditMode) {
todoId = getIntent()
.getIntExtra("todoId", -1);
primaryButton.setText("Update");
cancelButton.setVisibility(
View.VISIBLE
);
loadTodo();
} else {
primaryButton.setText("Add");
cancelButton.setVisibility(
View.GONE
);
}
primaryButton.setOnClickListener(
view -> saveTodo()
);
cancelButton.setOnClickListener(
view -> finish()
);
}
private void loadTodo() {
// Pada contoh sederhana ini,
// data Todo tidak disimpan di database.
//
// Dalam aplikasi nyata,
// Todo akan diambil berdasarkan todoId.
}
private void saveTodo() {
String title =
todoText.getText()
.toString()
.trim();
if (title.isEmpty()) {
todoText.setError(
"Todo title is required"
);
return;
}
if (isEditMode) {
updateTodo(title);
} else {
addTodo(title);
}
}
private void addTodo(String title) {
// Insert Todo ke repository/database.
finish();
}
private void updateTodo(String title) {
// Update Todo melalui repository/database.
finish();
}
}
22. Layout Add/Edit
activity_add_edit_todo.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="16dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/todoText"
android:hint="Todo"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Spinner
android:id="@+id/statusSpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/primaryButton"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/cancelButton"
android:text="Cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Perhatikan bahwa kita tidak membuat:
add_todo.xml
edit_todo.xml
Kita hanya memiliki:
activity_add_edit_todo.xml
Perbedaannya dikontrol oleh mode:
ADD
│
└── primaryButton = "Add"
cancelButton = hidden
EDIT
│
├── primaryButton = "Update"
└── cancelButton = visible
23. AndroidManifest
Agar Android mengetahui Activity yang tersedia, Activity perlu dideklarasikan dalam manifest.
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:theme="@style/Theme.Todo">
<activity
android:name=".AddEditTodoActivity" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action
android:name="android.intent.action.MAIN" />
<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Dengan demikian Android mengetahui:
Application
│
├── MainActivity
│ └── launcher
│
└── AddEditTodoActivity
24. Satu masalah pada contoh sederhana ini
Contoh di atas sengaja tidak menggunakan database.
Artinya data:
private final List<Todo> todos
hanya hidup selama object tersebut hidup.
Jika Activity dihancurkan, data dapat hilang.
Aplikasi produksi biasanya memiliki arsitektur yang lebih lengkap:
TodoFragment
│
▼
TodoViewModel
│
▼
TodoRepository
│
├── Room Database
│
└── REST API
Tetapi konsep UI yang kita pelajari tetap sama:
Activity
Fragment
XML
Intent
RecyclerView
Adapter
ViewHolder
25. Gambaran keseluruhan aplikasi
Sekarang semua konsep dapat dilihat dalam satu diagram:
Android App
│
┌────────────────┴────────────────┐
│ │
▼ ▼
MainActivity AddEditTodoActivity
│ │
▼ ▼
TodoFragment XML Layout
│ │
▼ │
RecyclerView │
│ │
▼ │
Adapter │
│ │
▼ │
ViewHolder │
│ │
▼ │
item_todo.xml │
│ │
▼ │
Todo UI │
│ │
│ click │
▼ │
Adapter │
│ │
▼ │
TodoFragment │
│ │
│ Intent │
└─────────────────────────────────┘
Alur navigation:
User
│
│ click Todo
▼
Todo item
│
▼
OnClickListener
│
▼
TodoAdapter
│
│ onTodoClick(todo)
▼
TodoFragment
│
│ Intent
│ mode = EDIT
│ todoId = 123
▼
Android OS
│
▼
AddEditTodoActivity
Sedangkan alur rendering list:
Todo data
│
▼
RecyclerView
│
▼
Adapter
│
▼
ViewHolder
│
▼
item_todo.xml
│
▼
User sees Todo
26. Mental Model Keseluruhan
Setelah memahami konsep-konsep ini, sebuah aplikasi Todo sederhana dapat dipandang seperti berikut:
Activity
│
└── Fragment
│
└── RecyclerView
│
└── Adapter
│
└── ViewHolder
│
└── XML/View
Sedangkan ketika user berpindah screen:
User Action
│
▼
OnClickListener
│
▼
Intent
│
▼
Activity
Untuk list:
Data
│
▼
Adapter
│
▼
ViewHolder
│
▼
View
│
▼
RecyclerView
Untuk UI:
XML
│
│ inflate
▼
View objects
27. Ringkasan
Konsep-konsep tersebut sebenarnya memiliki tanggung jawab yang berbeda:
| Konsep | Tanggung jawab |
|---|---|
| Activity | Screen-level component dan lifecycle |
| Fragment | Bagian/modular UI di dalam Activity |
| XML | Mendefinisikan struktur dan konfigurasi UI |
| View | Object UI yang tampil dan menerima interaksi |
| Intent | Request/message untuk navigation atau komunikasi antar Android component |
| RecyclerView | Container untuk list yang mendukung recycling |
| Adapter | Menghubungkan data dengan UI item |
| ViewHolder | Menyimpan reference terhadap View untuk satu item |
Mental model paling sederhananya:
Activity
│
└── Fragment
│
└── RecyclerView
│
└── Adapter
│
└── ViewHolder
│
└── XML/View
Sedangkan ketika user berpindah screen:
User Action
│
▼
OnClickListener
│
▼
Intent
│
▼
Activity
Awalnya Android memang terlihat memiliki banyak abstraction. Namun setelah dilihat berdasarkan tanggung jawabnya, konsep-konsep tersebut tidak terlalu tumpang tindih:
- Activity/Fragment mengatur screen dan lifecycle.
- XML mendefinisikan UI.
- View adalah object UI yang berinteraksi dengan user.
- RecyclerView mengelola list dan recycling.
- Adapter menghubungkan data dengan UI.
- ViewHolder memegang View untuk satu item.
- Intent menghubungkan komponen Android, terutama untuk navigation.
Dengan memahami hubungan tersebut, codebase Android Java/XML yang awalnya terlihat terdiri dari banyak file dan class mulai dapat dibaca sebagai satu sistem yang saling berhubungan.