Navigation Component
Pendahuluan
Pada praktikum kali ini anda akan mempelajari untuk membangun aplikasi single activity multi fragment dengan menggunakan navigation component.
Tujuan Pembelajaran
- Mahasiswa mampu mengkonversi multi activity menjadi single activity multi fragment.
- Mahasiswa mampu memasang dan menerapkan navigation component.
Alat dan Bahan
- Laptop atau PC
- Android Studio
- Starter Code
Navigation Component
Destination
Action
Praktikum
Silahkan klik tautan starter project yang telah dibagikan oleh masing-masing dosen pengampu.
Buka starter code yang telah disiapkan dengan menggunakan Android Studio. Amati susunan file/directory yang terdapat pada starter code.
Buka file
fragment_score.xml
, pelajari desain aplikasi Skor dengan seksama. Pada aplikasi terdapat dua bagian yaitu tim Home dan Away. Skor pada tim didasarkan pada daftar pencetak gol untuk masing-masing tim.Dari analisa sebelumnya, dapat diketahui bahwa dibutuhkan kumpulan data untuk menyimpan daftar pemain pencetak gol.
Tambahkan definisi variabel data pada
fragment_score.xml
yang digunakan untuk menyimpan data skor untuk masing-masing tim. Pendekatan pada praktikum ini menggunakan databinding.fragment_score.xml<?xml version="1.0" encoding="utf-8"?><layoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"><data><variablename="homeGoalScorerList"type="java.util.List" /><variablename="awayGoalScorerList"type="java.util.List" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".fragments.ScoreFragment"><!-- widget .... --></androidx.constraintlayout.widget.ConstraintLayout></layout>Buka file
ScoreFragment.java
, hubungkan databinding layout dengan fragment java dengan menambahkan kode berikut pada methodonCreateView()
ScoreFragment.java@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {FragmentScoreBinding binding = DataBindingUtil.inflate(inflater, R.layout.fragment_score, container, false);binding.setHomeGoalScorerList(homeGoalScorerList);binding.setAwayGoalScorerList(awayGoalScorerList);return binding.getRoot();}
Untuk menghitung skor tim, didapatkan dengan menghitung ukuran jumlah data pencetak gol dengan method
size()
. Ekspresi databinding yang dibutuhkan untuk menampilkan skor tim Home silahkan perhatikan kode berikut pada bagianfragment_score.xml
.<!-- Layout --><TextViewandroid:id="@+id/text_home_score"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{String.valueOf(homeGoalScorerList.size())}"android:textSize="64sp"app:layout_constraintBottom_toTopOf="@+id/guideline"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><!-- Layout -->Modifikasi bagian TextView untuk tim Away sehingga dapat menampilkan jumlah skor seperti pada tim Home.
Tombol pada tampilan
fragment_score
masih belum memiliki event. Untuk menghubungkan fragment dan layout dengan menggunakan konsep databinding, dibutuhkan tambahan deklarasi variabelfragment
. Tambahkan variabel pada bagian data dengan jenisScoreFragment
.fragment_score.xml<data><variablename="fragment"type="id.ac.polinema.skor.fragments.ScoreFragment" /></data>Buka kembali file
ScoreFragment.java
dan tambahkan pengaturan databinding untuk fragment. Silahkan perhatikan kode berikut.ScoreFragment.java@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {FragmentScoreBinding binding = DataBindingUtil.inflate(inflater, R.layout.fragment_score, container, false);binding.setHomeGoalScorerList(homeGoalScorerList);binding.setAwayGoalScorerList(awayGoalScorerList);binding.setFragment(this);return binding.getRoot();}Tambahkan event click pada id
button_add_home
dengan ekspresi databindingandroid:onClick="@{(v) -> fragment.onAddHomeClick(v)}"
dan pada idbutton_add_away
dengan ekspresi databindingandroid:onClick="@{(v) -> fragment.onAddAwayClick(v)}"
.<Buttonandroid:id="@+id/button_add_home"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginStart="8dp"android:layout_marginEnd="8dp"android:layout_marginBottom="16dp"android:onClick="@{(v) -> fragment.onAddHomeClick(v)}"android:text="Add Score Home"app:layout_constraintBottom_toTopOf="@+id/guideline"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent" /><Buttonandroid:id="@+id/button_add_away"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginStart="8dp"android:layout_marginEnd="8dp"android:layout_marginBottom="16dp"android:text="Add Score Away"android:onClick="@{(v) -> fragment.onAddAwayClick(v)}"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintHorizontal_bias="0.0"app:layout_constraintStart_toStartOf="parent" />Tambahkan method
onAddHomeClick(View view)
padaScoreFragment
. Pada method ini berisi logika untuk berpindah keGoalFragment
. Pada perpindahan ini dikirimkan data tim home menggunakan konstantaHOME_REQUEST_KEY
.ScoreFragment.javapublic void onAddHomeClick(View view) {ScoreFragmentDirections.GoalScorerAction action = ScoreFragmentDirections.goalScorerAction(HOME_REQUEST_KEY);Navigation.findNavController(view).navigate(action);}Tambahkan method
onAddAwayClick(View view)
padaScoreFragment
. Pada method ini berisi logika untuk berpindah keGoalFragment
. Pada perpindahan ini dikirimkan data tim home menggunakan konstantaAWAY_REQUEST_KEY
.public void onAddAwayClick(View view) {ScoreFragmentDirections.GoalScorerAction action = ScoreFragmentDirections.goalScorerAction(AWAY_REQUEST_KEY);Navigation.findNavController(view).navigate(action);}Pada Fragment
ScoreFragment
membutuhkan untuk menampung hasil data kembalian dari FragmentGoalFragment
. Untuk melakukan ini tambahkan dua buah listener baik untuk tim Home dan tim Away.ScoreFragment.java@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {FragmentScoreBinding binding = DataBindingUtil.inflate(inflater, R.layout.fragment_score, container, false);binding.setFragment(this);binding.setHomeGoalScorerList(homeGoalScorerList);binding.setAwayGoalScorerList(awayGoalScorerList);getParentFragmentManager().setFragmentResultListener(HOME_REQUEST_KEY, this, new FragmentResultListener() {@Overridepublic void onFragmentResult(@NonNull String requestKey, @NonNull Bundle result) {}});getParentFragmentManager().setFragmentResultListener(AWAY_REQUEST_KEY, this, new FragmentResultListener() {@Overridepublic void onFragmentResult(@NonNull String requestKey, @NonNull Bundle result) {}});return binding.getRoot();}Pada listener untuk
HOME_REQUEST_KEY
tambahkan logika untuk menambahkan data yang dikirimkan dari FragmentGoalFragment
.ScoreFragment.javagetParentFragmentManager().setFragmentResultListener(HOME_REQUEST_KEY, this, new FragmentResultListener() {@Overridepublic void onFragmentResult(@NonNull String requestKey, @NonNull Bundle result) {GoalScorer goalScorer = result.getParcelable(SCORER_KEY);homeGoalScorerList.add(goalScorer);}});Adaptasi logika untuk
AWAY_REQUEST_KEY
berdasarkan logika dariHOME_REQUEST_KEY
Buka layout
fragment_goal.xml
, dan tambahkan deklarasi databinding sesuai dengan inputan untuk nama pemain dan menit yang dimodelkan denganGoalScorer
. Selain itu tambahkan definisi variabelfragment
untuk menghubungkan Fragment dan layout.fragment_goal.xml<?xml version="1.0" encoding="utf-8"?><layoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"><data><variablename="fragment"type="id.ac.polinema.skor.fragments.GoalFragment" /><variablename="goalScorer"type="id.ac.polinema.skor.models.GoalScorer" /></data></layout>Tambahkan ekspresi databinding pada event tombol Save dan Cancel.
fragment_goal.xml<Buttonandroid:id="@+id/button_save"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginStart="8dp"android:layout_marginEnd="8dp"android:layout_marginBottom="8dp"android:onClick="@{(v) -> fragment.onSaveClicked(v)}"android:text="Save"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="@+id/guideline3" /><Buttonandroid:id="@+id/button_cancel"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginStart="8dp"android:layout_marginEnd="8dp"android:layout_marginBottom="8dp"android:text="Cancel"android:onClick="@{(v) -> fragment.onCancelClicked(v)}"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toStartOf="@+id/guideline3"app:layout_constraintStart_toStartOf="parent" />Buka file
GoalFragment.java
untuk mengatur databinding antara layout dan logika. Tambahkan logika berikut pada methodonCreateView()
.GoalFragment.java@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {FragmentGoalBinding binding = DataBindingUtil.inflate(inflater, R.layout.fragment_goal, container, false);binding.setFragment(this);binding.setGoalScorer(goalScorer);requestKey = GoalFragmentArgs.fromBundle(getArguments()).getRequestKey();return binding.getRoot();}Tambahkan logika berikut untuk mengirimkan data pencetak gol ke
ScoreFragment
melaluisetFragmentResult()
. Untuk kembali ke Fragment pemanggil, dapat digunakan methodnavigateUp()
.GoalFragment.javapublic void onSaveClicked(View view) {Bundle bundle = new Bundle();bundle.putParcelable(ScoreFragment.SCORER_KEY, goalScorer);getParentFragmentManager().setFragmentResult(requestKey, bundle);Navigation.findNavController(view).navigateUp();}Tambahkan logika untuk menangani aksi Cancel dengan menggunakan
navigateUp()
tanpa mengirimkan data ke Fragment pemanggil.GoalFragment.javapublic void onCancelClicked(View view) {Navigation.findNavController(view).navigateUp();}
Tantangan
Tampilkan data pemain beserta menit gol terjadi untuk masing-masing tim pada id
text_home_scorer
dan text_away_scorer
. Contoh tampilan yang diinginkan: