Membuat dan Menggunakan Fragment

Level intermediate, pembaca diasumsikan sudah memahami dasar-dasar pembuatan aplikasi Android

Pendahuluan

Fragment adalah sebuah reuseable class yang mengimplement beberapa fitur sebuah Activity. Fragment biasanya dibuat sebagai bagian dari suatu antarmuka. Sebuah fragment harus berada di dalam sebuah activity, mereka tidak dapat berjalan sendiri tanpa adanya activity tempat mereka menempel.

Fragments

Memahami Fragment

Berikut ini beberapa hal yang perlu dipahami tentang fragment:

  • Sebuah Fragment merupakan kombinasi sebuah layout XML dan kelas java yang mirip dengan sebuah Activity.
  • Dengan menggunakan support library, fragment dapat mendukung hampir semua versi Android.
  • Fragment dapat dipakai berulang kali didalam activity.
  • Fragment merupakan komponen utuh yang memiliki view, event, dan logic (meskipun tetap membutuhkan sebuah fragment agar dapat bekerja).

Dalam arsitektur berorientasi fragment, activity menjadi navigational container yang bertugas untuk melakukan navigasi ke activity lain, menampilkan fragment dan mengirim data.

Pentingnya Sebuah Fragment

Ada banyak kasus yang dapat diselesaikan menggunakan fragment, namun yang paling umum adalah:

  • Penggunaan Komponen View dan Logic Berulang Kali - Fragment dapat dipakai untuk menampilkan data atau melakukan event tertentu dibeberapa activity berbeda.
  • Dukungan Untuk Tablet - Dibeberapa aplikasi, versi tablet dari sebuah activity memberikan layout yang berbeda dari versi handphone yang juga berbeda dari versi TV. Fragment memungkinkan activity untuk menggunakan fragment dalam membuat antarmuka sesuai dengan perangkat yang membukanya.
  • Orientasi Layar - Seringkali dalam aplikasi, versi portrait dan landscape sebuah aplikasi memiliki layout yang berbeda. Fragment memungkinkan kedua orientasi tersebut untuk menggunakan tampilan yang berbeda menggunakan elemen yang sama.

Mengorganisasi Kode Fragment

Dalam aplikasi yang menggunakan banyak fragment, kita perlu selalu ingat untuk mengorganisasikan kode kita agar mengikuti best practice. Di dalam sebuah aplikasi yang memakai banyak fragment, kita harus selalu ingat fungsi dari perpindahan activity.

Activity adalah navigation controller yang bertugas untuk:

  • Pindah ke activity lain melalui intent.
  • Menampilkan komponen navigasi seperti navigation drawer atau viewpager.
  • Menampilkan dan menyembunyikan fragment tertentu menggunakan fragment manager.
  • Menerima data dari intent yang mengirim data antar fragment.

Fragments adalah content controllers dan memiliki view, layout, serta event logic sendiri:

  • Layout dan view menampilkan konten aplikasi yang relevan.
  • Melakukan management view seperti visibility atau error handling.
  • Memulai network request melalui objek klien.
  • Menerima dan menyimpan data dari atau ke database.

Diulangi lagi, dalam arsitektur berbasis fragment, activity bertugas sebagai navigasi dan fragment untuk menampilkan data yang melakukan logic aplikasi.

Penggunaan

Membuat Sebuah Fragment

Sebuah fragment, seperti activity, memiliki XML layout-nya sendiri dan sebuah kelas java sebagai controller dari Fragment tersebut.

Layout XML yang dimiliki oleh fragment, sama seperti layout-layout lainnya dan bisa memiliki nama apa saja (selama memiliki format yang ditentukan). Anggap kita memiliki layout sebagai berikut:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />

</LinearLayout>

Dengan sebuah kelas Java sebagai controller:

import android.support.v4.app.Fragment;

public class FooFragment extends Fragment {
    // Method onCreateView dipanggil saat Fragment harus menampilkan layoutnya 		// dengan membuat layout tersebut secara manual lewat objek View atau dengan 	 // membaca file XML
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        // Layout tampilan untuk fragment ini
        return inflater.inflate(R.layout.fragment_foo, parent, false);
    }
	
    // Method ini dipanggil sesaat setelah onCreateView().
    // Semua pembacaan view dan penambahan listener dilakukan disini (atau 			// bisa juga didalam onCreateView)
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        // EditText etFoo = (EditText) view.findViewById(R.id.etFoo);
    }
}

Menempelkan Fragment Kedalam Activity

Ada dua cara untuk menempelkan sebuah fragment ke activity: secara dinamis menggunakan Java dan secara statis (manual) dengan XML.

Sebelum menempelkan fragment dari library "support" didalam Activity, pastikan bahwa Activity sudah meng-extends FragmentActivity atau AppCompatActivity yang memiliki fragment manager untuk semua versi Android.

import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    // ...
}

Menempelkan Fragment Secara Statis (Manual)

Untuk menempelkan fragment secara statis (manual), cukup tambahkan elemen fragment ke dalam layout milik sebuah activity dimana kita menentukan nama dari Fragment yang akan ditampilkan lewat elemen tersebut.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <fragment
        android:name="com.example.android.FooFragment"
        android:id="@+id/fooFragment"
        android:layout_width="match_parent" 
        android:layout_height="match_parent" />

</LinearLayout>

Catatan:

  • Sesuaikan path FooFragment untuk mengikuti package name aplikasi kita.
  • Kita tidak dapat mengganti fragment yang ditambahkan secara statis lewat file XML menggunakan FragmentTransaction (baca di bawah). Kita hanya bisa mengganti fragment yang ditempelkan secara dinamis.

Menempelkan Fragment Secara Dinamis

Cara yang kedua ialah dengan menempelkan fragment secara dinamis menggunakan Java dengan melalui FragmentManager. Kelas FragmentManager dan kelas FragmentTransaction memungkinkan kita untuk menambah, menghapus dan menimpa fragment yang ada di layout saat activity sedang aktif.

Dalam kasus ini kita membutuhkan sebuah container (biasanya menggunakan FrameLayout) ke dalam activity dimana kita bisa menempelkan sebuah fragment.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

  <FrameLayout
       android:id="@+id/your_placeholder"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
  </FrameLayout>

</LinearLayout>

lalu kita dapat menggunakan FragmentManager untuk membuat sebuah FragmentTransaction yang mengijinkan kita menambah fragment ke FrameLayout di atas:

// Memulai transaksi 
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
// mengganti isi container dengan fragment baru 
ft.replace(R.id.your_placeholder, new FooFragment());
// atau ft.add(R.id.your_placeholder, new FooFragment());
// mulai melakukan hal di atas (jika belum di commit maka proses di atas belum dimulai)
ft.commit();

Jika sebuah fragment harus selalu ada di dalam activity, gunakan XML untuk meanmpilkannya secara statis namun saat menemukan kasus yang lebih kompleks pastikan untuk menggunakan pendekatan menggunakan Java.

Fragment Lifecycle

Fragment memiliki banyak method yang dapat di override seperti halnya Activity:

  • onAttach() dipanggil saat sebuah fragment terhubung ke activity.
  • onCreate() diapnggil saat sebuah fragment dibuat (objeknya di memori).
  • onCreateView() dipanggil saat fragment sudah siap membaca sebuah layout.
  • onViewCreated() dipanggil setelah onCreateView() dan memastikan layout yang dibaca fragment adalah non-null. Semua pengaturan view seperti pembacaan findViewById, menambah onClickListener dapat dilakukan di sini.
  • onActivityCreated() dipanggil setelah activity pembaca sudah menyelesaikan onCreate()-nya.
  • onStart() dipanggil setelah fragment siap untuk ditampilkan di layar.
  • onResume() - Dipakai untuk melakukan pembacaan data yang lebih "rumit" seperti lokasi, sensor, dll.
  • onPause() - Tempat melepas data "rumit". Lakukan commit di sini.
  • onDestroyView() dipanggil saat layout sebuah fragment akan dihapus dari memori, namun fragmentnya masih ada di memori.
  • onDestroy() dipanggil jika fragment sudah tidak dipakai.
  • onDetach() dipanggil saat fragment tidak lagi terhubung ke sebuah activity.

urutan eksekusi lifecycle dapat dilihat pada gambar di bawah:

Yang paling sering di override adalah onCreateView karena hampir setiap fragment akan memerlukan sebuah layout, onCreate saat ingin menginisialisasi data dan onActivityCreated untuk menyiapkan sesuatu saat Activity sudah sempurna dimuat.

Berikut ini contoh bagaimana kita bisa memanfaatkan event lifecycle milik fragment:

public class SomeFragment extends Fragment {
    ThingsAdapter adapter;
    FragmentActivity listener;
    // Event ini dipanggil pertam akali sebelum pembuatan fragment atau pembacaan
    // layout lain. Method onAttach dipanggil saat sebuah instance Fragment 
    // terhuubng dengan sebuah Activity.
    // Method ini tidak berarti Activity sudah dimuat sempurna.
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof Activity){
            this.listener = (FragmentActivity) context;
        }
    }
    
    // Event ini dipanggil kedua, sebelum layout dibaca dan method onCreate
    // didalam Fragment dipanggil saat instance Fragment tersebut sebuah dibuat
    // atau dibuat ualng.
    // Gunakan onCreate untuk pengaturan standar lainnya yang tidak mensyaratkan
    // activity dimuat terlebih dahulu.
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ArrayList<Thing> things = new ArrayList<Thing>();
        adapter = new ThingsAdapter(getActivity(), things);
    }

    // Method onCreateView dipanggil saat Fragment harus membuat layoutnya
    // menggunakan objek View di Java secara dinamis atau membacanya dari XML.
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_some, parent, false);
    }
	
	// Event ini dipanggil sesaat setelah onCreateView().
	// onViewCreated hanya dipanggil jika sebuah view dari onCreateView() tidak 
	// null.
	// Pembacaan findViewById atau listener lainnya dapat dilakukan di sini.
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        ListView lv = (ListView) view.findViewById(R.id.lvSome);
        lv.setAdapter(adapter);
    }

	// Method ini dipanggil saat fragment sudah tidak terhubung dengan Activity.
	// Semua reference yang dipasang di onAttach harus dilepas disini untuk
	// menghindari memory leak.
    @Override
    public void onDetach() {
        super.onDetach();
        this.listener = null;
    }
        
    // method ini dipanggil saat method onCreate() milik Activity yang memanggilnya
    // sudah sempurna dijalankan. 
    // Dimethod ini kita bisa membaca objek miliki Activity berdasarkan viewnya. 
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }
}

Mencari Fragment yang Sudah Dibuat

Seringkali kita perlu mencari sebuah instance fragment didalam layout activity. Ada beberapa cara yang dapat kita gunakan untuk mencari sebuah instance fragment yang sebelumnya telah dibuat:

  1. ID - Mencari fragment dengan memanggil findFragmentById di FragmentManager
  2. Tag - Mencari fragment dengan memanggil findFragmentByTag di FragmentManager
  3. Pager - Mencari fragment dengan memanggil getRegisteredFragment di PagerAdapter

Setiap teknik di atas dibahas secara mendetail di bawah ini.

Mencari Fragment Berdasarkan ID

Jika fragment ditempelkan secara manual di XML (menggunakan elemen <fragment>) dengan sebuah android:id misalnya fragmentDemo maka kita bisa membaca fragment ini berdasarkan id yang dia miliki menggunakan findFragmentById pada FragmentManager:

public class MainActivity extends AppCompatActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState == null) {
          DemoFragment fragmentDemo = (DemoFragment) 
              getSupportFragmentManager().findFragmentById(R.id.fragmentDemo);
        }
    }
}

Mencari Fragment Berdasarkan Tag

Jika fragment ditambah secara dinamis maka kita bisa mencarinya menggunakan findFragemntByTag pada FragmentManager:

public class MainActivity extends AppCompatActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState == null) {
          // Kita tambahkan dulu sebuah fragment dengan sebuah TAG
          getSupportFragmentManager().beginTransaction(). 
              replace(R.id.flContainer, new DemoFragment(), "SOMETAG").
              commit();
          // Kita bisa membaca fragment di atas dengan memanfaatkan TAG yang
          // telah diberikan
          DemoFragment fragmentDemo = (DemoFragment) 
              getSupportFragmentManager().findFragmentByTag("SOMETAG");
        }
    }
}

Mencari Fragment didalam Pager

Jika sebuah fragment ditambahkan secara dinamis menggunakan ViewPager dan sebuah FragmentPagerAdapter maka kita bisa mencari fragment di dalamnya dengan menggantinya menjadi SmartFragmentStatePagerAdapter seperti dijelaskan di panduan ViewPager ini. Sekarang dengan adapter yang sudah di upgrade, kita bisa dengan mudah mengakses fragment di dalamnya menggunakan getRegisteredFragment:

// returns first Fragment item within the pager
adapterViewPager.getRegisteredFragment(0); 

Ingat bahwa ViewPager membaca fragment seperti ListView dengan me-recycle fragment saat mereka tampil di layar. Jika kita mencoba mengakses fragment yang tidak ada di layar, maka pembacaan ini bisa mendapatkan data null.

Berkomunikasi dengan Fragment (Kirim Data)

Fragment pada umumnya hanya berkomunikasi secara langsung dengan activity yang menampilkannya. Fragment dapat berkomunikasi melalui activity yang membacanya untuk mengatur data input dan output dari fragment tersebut ke fragment lain atau activity lain. Cukup anggap Activity sebagai controller yang mengatur interaksi antar fragment yang dia baca.

Beberapa pengecualian untuk teori di atas adalah dialog fragments yang ditampilkan dari dalam fragment lain atau nested child fragments. Kedua kasus ini adalah situasi di mana sebuah fragment memiliki nested child fragments dan boleh berkomunikasi dengan parent-nya langsung (yang merupakan sebuah fragment) tanpa melalui activity tempat fragment utama menempel.

Hal penting lainnya yang perlu diingat adalah fragment tidak semestinya berkomunikasi dengan fragment lain secara langsung dan sebaiknya hanya berkomunikasi melalui parent activity.

Ada tiga cara sebuah fragment dan sebuah activity dapat berkomunikasi:

  1. Bundle - Activity dapat membuat sebuah fragment dan menambahkan arguments
  2. Methods - Activity dapat memanggil method di dalam instance fragment
  3. Listener - Fragment dapat memanggil event listener di dalam sebuah activity lewat sebuah interface.

Dengan kat alain, komunikasi yang terjadi seharusnya mengikuti prinsip-prinsip berikut:

  • Activity dapat menginisialisasi fragment dengan data saat dibuat.
  • Activity dapat mengirim data ke fragment menggunakan method yang ada di dalam instance si fragment.
  • Fragment dapat berkomunikasi dengan parent activity menggunakan sebuah interface dan listener.
  • Fragment harus mengirimkan data ke fragment lain melalui parent activity-nya.
  • Fragment dapat mengirim data dari dan ke dalam dialog fragment secara langsung.
  • Fragment dapat memiliki nested child fragment.

Fragment dengan Argument

Dalam beberapa kasus, fragment kita mungkin perlu meminta argument tertentu. Pola yang paling umum ialah dengan membuat method static bernama newInstace untuk membuat sebuah Fragment dengan argument. Hal ini karena kita hanya boleh memiliki sebuah constructor tanpa argument papun. Di dalam method newInstance ini kita dapat memanggil setArguments:

public class DemoFragment extends Fragment {
    // Membuat sebuah fragment engan sebuah int dan title
    // DemoFragment.newInstance(5, "Hello");
    public static DemoFragment newInstance(int someInt, String someTitle) {
        DemoFragment fragmentDemo = new DemoFragment();
        Bundle args = new Bundle();
        args.putInt("someInt", someInt);
        args.putString("someTitle", someTitle);
        fragmentDemo.setArguments(args);
        return fragmentDemo;
    }
}

Kode di atas memberikan argument ke fragment untuk dipanggil nanti di dalam onCreate. Kita dapat mengakses argument ini nanti menggunakna:

public class DemoFragment extends Fragment {
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       // Ambil lagi argument tadi
       int SomeInt = getArguments().getInt("someInt", 0);	
       String someTitle = getArguments().getString("someTitle", "");	
   }
}

Sekarang kita bisa membaca sebuah fragment secara dinamis di dalam sebuah Activity menggunakan:

// Di dalam activity
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
DemoFragment fragmentDemo = DemoFragment.newInstance(5, "my title");
ft.replace(R.id.your_placeholder, fragmentDemo);
ft.commit();

Pola ini membuat proses pengiriman fragment ke fragment menjadi lebih jelas.

Method Fragment

Jika sebuah activity mengingimkan sebuah fragment melakukan suatu aksi setelah dibuat, cara paling mudah ialah dengan memanggil method dari dalam instance si fragment. Di dalam fragment, buat sebuah method:

public class DemoFragment extends Fragment {
  public void doSomething(String param) {
      // lakukan sesuatu
  }
}

lalu di dalam activity, panggil method tadi:

public class MainActivity extends AppCompatActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        DemoFragment fragmentDemo = (DemoFragment) 
            getSupportFragmentManager().findFragmentById(R.id.fragmentDemo);
        fragmentDemo.doSomething("some param");
    }
}

maka activity dapat berkomunikasi secara langsung dengan si fragment menggunakan cara ini.

Fragment Listener

Jika fragment perlu berkomunikasi dengan parent activity-nya secara langsung, maka fragment tersebut perlu mendefinisikan sebuah interface dan meminta activity untuk mengimplement interface ini.

import android.support.v4.app.Fragment;

public class MyListFragment extends Fragment {
  // ...
  // Buat objek untuk listener
  private OnItemSelectedListener listener;
  
  // Definisikan event yang harus ada di dalam sebuah interface
  public interface OnItemSelectedListener {
    // Dapat berupa event apapun
    public void onRssItemSelected(String link);
  }
  
  // Simpan listener yang akan terpanggil dari suatu event setelah fragment-nya ter-attach di activity
  @Override
  public void onAttach(Context context) {
      super.onAttach(context);
      if (context instanceof OnItemSelectedListener) {
        listener = (OnItemSelectedListener) context;
      } else {
        throw new ClassCastException(context.toString()
            + " must implement MyListFragment.OnItemSelectedListener");
      }
  }
 
  // Sekarang kita dapat memanggil event dari dalam fragment
  public void onSomeClick(View v) {
     listener.onRssItemSelected("some link");
  }
}

dan di dalam activity kita perlu meng-implement listener OnItemSelectedListener:

import android.support.v7.app.AppCompatActivity;

// Activity perlu mengimplement listener di atas untuk meng-handle event
public class RssfeedActivity extends AppCompatActivity implements MyListFragment.OnItemSelectedListener {
    // Dapat berupa fragment apapun, DetailFragment hanya contoh
    DetailFragment fragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rssfeed);
        // membaca fragment menggunakan id
        fragment = (DetailFragment) getSupportFragmentManager()
            .findFragmentById(R.id.detailFragment);
  }
  
  // Sekarang kita bisa mendefinisikan aksi yang perlu dilakukan oleh activity
  // saat fragment dijalankan
  // Kita meng-implement method yang didefinisikan didalam interface `OnItemSelectedListener` yang sebelumnya kita buat di dalam Fragment
  @Override
  public void onRssItemSelected(String link) {
      if (fragment != null && fragment.isInLayout()) {
          fragment.setText(link);
      }
  }
}

Memahami FragmentManager

FragmentManager bertugas untuk melakukan manajemen fragment saat aplikasi berjalan termasuk didalamnya menambah, menghapus, menampilkan atau melakukan navigasi antar fragment. Seperti terlihat pada contoh-contoh di atas, fragment manager juga dapat dipakai untuk mencari fragment di dalam sebuah activity. Method penting dari FragmentManager adalah sebagai berikut:

Method Deskripsi
addOnBackStackChangedListener Menambah listener untuk back stack fragment.
beginTransaction() Membuat transaksi baru untuk merubah fragment saat program berjalan.
findFragmentById(int id) Mencari fragment berdasarkan id yang biasanya ditulis di layout XML milik activity.
findFragmentByTag(String tag) Mencari fragment berdasarkan tag jika menambah fragment secara dinamis.
popBackStack() Menghapus sebuah fragment dari backstack.
executePendingTransactions() Memaksa transaksi untuk diaplikasikan.

ActionBar Menu Items dan Fragments

Dalam beberapa kasus kita ingin agar sebuah fragment memiliki menu item sendiri yang hanya tampil saat fragment tersebut aktif. Kasus ini dapat diselesaikan dengan menambah method onCreateOptionsMenu ke fragment tersebut. Cara kerjanya mirip dengan yang ada di Activity:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
   inflater.inflate(R.menu.fragment_menu, menu);
}

Kita juga harus memberitahu fragment bahwa ia memiliki menu item di dalam onCreate:

@Override
public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setHasOptionsMenu(true);
}  

Klik dapat ditanganai seperti pada activity dengan method onOptionsItemSelected:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
   // handle item selection
   switch (item.getItemId()) {
      case R.id.edit_item:
         // do s.th.
         return true;
      default:
         return super.onOptionsItemSelected(item);
   }
}

Navigasi Antar Fragments

Ada beberapa method untuk melakukan navigasi antar fragment yang berbeda di dalam satu Activity. Solusi-solusi utamanya adalah:

There are several methods for navigating between different fragments within a single Activity. The primary options are:

  1. TabLayout - Tabs di atas
  2. Fragment Navigation Drawer - Menyeret menu navigasi dari samping
  3. ViewPager - Geser antar fragment untuk pindah

Manajemen Backstack Fragment

Catatan untuk semua transaksi Fragment disimpan oleh setiap Activity melalui FragmentManager. Saat diatur dengan benar, pengguna dapat menghapus fragment terakhir yang ditambahkan saat tombol back ditekan (tidak langsung keluar dari activity). Cukup panggil addToBackstack disetiap FragmentTransaction:

// Membuat transaksi
FragmentTransaction fts = getSupportFragmentManager().beginTransaction();
// Mengganti konten f1Container dengan FirstFragment
fts.replace(R.id.flContainer, new FirstFragment());	
// Menambah transaksi ini ke backstack
fts.addToBackStack("optional tag");
// Commit the changes
fts.commit();

Kita juga dapat menghapus fragment terakhir yang ditambahkan lewat kode Java menggungkan objek manager:

FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
    fragmentManager.popBackStack();
}

Dengan teknik ini kita dapat mencatat urutan fragmen yang tampil secara dinamis dan memungkinkan pengguna untuk pindah ke fragment-fragment sebelumnya.

Hide vs Replace

Dapat contoh-contoh di atas, kita memanggil transaction.replace(...) untuk membaca fragment secara dinamis dengan menghapus fragment yang sebelumnya sudah ada di container. Method ini akan memanggil onStop dan onDestroy untuk fragment sebelumnya lalu membuat fragment baru di container tadi. Cara ini baik karena kita bisa membersihkan memori dan membuat UI lebih smooth. Namun, dalam banyak kasus kita ingin akan fragment-fragment tersebut tetap ada di container dengan menampilkannya dengan mengatur visibility-nya saja. Dengan begini semua fragment terlihat seperti saat terakhir sebelum pindah fragment:

// Di dalam activity

private FragmentA fragmentA;
private FragmentB fragmentB;
private FragmentC fragmentC;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if (savedInstanceState == null) {
        fragmentA = FragmentA.newInstance("foo");
        fragmentB = FragmentB.newInstance("bar");
        fragmentC = FragmentC.newInstance("baz");
    }
}

protected void displayFragmentA() {
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    // menghapus fragment sebelumnya
    ft.replace(R.id.flContainer, fragmentA); 
    ft.commit();
}

teknik di bawah menambah add, show, dan hide di FragmentTransaction:

// ...onCreate masih sama

// Ganti cara perpindahannya
protected void displayFragmentA() {
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    if (fragmentA.isAdded()) { // jika fragment sudah ada di container tampilkan
        ft.show(fragmentA);
    } else { // jika tidak ada tambahkan
        ft.add(R.id.flContainer, fragmentA, "A");
    }
    // Sembunyikan fragment B
    if (fragmentB.isAdded()) { ft.hide(fragmentB); }
    // Sembunyikan fragment  C
    if (fragmentC.isAdded()) { ft.hide(fragmentC); }
    // Commit perubahan
    ft.commit();
}

Dengan teknik ini ketiga fragment tetap ada di container dan perpindahannya hanya dilakukan dengan mengatur visibility-nya saja.

Fragment di dalam Fragment

Terkadang kita perlu menambah fragment di dalam fragment yang lai. Sejak Andorid 4.2 kita memiliki kemampuan tersebut. Fragment yang ditempelkan ke dalam fragment lain disebut dengan child fragment. Situasi seperti ini terjadi saat kita ingin membuat fragment menampilkan tabs saat menggunakan teknik navigasi lain seperti ViewPager atau Navigation Drawer.

Kekurangan child fragment adalah mereka harus ditambahkan secara dinamis tidak bisa menggunakan tag <fragment>. Untuk menambahkan fragment ke dalam fragment lain, kita memerlukan <FragmeLayout> atau sebuah ViewPager (yang nantinya akan membaca fragment secara dinamis, dimasa mendatang kita akan membahasnya) ke res/layout/fragment_parent.xml (ingat bahwa file ini hanya contoh, sesuaikan dengan layout yang dimiliki oleh fragment dimana kita ingin menambah fragment lain di dalamnya):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" android:layout_height="fill_parent"
    android:orientation="vertical" >
<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="I am the parent fragment" />
<FrameLayout
        android:id="@+id/child_fragment_container"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

Lihat di FrameLayout di atas memiliki id @+id/child_fragment_container dimana child fragment akan kita tempelkan. Kita dapat menempelkan fragment ke FrameLayout ini melalui kelas Java si Fragment-nya:

// Kelas Fragment utama tempat kita ingin menempelkan fragment lain
public class ParentFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
       return inflater.inflate(R.layout.fragment_parent, container, false);
   }
}

// Kelas Fragment yang ingin ditampilkan ke fragment di atas
public class ChildFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
       // Need to define the child fragment layout
       return inflater.inflate(R.layout.fragment_child, container, false);
   }
}

Di dalam Fragment Utama, kita akan menambahkan ChildFragment menggunakan method getChildFragmentManager:

// Kelas Fragment utama tempat kita ingin menempelkan fragment lain
public class ParentFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_parent, container, false);
    }

   // Dipanggil setelah onCreateView() sukses.
   // onViewCreated() hanya dipanggil jika view dari onCreateView() tidak null
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        insertNestedFragment();
    }
  
   // Tambah child fragment secara dinamis
   private void insertNestedFragment() {
       Fragment childFragment = new ChildFragment();
       FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
       transaction.replace(R.id.child_fragment_container, childFragment).commit();
   }
}

Catat bahwa kita harus selalu menggunakan getChildFragmentManager saat berinteraksi dengan nested fragment dan tidak menggunakan getSupportFragmentManager. Baca stackoverflow post ini untuk penjelasan perbedaan antara keduanya.

Di dalam child fragment, kita dapat menggunakan getParentFragment() untuk mendapat reference ke parent fragment, seperti getActivity() jika di fragment biasa yang memberikan akses ke parent Activity.

Menangani Configuration Changes

Saat bekerja dengan fragment, kita juga harus menangani configuration changes misalnya saat layar diputar atau saat activity dihapus. Artikel selanjutnya kita akan membahas hal ini. Stay tuned dan ingatkan kalau terlalu lama.

Diterjemahkan dari Creating and Using Fragments

Dilihat 603 kali

Is this helpful?

Share This Post