Kita telah belajar bagaimana berpindah dari satu fragment ke fragment lain. Nah, kurang lengkap rasanya kalau belum tahu bagaimana berpindah fragment dengan membawa data. Terdapat dua cara yakni dengan menggunakan obyek bundle dan setter and getter. Mari langsung praktikkan kedua cara tersebut.
- Buat fragment lagi dengan nama DetailCategoryFragment.
- Pada fragment_detail_category sesuaikan kodenya menjadi seperti berikut:
<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"
android:padding="16dp">
<TextView
android:id="@+id/tv_category_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/category_name" />
<TextView
android:id="@+id/tv_category_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/category_description" />
<Button
android:id="@+id/btn_profile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/to_profile" />
<Button
android:id="@+id/btn_show_dialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/show_dialog" />
</LinearLayout> - Setelah selesai, silakan lengkapi kode pada DetailCategoryFragment. Pertama, tambahkan beberapa view, dan juga casting-nya.
Kemudian metode setOnClickListener akan mengalami error karena Anda belum mengimplementasi onClick() ke DetailCategoryFragment. Maka implementasikanlah onClick di kelas fragment-nya dan juga set listener di view-nya.Kotlin class DetailCategoryFragment : Fragment(){
lateinit var tvCategoryName: TextView
lateinit var tvCategoryDescription: TextView
lateinit var btnProfile: Button
lateinit var btnShowDialog: Button
...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
tvCategoryName = view.findViewById(R.id.tv_category_name)
tvCategoryDescription = view.findViewById(R.id.tv_category_description)
btnProfile = view.findViewById(R.id.btn_profile)
btnProfile.setOnClickListener(this)
btnShowDialog = view.findViewById(R.id.btn_show_dialog)
btnShowDialog.setOnClickListener(this)
}
}Java TextView tvCategoryName;
TextView tvCategoryDescription;
Button btnProfile;
Button btnShowDialog;
...
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
tvCategoryName = view.findViewById(R.id.tv_category_name);
tvCategoryDescription = view.findViewById(R.id.tv_category_description);
btnProfile = view.findViewById(R.id.btn_profile);
btnProfile.setOnClickListener(this);
btnShowDialog = view.findViewById(R.id.btn_show_dialog);
btnShowDialog.setOnClickListener(this);
}
Dan tambahkan beberapa variabel dan berikan aksi ketika button diklik.Kotlin class DetailCategoryFragment : Fragment(), View.OnClickListener {
...
override fun onClick(v: View) {
when (v.id) {
}
}
}Java public class DetailCategoryFragment extends Fragment implements View.OnClickListener {
...
@Override
public void onClick(View v) {
switch (v.getId()) {
}
}
}
Kode di atas akan mendemonstrasikan bagaimana melakukan penampilan data yang dikirim melalui perpindahan fragment.Kotlin class DetailCategoryFragment : Fragment(), View.OnClickListener {
var description: String? = null
companion object {
var EXTRA_NAME = "extra_name"
var EXTRA_DESCRIPTION = "extra_description"
}
...
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
if (savedInstanceState != null) {
val descFromBundle = savedInstanceState.getString(EXTRA_DESCRIPTION)
description = descFromBundle
}
if (arguments != null) {
val categoryName = arguments?.getString(EXTRA_NAME)
tv_category_name.text = categoryName
tv_category_description.text = description
}
}
override fun onClick(v: View) {
when (v.id) {
R.id.btn_profile -> {
}
R.id.btn_show_dialog -> {
}
}
}
}Java public class DetailCategoryFragment extends Fragment implements View.OnClickListener {
...
public static String EXTRA_NAME = "extra_name";
public static String EXTRA_DESCRIPTION = "extra_description";
private String description;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
...
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String categoryName = getArguments().getString(EXTRA_NAME);
tvCategoryName.setText(categoryName);
tvCategoryDescription.setText(getDescription());
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_profile:
break;
case R.id.btn_show_dialog:
break;
}
}
}
Sehingga DetailCategoryFragment menjadi seperti ini:Kotlin class DetailCategoryFragment : Fragment(), View.OnClickListener {
lateinit var tvCategoryName: TextView
lateinit var tvCategoryDescription: TextView
lateinit var btnProfile: Button
lateinit var btnShowDialog: Button
var description: String? = null
companion object {
var EXTRA_NAME = "extra_name"
var EXTRA_DESCRIPTION = "extra_description"
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_detail_category, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
tvCategoryName = view.findViewById(R.id.tv_category_name)
tvCategoryDescription = view.findViewById(R.id.tv_category_description)
btnProfile = view.findViewById(R.id.btn_profile)
btnProfile.setOnClickListener(this)
btnShowDialog = view.findViewById(R.id.btn_show_dialog)
btnShowDialog.setOnClickListener(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
if (savedInstanceState != null) {
val descFromBundle = savedInstanceState.getString(EXTRA_DESCRIPTION)
description = descFromBundle
}
if (arguments != null) {
val categoryName = arguments?.getString(EXTRA_NAME)
tv_category_name.text = categoryName
tv_category_description.text = description
}
}
override fun onClick(v: View) {
when (v.id) {
R.id.btn_profile -> {
}
R.id.btn_show_dialog -> {
}
}
}
}Java public class DetailCategoryFragment extends Fragment implements View.OnClickListener {
TextView tvCategoryName;
TextView tvCategoryDescription;
Button btnProfile;
Button btnShowDialog;
public static String EXTRA_NAME = "extra_name";
public static String EXTRA_DESCRIPTION = "extra_description";
private String description;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public DetailCategoryFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_detail_category, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
tvCategoryName = view.findViewById(R.id.tv_category_name);
tvCategoryDescription = view.findViewById(R.id.tv_category_description);
btnProfile = view.findViewById(R.id.btn_profile);
btnProfile.setOnClickListener(this);
btnShowDialog = view.findViewById(R.id.btn_show_dialog);
btnShowDialog.setOnClickListener(this);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String categoryName = getArguments().getString(EXTRA_NAME);
tvCategoryName.setText(categoryName);
tvCategoryDescription.setText(getDescription());
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_profile:
break;
case R.id.btn_show_dialog:
break;
}
}
} - Baik, tinggal selangkah lagi kita menyelesaikan proses implementasi pengiriman data melalui perpindahan fragment. Sekarang buka kembali CategoryFragment lalu tambahkan baris berikut pada method onClick().
Sehingga kode CategoryFragment kita sekarang menjadi:Kotlin override fun onClick(v: View) {
if (v.id == R.id.btn_detail_category) {
val mDetailCategoryFragment = DetailCategoryFragment()
val mBundle = Bundle()
mBundle.putString(DetailCategoryFragment.EXTRA_NAME, "Lifestyle")
val description = "Kategori ini akan berisi produk-produk lifestyle"
mDetailCategoryFragment.arguments = mBundle
mDetailCategoryFragment.description = description
val mFragmentManager = fragmentManager
mFragmentManager?.beginTransaction()?.apply {
replace(R.id.frame_container, mDetailCategoryFragment, DetailCategoryFragment::class.java.simpleName)
addToBackStack(null)
commit()
}
}
}Java @Override
public void onClick(View v) {
if (v.getId() == R.id.btn_detail_category) {
DetailCategoryFragment mDetailCategoryFragment = new DetailCategoryFragment();
Bundle mBundle = new Bundle();
mBundle.putString(DetailCategoryFragment.EXTRA_NAME, "Lifestyle");
String description = "Kategori ini akan berisi produk-produk lifestyle";
mDetailCategoryFragment.setArguments(mBundle);
mDetailCategoryFragment.setDescription(description);
FragmentManager mFragmentManager = getFragmentManager();
if (mFragmentManager != null) {
mFragmentManager
.beginTransaction()
.replace(R.id.frame_container, mDetailCategoryFragment, DetailCategoryFragment.class.getSimpleName())
.addToBackStack(null)
.commit();
}
}
}Kotlin class CategoryFragment : Fragment(), View.OnClickListener {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_category, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val btnDetailCategory:Button = view.findViewById(R.id.btn_detail_category)
btnDetailCategory.setOnClickListener(this)
}
override fun onClick(v: View) {
if (v.id == R.id.btn_detail_category) {
val mDetailCategoryFragment = DetailCategoryFragment()
val mBundle = Bundle()
mBundle.putString(DetailCategoryFragment.EXTRA_NAME, "Lifestyle")
val description = "Kategori ini akan berisi produk-produk lifestyle"
mDetailCategoryFragment.arguments = mBundle
mDetailCategoryFragment.description = description
val mFragmentManager = fragmentManager
mFragmentManager?.beginTransaction()?.apply {
replace(R.id.frame_container, mDetailCategoryFragment, DetailCategoryFragment::class.java.simpleName)
addToBackStack(null)
commit()
}
}
}
}Java public class CategoryFragment extends Fragment implements View.OnClickListener {
public CategoryFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_category, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Button btnDetailCategory = view.findViewById(R.id.btn_detail_category);
btnDetailCategory.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_detail_category) {
DetailCategoryFragment mDetailCategoryFragment = new DetailCategoryFragment();
Bundle mBundle = new Bundle();
mBundle.putString(DetailCategoryFragment.EXTRA_NAME, "Lifestyle");
String description = "Kategori ini akan berisi produk-produk lifestyle";
mDetailCategoryFragment.setArguments(mBundle);
mDetailCategoryFragment.setDescription(description);
/*
Method addToBackStack akan menambahkan fragment ke backstack
Behaviour dari back button akan cek fragment dari backstack,
jika ada fragment di dalam backstack maka fragment yang akan di close / remove
jika sudah tidak ada fragment di dalam backstack maka activity yang akan di close / finish
*/
FragmentManager mFragmentManager = getFragmentManager();
if (mFragmentManager != null) {
mFragmentManager
.beginTransaction()
.replace(R.id.frame_container, mDetailCategoryFragment, DetailCategoryFragment.class.getSimpleName())
.addToBackStack(null)
.commit();
}
}
}
} - Sekarang setelah selesai semua, silakan jalankan aplikasinya untuk melihat hasil kode yang di atas. Seharusnya ketika Anda mengklik tombol Kategory Lifestyle pada CategoryFragment akan ada data yang dikirimkan sewaktu perpindahan fragment itu melalui object bundle dan mekanisme metode setter and getter. Tampilan aplikasi Anda sekarang sudah menjadi seperti ini.
Bedah Kode
Mantap! Anda sekarang sudah bisa berpindah dari satu fragment ke fragment lain dengan mengirimkan data. Ya seperti yang sudah dijelaskan di awal, ada dua mekanisme mengirimkan data antar fragment yaitu:
Dengan Menggunakan Bundle
Pada kode di atas kita menggunakan obyek bundle untuk mengirimkan data antar fragment. Perhatikan cara yang digunakan sama dengan cara yang telah kita implementasikan sebelumnya di activity. Setelah dibuat obyeknya dan data yang mau dikirimkan apa, kita hanya perlu menambahkan sebaris kode berikut:Kotlin val mBundle = Bundle()
mBundle.putString(DetailCategoryFragment.EXTRA_NAME, "Lifestyle")Java Bundle mBundle = new Bundle();
mBundle.putString(DetailCategoryFragment.EXTRA_NAME, "Lifestyle");
Cara mengambil data yang dikirimkan melalui obyek bundle pada fragment tujuan pun, sangatlah mudah. Cukup memanggil metode getArguments() di fragment DetailCategoryFragment seperti berikut:Kotlin mDetailCategoryFragment.arguments = mBundle
Java mDetailCategoryFragment.setArguments(mBundle);
Kelas Bundle merupakan kelas map data string untuk obyek-obyek parcelable. Di sini kita bisa menginput lebih dari satu parameter/variabel ke dalam obyek Bundle.Kotlin val categoryName = arguments?.getString(EXTRA_NAME)
Java String categoryName = getArguments().getString(EXTRA_NAME);
Dengan Menggunakan Setter dan Getter
Kelas fragment adalah kelas java pada umumnya, dengan menggunakan metode setter and getter untuk mengirimkan parameter/variabel dari satu fragment ke fragment lainnya. Seperti baris berikut:Kotlin val description = "Kategori ini akan berisi produk-produk lifestyle"
mDetailCategoryFragment.description = descriptionJava String description = "Kategori ini akan berisi produk-produk lifestyle";
mDetailCategoryFragment.setDescription(description);Yang mana isi kode pada kelas DetailCategoryFragment sebagai berikut:Kotlin var description: String? = null
companion object {
var EXTRA_NAME = "extra_name"
var EXTRA_DESCRIPTION = "extra_description"
}Java public static String EXTRA_NAME = "extra_name";
private String description;
public DetailCategoryFragment() {
// Required empty public constructor
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}Cara menggunakannya juga cukup mudah, yakni hanya dengan menempatkan value yang ingin dikirimkan via metode setter lalu diambil dengan menggunakan metode getter seperti pada baris berikut:Kotlin tv_category_description.text = description
Java tvCategoryDescription.setText(getDescription());
Mudah kan? Dua cara di atas sudah umum dilakukan dan diimplementasikan ke dalam project pengembangan aplikasi android. Selamat! Sejauh ini Anda sudah memahami lebih jauh tentang fragment, mulai dari bagaimana membuat, menempelkan ke activity, hingga berpindah antar fragment dengan atau tanpa membawa data.
Codelab Fragment untuk Dialog
Selanjutnya kita masuk ke pemanfaatan fragment untuk menampilkan sebuah custom dialog. Kita akan menggunakan DialogFragment lengkap dengan interaksinya. Siap? Ayo kita lanjutkan ngoding-nya.
- Buat kembali satu kelas fragment dengan nama OptionDialogFragment . Jangan lupa uncheck pilihan include fragment factory methods dan include interface methods.
- Ketika sudah diciptakan, pada fragment_option_dialog.xml kondisikan kodenya menjadi seperti berikut:
<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="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/question_coach" />
<RadioGroup
android:id="@+id/rg_options"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RadioButton
android:id="@+id/rb_saf"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/sir_alex_ferguson" />
<RadioButton
android:id="@+id/rb_mou"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/jose_mourinho" />
<RadioButton
android:id="@+id/rb_lvg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/louis_van_gaal" />
<RadioButton
android:id="@+id/rb_moyes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/david_moyes" />
</RadioGroup>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_close"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
android:layout_marginRight="4dp"
android:layout_weight="0.5"
android:text="@string/close" />
<Button
android:id="@+id/btn_choose"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:layout_weight="0.5"
android:text="@string/choose" />
</LinearLayout>
</LinearLayout> - Setelah selesai dengan berkas layout xml, lanjutkan ngoding untuk OptionDialogFragment. Pertama, kenalkan obyek yang ada di dalam layout seperti ini:
Selanjutnya kita beri aksi untuk button-nya dan beri pula kelas interface dan ubah turunannya dari Fragment menjadi DialogFragment.Kotlin private lateinit var btnChoose: Button
private lateinit var btnClose: Button
private lateinit var rgOptions: RadioGroup
private lateinit var rbSaf: RadioButton
private lateinit var rbMou: RadioButton
private lateinit var rbLvg: RadioButton
private lateinit var rbMoyes: RadioButton
private var optionDialogListener: OnOptionDialogListener? = null
...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btnChoose = view.findViewById(R.id.btn_choose)
btnChoose.setOnClickListener(this)
btnClose = view.findViewById(R.id.btn_close)
btnClose.setOnClickListener(this)
rgOptions = view.findViewById(R.id.rg_options)
rbSaf = view.findViewById(R.id.rb_saf)
rbLvg = view.findViewById(R.id.rb_lvg)
rbMou = view.findViewById(R.id.rb_mou)
rbMoyes = view.findViewById(R.id.rb_moyes)
}Java Button btnChoose, btnClose;
RadioGroup rgOptions;
RadioButton rbSaf, rbMou, rbLvg, rbMoyes;
OnOptionDialogListener optionDialogListener;
...
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
btnChoose = view.findViewById(R.id.btn_choose);
btnChoose.setOnClickListener(this);
btnClose = view.findViewById(R.id.btn_close);
btnClose.setOnClickListener(this);
rgOptions = view.findViewById(R.id.rg_options);
rbSaf = view.findViewById(R.id.rb_saf);
rbLvg = view.findViewById(R.id.rb_lvg);
rbMou = view.findViewById(R.id.rb_mou);
rbMoyes = view.findViewById(R.id.rb_moyes);
}
Kemudian tambahkan kode berikut untuk mengelola optionDialogListener ketika fragment dipanggil dan dimatikan:Kotlin class OptionDialogFragment : DialogFragment(), View.OnClickListener {
...
override fun onClick(v: View) {
when (v.id) {
R.id.btn_close -> dialog?.cancel()
R.id.btn_choose -> {
val checkedRadioButtonId = rg_options.checkedRadioButtonId
if (checkedRadioButtonId != -1) {
var coach: String? = null
when (checkedRadioButtonId) {
R.id.rb_saf -> coach = rbSaf.text.toString().trim()
R.id.rb_mou -> coach = rbMou.text.toString().trim()
R.id.rb_lvg -> coach = rbLvg.text.toString().trim()
R.id.rb_moyes -> coach = rbMoyes.text.toString().trim()
}
if (optionDialogListener != null) {
optionDialogListener?.onOptionChosen(coach)
}
dialog?.dismiss()
}
}
}
}
interface OnOptionDialogListener {
fun onOptionChosen(text: String?)
}
}Java public class OptionDialogFragment extends DialogFragment implements View.OnClickListener {
...
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_close:
getDialog().cancel();
break;
case R.id.btn_choose:
int checkedRadioButtonId = rgOptions.getCheckedRadioButtonId();
if (checkedRadioButtonId != -1) {
String coach = null;
switch (checkedRadioButtonId) {
case R.id.rb_saf:
coach = rbSaf.getText().toString().trim();
break;
case R.id.rb_mou:
coach = rbMou.getText().toString().trim();
break;
case R.id.rb_lvg:
coach = rbLvg.getText().toString().trim();
break;
case R.id.rb_moyes:
coach = rbMoyes.getText().toString().trim();
break;
}
if (optionDialogListener != null) {
optionDialogListener.onOptionChosen(coach);
}
getDialog().dismiss();
}
break;
}
}
public interface OnOptionDialogListener {
void onOptionChosen(String text);
}
}
Kondisikan kodenya menjadi sebagai berikut:Kotlin override fun onAttach(context: Context) {
super.onAttach(context)
val fragment = parentFragment
if (fragment is DetailCategoryFragment) {
val detailCategoryFragment = fragment
this.optionDialogListener = detailCategoryFragment.optionDialogListener
}
}
override fun onDetach() {
super.onDetach()
this.optionDialogListener = null
}Java @Override
public void onAttach(Context context) {
super.onAttach(context);
Fragment fragment = getParentFragment();
if (fragment instanceof DetailCategoryFragment) {
DetailCategoryFragment detailCategoryFragment = (DetailCategoryFragment) fragment;
this.optionDialogListener = detailCategoryFragment.optionDialogListener;
}
}
@Override
public void onDetach() {
super.onDetach();
this.optionDialogListener = null;
}
Ingat, jangan lupa untuk menambahkan inherit ke kelas DialogFragment.Kotlin class OptionDialogFragment : DialogFragment(), View.OnClickListener {
private lateinit var btnChoose: Button
private lateinit var btnClose: Button
private lateinit var rgOptions: RadioGroup
private lateinit var rbSaf: RadioButton
private lateinit var rbMou: RadioButton
private lateinit var rbLvg: RadioButton
private lateinit var rbMoyes: RadioButton
private var optionDialogListener: OnOptionDialogListener? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_option_dialog, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btnChoose = view.findViewById(R.id.btn_choose)
btnChoose.setOnClickListener(this)
btnClose = view.findViewById(R.id.btn_close)
btnClose.setOnClickListener(this)
rgOptions = view.findViewById(R.id.rg_options)
rbSaf = view.findViewById(R.id.rb_saf)
rbLvg = view.findViewById(R.id.rb_lvg)
rbMou = view.findViewById(R.id.rb_mou)
rbMoyes = view.findViewById(R.id.rb_moyes)
}
override fun onAttach(context: Context) {
super.onAttach(context)
val fragment = parentFragment
if (fragment is DetailCategoryFragment) {
val detailCategoryFragment = fragment
this.optionDialogListener = detailCategoryFragment.optionDialogListener
}
}
override fun onDetach() {
super.onDetach()
this.optionDialogListener = null
}
override fun onClick(v: View) {
when (v.id) {
R.id.btn_close -> dialog?.cancel()
R.id.btn_choose -> {
val checkedRadioButtonId = rg_options.checkedRadioButtonId
if (checkedRadioButtonId != -1) {
var coach: String? = null
when (checkedRadioButtonId) {
R.id.rb_saf -> coach = rbSaf.text.toString().trim()
R.id.rb_mou -> coach = rbMou.text.toString().trim()
R.id.rb_lvg -> coach = rbLvg.text.toString().trim()
R.id.rb_moyes -> coach = rbMoyes.text.toString().trim()
}
if (optionDialogListener != null) {
optionDialogListener?.onOptionChosen(coach)
}
dialog?.dismiss()
}
}
}
}
interface OnOptionDialogListener {
fun onOptionChosen(text: String?)
}
}Java public class OptionDialogFragment extends DialogFragment implements View.OnClickListener {
Button btnChoose, btnClose;
RadioGroup rgOptions;
RadioButton rbSaf, rbMou, rbLvg, rbMoyes;
OnOptionDialogListener optionDialogListener;
public OptionDialogFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_option_dialog, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
btnChoose = view.findViewById(R.id.btn_choose);
btnChoose.setOnClickListener(this);
btnClose = view.findViewById(R.id.btn_close);
btnClose.setOnClickListener(this);
rgOptions = view.findViewById(R.id.rg_options);
rbSaf = view.findViewById(R.id.rb_saf);
rbLvg = view.findViewById(R.id.rb_lvg);
rbMou = view.findViewById(R.id.rb_mou);
rbMoyes = view.findViewById(R.id.rb_moyes);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
Fragment fragment = getParentFragment();
if (fragment instanceof DetailCategoryFragment) {
DetailCategoryFragment detailCategoryFragment = (DetailCategoryFragment) fragment;
this.optionDialogListener = detailCategoryFragment.optionDialogListener;
}
}
@Override
public void onDetach() {
super.onDetach();
this.optionDialogListener = null;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_close:
getDialog().cancel();
break;
case R.id.btn_choose:
int checkedRadioButtonId = rgOptions.getCheckedRadioButtonId();
if (checkedRadioButtonId != -1) {
String coach = null;
switch (checkedRadioButtonId) {
case R.id.rb_saf:
coach = rbSaf.getText().toString().trim();
break;
case R.id.rb_mou:
coach = rbMou.getText().toString().trim();
break;
case R.id.rb_lvg:
coach = rbLvg.getText().toString().trim();
break;
case R.id.rb_moyes:
coach = rbMoyes.getText().toString().trim();
break;
}
if (optionDialogListener != null) {
optionDialogListener.onOptionChosen(coach);
}
getDialog().dismiss();
}
break;
}
}
public interface OnOptionDialogListener {
void onOptionChosen(String text);
}
} - Tambahkan beberapa baris pada metode onClick() di DetailCategoryFragment menjadi sebagai berikut:
Kotlin override fun onClick(v: View) {
when (v.id) {
R.id.btn_profile -> {
}
R.id.btn_show_dialog -> {
val mOptionDialogFragment = OptionDialogFragment()
val mFragmentManager = childFragmentManager
mOptionDialogFragment.show(mFragmentManager, OptionDialogFragment::class.java.simpleName)
}
}
}Java @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_profile:
break;
case R.id.btn_show_dialog:
OptionDialogFragment mOptionDialogFragment = new OptionDialogFragment();
FragmentManager mFragmentManager = getChildFragmentManager();
mOptionDialogFragment.show(mFragmentManager, OptionDialogFragment.class.getSimpleName());
break;
}
} - Kemudian tambahkan OptionDialogFragment pada DetailCategoryFragment seperti berikut:
Kotlin class DetailCategoryFragment : Fragment(), View.OnClickListener {
...
internal var optionDialogListener: OptionDialogFragment.OnOptionDialogListener = object : OptionDialogFragment.OnOptionDialogListener {
override fun onOptionChosen(text: String?) {
Toast.makeText(activity, text, Toast.LENGTH_SHORT).show()
}
}
}Java public class DetailCategoryFragment extends Fragment implements View.OnClickListener {
...
OptionDialogFragment.OnOptionDialogListener optionDialogListener = new OptionDialogFragment.OnOptionDialogListener() {
@Override
public void onOptionChosen(String text) {
Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT).show();
}
};
} - Sehingga kode DetailCategoryFragment kita saat ini menjadi seperti ini:
Kotlin class DetailCategoryFragment : Fragment(), View.OnClickListener {
lateinit var tvCategoryName: TextView
lateinit var tvCategoryDescription: TextView
lateinit var btnProfile: Button
lateinit var btnShowDialog: Button
var description: String? = null
companion object {
var EXTRA_NAME = "extra_name"
var EXTRA_DESCRIPTION = "extra_description"
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_detail_category, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
tvCategoryName = view.findViewById(R.id.tv_category_name);
tvCategoryDescription = view.findViewById(R.id.tv_category_description);
btnProfile = view.findViewById(R.id.btn_profile);
btnProfile.setOnClickListener(this);
btnShowDialog = view.findViewById(R.id.btn_show_dialog);
btnShowDialog.setOnClickListener(this);
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
if (savedInstanceState != null) {
val descFromBundle = savedInstanceState.getString(EXTRA_DESCRIPTION)
description = descFromBundle
}
if (arguments != null) {
val categoryName = arguments?.getString(EXTRA_NAME)
tv_category_name.text = categoryName
tv_category_description.text = description
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString(EXTRA_DESCRIPTION, description)
}
override fun onClick(v: View) {
when (v.id) {
R.id.btn_profile -> {
val mIntent = Intent(activity, ProfileActivity::class.java)
startActivity(mIntent)
}
R.id.btn_show_dialog -> {
val mOptionDialogFragment = OptionDialogFragment()
val mFragmentManager = childFragmentManager
mOptionDialogFragment.show(mFragmentManager, OptionDialogFragment::class.java.simpleName)
}
}
}
internal var optionDialogListener: OptionDialogFragment.OnOptionDialogListener = object : OptionDialogFragment.OnOptionDialogListener {
override fun onOptionChosen(text: String?) {
Toast.makeText(activity, text, Toast.LENGTH_SHORT).show()
}
}
}Java public class DetailCategoryFragment extends Fragment implements View.OnClickListener {
TextView tvCategoryName;
TextView tvCategoryDescription;
Button btnProfile;
Button btnShowDialog;
public static String EXTRA_NAME = "extra_name";
public static String EXTRA_DESCRIPTION = "extra_description";
private String description;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public DetailCategoryFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_detail_category, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
tvCategoryName = view.findViewById(R.id.tv_category_name);
tvCategoryDescription = view.findViewById(R.id.tv_category_description);
btnProfile = view.findViewById(R.id.btn_profile);
btnProfile.setOnClickListener(this);
btnShowDialog = view.findViewById(R.id.btn_show_dialog);
btnShowDialog.setOnClickListener(this);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
String descFromBundle = savedInstanceState.getString(EXTRA_DESCRIPTION);
setDescription(descFromBundle);
}
if (getArguments() != null) {
String categoryName = getArguments().getString(EXTRA_NAME);
tvCategoryName.setText(categoryName);
tvCategoryDescription.setText(getDescription());
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(EXTRA_DESCRIPTION, getDescription());
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_profile:
break;
case R.id.btn_show_dialog:
OptionDialogFragment mOptionDialogFragment = new OptionDialogFragment();
FragmentManager mFragmentManager = getChildFragmentManager();
mOptionDialogFragment.show(mFragmentManager, OptionDialogFragment.class.getSimpleName());
break;
}
}
OptionDialogFragment.OnOptionDialogListener optionDialogListener = new OptionDialogFragment.OnOptionDialogListener() {
@Override
public void onOptionChosen(String text) {
Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT).show();
}
};
} - Sekarang jalankan kembali aplikasi dan klik pada tombol Tampilkan sebuah dialog. Hasilnya akan muncul obyek OptionDialogFragment yang baru saja dibuat. Coba Anda pilih salah satu option yang ada dan klik tombol Pilih. Lihat, hasil dari yang kita pilih, tampil dalam bentuk soft message (Toast).
Bedah Kode
DialogFragment
Kotlin |
class OptionDialogFragment : DialogFragment() |
Java |
public class OptionDialogFragment extends DialogFragment |
Sama dengan obyek fragment seperti sebelumnya, di sini kelas fragment yang kita buat inherit ke DialogFragment. Dengan begitu obyek fragment sekarang merupakan obyek dialog yang akan tampil mengambang di layar. Seperti pada obyek modal pada platform lain, obyek DialogFragment dapat disesuaikan tampilan dan fungsinya secara spesifik. Di sini kita menampillkan sebuah dialog ke pengguna untuk memilih sebuah opsi yang tersedia
Kotlin |
internal var optionDialogListener: OptionDialogFragment.OnOptionDialogListener = object : OptionDialogFragment.OnOptionDialogListener { |
Java |
public final OptionDialogFragment.OnOptionDialogListener optionDialogListener = new OptionDialogFragment.OnOptionDialogListener() { |
OptionDialogFragment mOptionDialogFragment = new OptionDialogFragment();
mOptionDialogFragment.setOnOptionDialogListener(new OptionDialogFragment.OnOptionDialogListener() {
@Override
public void onOptionChosen(String text) {
Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT).show();
}
});
Kotlin |
val mFragmentManager = childFragmentManager |
Java |
FragmentManager mFragmentManager = getChildFragmentManager(); |
Proses pemanggilannya pun hampir sama dengan yang kita lakukan sebelumnya. Namun perbedaanya ada di sini:
Kotlin |
val mFragmentManager = childFragmentManager |
Java |
FragmentManager mFragmentManager = getChildFragmentManager(); |
Kita tidak menggunakan getFragmentManager() saat ini. Alih- alih, getChildFragmentManager() merupakan pilihan yang tepat untuk kondisi saat ini, yakni sebuah nested fragment / fragment bersarang. Karena OptionDialogFragment dipanggil di dalam sebuah obyek fragment yang telah ada sebelumnya yaitu DetailDialogFragment, maka demi performa lebih baik gunakanlah getChildFragmentManager() sebagai pilihan yang lebih tepat.
Kotlin |
mOptionDialogFragment.show(mFragmentManager, OptionDialogFragment::class.java.simpleName) |
Java |
mOptionDialogFragment.show(mFragmentManager, OptionDialogFragment.class.getSimpleName()); |
Baris di atas digunakan untuk menampilkan obyek OptionDialogFragment ke layar.
Untuk proses handling event ketika tombol Pilih pada OptionDialogFragment diklik, kita menggunakan implementasi interface. Bagi yang belum paham tentang definisi interface pada pemrograman Java, inilah definisi singkatnya.
Interface adalah sebuah kelas yang terdiri kumpulan method yang hanya memuat deklarasi dan struktur method, tanpa detail implementasinya.
Tautan berikut akan membantu pemahaman Anda tentang Interface.
Kelas interface yang kita punya pada OptionDialogFragment adalah sebagai berikut:
Kotlin |
interface OnOptionDialogListener { |
Java |
public interface OnOptionDialogListener{ |
Di mana kita menggunakannya pada bagian ini:
Kotlin |
val checkedRadioButtonId = rgOptions.checkedRadioButtonId |
Java |
int checkedRadioButtonId = rgOptions.getCheckedRadioButtonId(); |
Dan mengimplementasikannya pada bagian ini:
Kotlin |
internal var optionDialogListener: OptionDialogFragment.OnOptionDialogListener = object : OptionDialogFragment.OnOptionDialogListener { |
Java |
mOptionDialogFragment.setOnOptionDialogListener(new OptionDialogFragment.OnOptionDialogListener() { |
Jadi ketika pengguna menekan tombol Pilih setelah memilih salah satu pilihan, baris ini akan dieksekusi:
Kotlin |
optionDialogListener?.onOptionChosen(coach) |
Java |
getOnOptionDialogListener().onOptionChosen(coach); |
Kotlin |
internal var optionDialogListener: OptionDialogFragment.OnOptionDialogListener = object : OptionDialogFragment.OnOptionDialogListener { |
Java |
mOptionDialogFragment.setOnOptionDialogListener(new OptionDialogFragment.OnOptionDialogListener() { |
Cool, sejauh ini kami harap Anda sudah lebih memahami tentang bentuk dan implementasi fragment seperti apa.
Codelab Memanggil Activity dari fragment
Terakhir sebelum sesi ini selesai kita akan belajar bagaimana menjalankan sebuah activity dari fragment. Caranya pun hampir sama dengan apa yang telah kita pelajari di activity.- Buat sebuah activity dengan nama ProfileActivity.
- Setelah terbentuk, pada activity_profile.xml kondisikan kode yang ada menjadi sebagai berikut:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:padding="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/this_profile" />
</RelativeLayout> - Kemudian pada method onClick() pilihan R.id.btn_profile di kelas DetailCategoryFragment , tambahkan beberapa baris berikut untuk menjalankan ProfileActivity:
Kotlin override fun onClick(v: View) {
when (v.id) {
R.id.btn_profile -> {
val mIntent = Intent(activity, ProfileActivity::class.java)
startActivity(mIntent)
}
R.id.btn_show_dialog -> {
val mOptionDialogFragment = OptionDialogFragment()
val mFragmentManager = childFragmentManager
mOptionDialogFragment.show(mFragmentManager, OptionDialogFragment::class.java.simpleName)
}
}
}Java @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_profile:
Intent mIntent = new Intent(getActivity(), ProfileActivity.class);
startActivity(mIntent);
break;
case R.id.btn_show_dialog:
OptionDialogFragment mOptionDialogFragment = new OptionDialogFragment();
FragmentManager mFragmentManager = getChildFragmentManager();
mOptionDialogFragment.show(mFragmentManager, OptionDialogFragment.class.getSimpleName());
break;
}
} - Setelah selesai semua, coba jalankan aplikasi Anda dan klik tombol Ke Halaman Profile Activity.
Bedah Kode
Perbedaan Activity dan Fragment
Lihat kode di bawah ini:
Kotlin |
val mIntent = Intent(activity, ProfileActivity::class.java) |
Java |
Intent mIntent = new Intent(getActivity(), ProfileActivity.class); |
Mengapa pakai activity/getActivity() ? Padahal pada modul tentang Intent sebelumnya, kita menggunakan this@MainActivity/MainActivity.this sebagai context. Hal ini karena kita menggunakan Fragment, sedangkan fungsi this hanya bisa dipanggil melalui Activity. Oleh karena itulah, kita menggunakan activity/getActivity() untuk mendapatkan context dari activity tempat fragment ini menempel.
Perbedaan yang lainnya yaitu dalam pemanggilan id, contohnya di bawah ini:
Kotlin |
class DetailCategoryFragment : Fragment(){ |
Java |
@Override |
Jika pada activity anda dapat langsung memanggil findViewById tanpa kode view. di depannya, namun pada fragment anda harus membutuhkan kode tersebut, mengapa demikian? Hal ini karena pada fragment dalam inisialisasi layout kita menggunaan inflater yang kemudian pada method onCreateView masuk pada variabel view.
Jadi, itulah dua perbedaan antara fragment dan activity dari segi kode yaitu:
Jadi, itulah dua perbedaan antara fragment dan activity dari segi kode yaitu:
- Context menggunakan getActivity/activity, bukan this@MainActivity/MainActivity.this
- Pemanggilan id menggunakan view.findFiewById, bukan findFiewById
Anda telah melalui banyak perjuangan dan menulis banyak barisan kode. Anda sudah berhasil memahami bagaimana komponen fragment bekerja. Selanjutnya, akan ada codelab tentang implementasi lanjut dari fragment. Ayo kita lanjut lagi, Semangat ngoding!
Untuk source code bagian ini bisa Anda unduh di