Bagaimana saya bisa mempertahankan status fragmen ketika ditambahkan ke tumpukan belakang?

160

Saya telah menulis aktivitas boneka yang beralih di antara dua fragmen. Ketika Anda pergi dari FragmentA ke FragmentB, FragmentA ditambahkan ke tumpukan belakang. Namun, ketika saya kembali ke FragmentA (dengan menekan kembali), FragmentA yang sama sekali baru dibuat dan keadaan tempatnya hilang. Saya merasa bahwa saya mencari hal yang sama dengan pertanyaan ini , tetapi saya telah memasukkan contoh kode lengkap untuk membantu membasmi masalah:

public class FooActivity extends Activity {
  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    final FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(android.R.id.content, new FragmentA());
    transaction.commit();
  }

  public void nextFragment() {
    final FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(android.R.id.content, new FragmentB());
    transaction.addToBackStack(null);
    transaction.commit();
  }

  public static class FragmentA extends Fragment {
    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
      final View main = inflater.inflate(R.layout.main, container, false);
      main.findViewById(R.id.next_fragment_button).setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
          ((FooActivity) getActivity()).nextFragment();
        }
      });
      return main;
    }

    @Override public void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
      // Save some state!
    }
  }

  public static class FragmentB extends Fragment {
    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
      return inflater.inflate(R.layout.b, container, false);
    }
  }
}

Dengan beberapa pesan log ditambahkan:

07-05 14:28:59.722 D/OMG     ( 1260): FooActivity.onCreate
07-05 14:28:59.742 D/OMG     ( 1260): FragmentA.onCreateView
07-05 14:28:59.742 D/OMG     ( 1260): FooActivity.onResume
<Tap Button on FragmentA>
07-05 14:29:12.842 D/OMG     ( 1260): FooActivity.nextFragment
07-05 14:29:12.852 D/OMG     ( 1260): FragmentB.onCreateView
<Tap 'Back'>
07-05 14:29:16.792 D/OMG     ( 1260): FragmentA.onCreateView

Itu tidak pernah memanggil FragmentA.onSaveInstanceState dan itu menciptakan FragmentA baru ketika Anda menekan kembali. Namun, jika saya menggunakan FragmentA dan saya mengunci layar, FragmentA.onSaveInstanceState dipanggil. Sangat aneh ... apakah saya salah mengharapkan fragmen yang ditambahkan ke tumpukan belakang tidak perlu dibuat ulang? Inilah yang dikatakan dokumen :

Sedangkan, jika Anda memanggil addToBackStack () saat menghapus sebuah fragmen, maka fragmen tersebut dihentikan dan akan dilanjutkan jika pengguna menavigasi kembali.

Eric
sumber
3
@ Jan-Henk Bagaimana dengan hal-hal yang harus diambil? Misalnya, posisi gulir dari a ListView. Sepertinya terlalu banyak omong kosong untuk melampirkan pendengar gulir dan memperbarui variabel instan.
Jake Wharton
2
@JakeWharton Saya setuju seharusnya lebih mudah, tetapi sejauh yang saya tahu tidak ada jalan lain karena onCreateView dipanggil ketika sebuah fragmen dipulihkan dari backstack. Tapi saya bisa saja salah :)
Jan-Henk
1
onCreate tidak dipanggil. Jadi rupanya menggunakan kembali contoh yang sama tetapi memanggil onCreateView lagi? Kuno. Saya kira saya bisa men-cache hasil onCreateView dan mengembalikan tampilan yang ada jika onCreateView dipanggil lagi.
Eric
1
Persis apa yang saya cari berjam-jam. Bisakah Anda memposting bagaimana Anda mencapai ini menggunakan variabel instan?
Uma
1
Jadi saya baru-baru ini memulai implementasi saya sendiri di github.com/frostymarvelous/Folio dan menemukan masalah. Saya dapat membuat sekitar 5 Halaman / Fragmen kompleks sebelum saya mulai mendapatkan crash OOM. Itulah yang membawaku ke sini. Menyembunyikan dan Menampilkan tidak cukup. Tampilan memori terlalu berat.
frostymarvelous

Jawaban:

120

Jika Anda kembali ke fragmen dari tumpukan belakang, ia tidak membuat ulang fragmen tetapi menggunakan kembali contoh yang sama dan mulai dengan onCreateView()siklus hidup fragmen, lihat Siklus hidup fragmen .

Jadi jika Anda ingin menyimpan state Anda harus menggunakan variabel instan dan tidak bergantung onSaveInstanceState().

Jan-Henk
sumber
32
Versi dokumentasi saat ini bertentangan dengan klaim ini. Flowchart mengatakan apa yang Anda nyatakan, tetapi teks di area utama halaman mengatakan onCreateView () hanya disebut pertama kali Fragment ditampilkan: developer.android.com/guide/components/fragments.html Saya memperjuangkan ini masalah sekarang, dan saya tidak melihat metode apa pun yang dipanggil ketika mengembalikan sebuah fragmen dari backstack. (Android 4.2)
Colin M.
10
Mencoba mencatat perilakunya. OnCreateView () selalu dipanggil saat fragmen ditampilkan.
princepiero
4
@ColinM. Ada solusi untuk masalah ini?
badai salju
9
Ini tidak berhasil untuk saya. Variabel instan saya nol untuk kembali ke fragmen! Bagaimana saya bisa menyelamatkan negara?
Don Rummy
5
jadi jika kita tidak melanjutkan dengan save instance bagaimana seharusnya menyimpan status dan data fragmen?
Mahdi
80

Dibandingkan dengan Apple UINavigationControllerdan UIViewController, Google tidak melakukan dengan baik dalam arsitektur perangkat lunak Android. Dan dokumen Android tentang Fragmenttidak banyak membantu.

Saat Anda memasukkan FragmentB dari FragmentA, instance FragmentA yang ada tidak dihancurkan. Saat Anda menekan Kembali di FragmentB dan kembali ke FragmentA, kami tidak membuat instance FragmentA baru. Instance FragmentA yang ada onCreateView()akan dipanggil.

Kuncinya adalah kita tidak harus mengembang tampilan lagi di FragmentA onCreateView(), karena kita menggunakan instance FragmentA yang ada. Kita perlu menyimpan dan menggunakan kembali rootView.

Kode berikut berfungsi dengan baik. Itu tidak hanya menjaga keadaan fragmen, tetapi juga mengurangi beban RAM dan CPU (karena kami hanya mengembang tata letak jika perlu). Saya tidak percaya kode sampel dan dokumen Google tidak pernah menyebutkannya tetapi selalu mengembang tata letak .

Versi 1 (Jangan gunakan versi 1. Gunakan versi 2)

public class FragmentA extends Fragment {
    View _rootView;
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (_rootView == null) {
            // Inflate the layout for this fragment
            _rootView = inflater.inflate(R.layout.fragment_a, container, false);
            // Find and setup subviews
            _listView = (ListView)_rootView.findViewById(R.id.listView);
            ...
        } else {
            // Do not inflate the layout again.
            // The returned View of onCreateView will be added into the fragment.
            // However it is not allowed to be added twice even if the parent is same.
            // So we must remove _rootView from the existing parent view group
            // (it will be added back).
            ((ViewGroup)_rootView.getParent()).removeView(_rootView);
        }
        return _rootView;
    }
}

------ Pembaruan pada 3 Mei 2005: -------

Seperti komentar yang disebutkan, terkadang _rootView.getParent()null onCreateView, yang menyebabkan crash. Versi 2 menghapus _rootView di onDestroyView (), seperti yang disarankan dell116. Diuji pada Android 4.0.3, 4.4.4, 5.1.0.

Versi 2

public class FragmentA extends Fragment {
    View _rootView;
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (_rootView == null) {
            // Inflate the layout for this fragment
            _rootView = inflater.inflate(R.layout.fragment_a, container, false);
            // Find and setup subviews
            _listView = (ListView)_rootView.findViewById(R.id.listView);
            ...
        } else {
            // Do not inflate the layout again.
            // The returned View of onCreateView will be added into the fragment.
            // However it is not allowed to be added twice even if the parent is same.
            // So we must remove _rootView from the existing parent view group
            // in onDestroyView() (it will be added back).
        }
        return _rootView;
    }

    @Override
    public void onDestroyView() {
        if (_rootView.getParent() != null) {
            ((ViewGroup)_rootView.getParent()).removeView(_rootView);
        }
        super.onDestroyView();
    }
}

PERINGATAN!!!

Ini adalah HACK! Meskipun saya menggunakannya di aplikasi saya, Anda perlu menguji dan membaca komentar dengan cermat.

Vince Yuan
sumber
38
Memegang referensi ke rootview seluruh fragmen adalah ide yang buruk IMO. Jika Anda terus menambahkan beberapa fragmen ke backstack dan semuanya memegang rootview (yang memiliki jejak memori cukup besar), maka ada kemungkinan besar Anda berakhir dengan OutOfMemoryError karena semua fragmen memegang referensi rootview dan GC tidak dapat kumpulkan itu. Saya pikir pendekatan yang lebih baik adalah mengembang tampilan sepanjang waktu (dan biarkan sistem Android menangani pembuatan / penghancuran tampilan) dan cek onActivityCreated / onViewCreated untuk memeriksa apakah data Anda nol. Jika ya, maka muat, atur data ke tampilan lain.
traninho
15
Jangan lakukan ini! Ketika hierarki tampilan Fragmen dibuat, itu berisi referensi internal ke Aktivitas yang menyimpan fragmen pada saat itu. Ketika perubahan konfigurasi terjadi, Kegiatan ini sering dibuat kembali. Menggunakan kembali tata letak lama membuat Aktivitas zombie di dalam memori bersama dengan objek apa pun yang juga referensi. Membuang memori seperti ini menghambat kinerja dan menjadikan aplikasi Anda kandidat teratas untuk penghentian segera saat tidak ada di latar depan.
Krylez
4
@ AllDayAmazing Ini poin bagus. Sejujurnya, saya sangat bingung sekarang. Adakah yang bisa mencoba menjelaskan mengapa memegang referensi ke rootview fragmen tidak ok tapi memegang referensi hanya untuk anak-anak rootview (yang memiliki referensi untuk rootview) tidak apa-apa?
traninho
2
TINGGAL JAUH DARI INI kecuali Anda ingin menghabiskan 5 jam mencari tahu apa yang mengganggu kode Anda ..... maka hanya untuk menemukan bahwa ini adalah penyebabnya. Sekarang saya harus memperbaiki banyak hal karena saya menggunakan hack ini. Jauh lebih baik menggunakan fragmentTransaction.add jika Anda ingin tetap menjaga UI fragmen saat menampilkan yang lain (bahkan di atas). fragmentTransaction.replace () dimaksudkan untuk menghancurkan pandangan fragmen ..... jangan melawan sistem.
dell116
2
@VinceYuan - Saya menguji dengan pustaka v7-appcompat terbaru di Android 5.1 dan ini menyisakan 6 contoh fragmen yang seharusnya dihapus dalam FragmentManager aktivitas saya. Bahkan jika GC akan menanganinya dengan benar (yang saya tidak percaya akan melakukannya) ini menyebabkan ketegangan yang tidak perlu pada memori untuk aplikasi Anda serta perangkat pada umumnya. Cukup menggunakan .add () sepenuhnya menghilangkan kebutuhan untuk semua kode hacky ini. Melakukan ini sepenuhnya bertentangan dengan apa yang menggunakan FragmentTransaction.replace () seharusnya dilakukan di tempat pertama.
dell116
53

Saya kira ada cara alternatif untuk mencapai apa yang Anda cari. Saya tidak mengatakan ini solusi yang lengkap tetapi melayani tujuan dalam kasus saya.

Apa yang saya lakukan adalah bukannya mengganti fragmen yang saya tambahkan fragmen target. Jadi pada dasarnya Anda akan menggunakan add()metode sebagai gantinya replace().

Apa lagi yang saya lakukan. Saya menyembunyikan fragmen saya saat ini dan juga menambahkannya ke backstack.

Oleh karena itu tumpang tindih fragmen baru atas fragmen saat ini tanpa merusak pandangannya. (Periksa bahwa onDestroyView()metodenya tidak disebut. Ditambah menambahkannya untuk backstatememberi saya keuntungan dari melanjutkan fragmen.

Ini kodenya:

Fragment fragment=new DestinationFragment();
FragmentManager fragmentManager = getFragmentManager();
android.app.FragmentTransaction ft=fragmentManager.beginTransaction();
ft.add(R.id.content_frame, fragment);
ft.hide(SourceFragment.this);
ft.addToBackStack(SourceFragment.class.getName());
ft.commit();

Sistem AFAIK hanya memanggil onCreateView()jika tampilan dihancurkan atau tidak dibuat. Tapi di sini kita telah menyimpan tampilan dengan tidak melepasnya dari memori. Jadi itu tidak akan membuat tampilan baru.

Dan ketika Anda kembali dari Fragmen Tujuan, itu akan muncul terakhir FragmentTransaction fragmen atas menghapus yang akan membuat tampilan paling atas (SourceFragment) muncul di layar.

KOMENTAR: Seperti yang saya katakan itu bukan solusi lengkap karena tidak menghapus tampilan fragmen Sumber dan karenanya menempati lebih banyak memori daripada biasanya. Namun tetap, melayani tujuan. Kami juga menggunakan mekanisme yang sama sekali berbeda untuk menyembunyikan tampilan alih-alih menggantinya yang non tradisional.

Jadi itu bukan untuk bagaimana Anda mempertahankan negara, tetapi untuk bagaimana Anda mempertahankan pandangan.

kaushal trivedi
sumber
Dalam kasus saya, dengan menambahkan fragmen alih-alih mengganti penyebab masalah saat menggunakan polling atau jenis permintaan web lainnya digunakan dalam fragmen. Saya ingin menjeda polling ini di Fragment A ketika Fragment B ditambahkan. Ada ide tentang ini?
Uma
Bagaimana Anda menggunakan polling di FirstFragment? Anda harus melakukannya secara manual karena kedua fragmen itu tetap ada dalam memori. Jadi, Anda dapat menggunakan instans mereka untuk melakukan tindakan yang diperlukan. Itulah petunjuknya, buat suatu peristiwa dalam aktivitas utama yang melakukan sesuatu ketika Anda menambahkan fragmen kedua. Semoga ini bisa membantu.
kaushal trivedi
1
Terima kasih atas petunjuknya =). Saya sudah melakukan ini. Tetapi apakah ini satu-satunya cara untuk melakukannya? Dan cara yang tepat? Juga ketika saya menekan tombol home dan meluncurkan aplikasi lagi semua fragmen aktif kembali. Misalkan saya di sini di Fragmen B melalui cara ini. Activity A{Fragment A --> Fragment B}ketika saya meluncurkan aplikasi lagi setelah menekan tombol home kedua fragmen onResume()dipanggil dan karenanya mereka memulai polling mereka. Bagaimana saya bisa mengendalikan ini?
Uma
1
Sayangnya Anda tidak bisa, Sistem tidak bekerja dalam perilaku normal dengan cara ini, ia akan menganggap kedua fragmen tersebut sebagai anak langsung dari aktivitas. Walaupun berfungsi untuk mempertahankan status fragmen, hal-hal normal lainnya menjadi sangat sulit untuk dikelola. menemukan semua masalah ini, sekarang saran saya adalah untuk tidak pergi dengan cara ini. Maaf.
kaushal trivedi
1
Tentu saja, pada akhirnya saya akan mengatakan untuk tidak pergi dengan pendekatan ini sampai Anda menemukan solusi lain. Karena sulit untuk dikelola.
kaushal trivedi
7

Saya akan menyarankan solusi yang sangat sederhana.

Ambil variabel Lihat referensi dan atur tampilan di OnCreateView. Periksa apakah tampilan sudah ada dalam variabel ini, lalu kembali tampilan yang sama.

   private View fragmentView;

   public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);

        if (fragmentView != null) {
            return fragmentView;
        }
        View view = inflater.inflate(R.layout.yourfragment, container, false);
        fragmentView = view;
        return view;
    }
Mandeep Singh
sumber
1
Ada kemungkinan kebocoran memori jika kami tidak menghapus variabel 'fragmentView' di onDestroy ()
Arun PM
@ArunPM jadi bagaimana cara menghapus fragmentView di onDestroy ()? if (_rootView.getParent() != null) { ((ViewGroup)_rootView.getParent()).removeView(_rootView); }apakah pantas untuk mengosongkan memori?
Mehmet Gür
1
@ MehmetGür saya menggunakan solusi ini berkali-kali. Sampai sekarang saya tidak mendapatkan kesalahan kebocoran memori. Tetapi Anda dapat menggunakan solusi ArunPM dengan itu jika Anda mau. Saya pikir dia mengatakan untuk mengatur fragmentView menjadi nol di Metode OnDestroy ().
Mandeep Singh
1
Saya menggunakan LeakCanary untuk mendeteksi kebocoran memori dan masalah kebocoran ketika saya mengikuti metode ini. Tapi seperti @Mandeep napas disebutkan dalam komentar kita dapat mengatasi masalah ini dengan menetapkan nullke fragmentView variabel dalam onDestroy()metode.
Arun PM
1
Sesuai pengetahuan saya, ketika sebuah fragmen dihancurkan, tampilan yang terkait dengan fragmen tersebut dihapus onDestroyView(). Kliring ini tidak terjadi untuk variabel tampilan cadangan kami (di sini fragmentView ) dan itu akan menyebabkan kebocoran memori ketika fragmen kembali ditumpuk / dihancurkan. Anda dapat menemukan referensi yang sama di [Penyebab umum kebocoran memori] ( square.github.io/leakcanary/fundamentals/… ) di pengantar LeakCanery.
Arun PM
6

Saya menemukan masalah ini dalam Fragmen yang berisi peta, yang memiliki terlalu banyak detail pengaturan untuk disimpan / dimuat ulang. Solusi saya adalah pada dasarnya menjaga Fragmen ini tetap aktif sepanjang waktu (mirip dengan apa yang disebutkan @kaushal).

Katakanlah Anda memiliki Fragmen A saat ini dan ingin menampilkan Fragmen B. Ringkas konsekuensinya:

  • ganti () - hapus Fragmen A dan ganti dengan Fragmen B. Fragmen A akan dibuat kembali setelah dibawa ke depan lagi
  • add () - (buat dan) tambahkan Fragment B dan tumpang tindih Fragment A, yang masih aktif di latar belakang
  • remove () - dapat digunakan untuk menghapus Fragment B dan kembali ke A. Fragment B akan dibuat kembali saat dipanggil nanti

Oleh karena itu, jika Anda ingin menjaga kedua Fragmen "disimpan", alihkan saja menggunakan hide () / show ().

Kelebihan : metode mudah dan sederhana untuk membuat beberapa Fragmen tetap berjalan
Kontra : Anda menggunakan lebih banyak memori untuk membuat semuanya tetap berjalan. Dapat mengalami masalah, misalnya menampilkan banyak bitmap besar

Teo Inke
sumber
dapatkah Anda memberi tahu saya ketika kami menghapus fragmen b dan kembali ke A lalu metode mana yang disebut dalam Fragmen A? saya ingin mengambil tindakan ketika kami menghapus fragmen B.
Google
5

onSaveInstanceState() hanya dipanggil jika ada perubahan konfigurasi.

Sejak mengubah dari satu fragmen ke fragmen lain, tidak ada konfigurasi yang berubah jadi tidak ada panggilan onSaveInstanceState() sana. Status apa yang tidak disimpan? Bisakah Anda menentukan?

Jika Anda memasukkan beberapa teks dalam EditText, teks itu akan disimpan secara otomatis. Item UI apa pun tanpa ID apa pun adalah item yang status pandangannya tidak akan disimpan.

pengguna2779311
sumber
onSaveInstanceState()disebut juga ketika sistem menghancurkan Activity karena kekurangan sumber daya.
Marcel Bro
0

Di sini, karena onSaveInstanceStatedalam fragmen tidak memanggil ketika Anda menambahkan fragmen ke backstack. Siklus hidup fragmen di backstack ketika dipulihkan mulai onCreateViewdan berakhir onDestroyViewsementara onSaveInstanceStatedisebut antara onDestroyViewdan onDestroy. Solusi saya adalah membuat variabel instan dan init di onCreate. Kode sampel:

private boolean isDataLoading = true;
private ArrayList<String> listData;
public void onCreate(Bundle savedInstanceState){
     super.onCreate(savedInstanceState);
     isDataLoading = false;
     // init list at once when create fragment
     listData = new ArrayList();
}

Dan periksa di onActivityCreated:

public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    if(isDataLoading){
         fetchData();
    }else{
         //get saved instance variable listData()
    }
}

private void fetchData(){
     // do fetch data into listData
}
Ling Boo
sumber
0
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener()
    {
        @Override
        public void onBackStackChanged()
        {
            if (getSupportFragmentManager().getBackStackEntryCount() == 0)
            {
                //setToolbarTitle("Main Activity");
            }
            else
            {
                Log.e("fragment_replace11111", "replace");
            }
        }
    });


YourActivity.java
@Override
public void onBackPressed()
{
 Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.Fragment_content);
  if (fragment instanceof YourFragmentName)
    {
        fragmentReplace(new HomeFragment(),"Home Fragment");
        txt_toolbar_title.setText("Your Fragment");
    }
  else{
     super.onBackPressed();
   }
 }


public void fragmentReplace(Fragment fragment, String fragment_name)
{
    try
    {
        fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.Fragment_content, fragment, fragment_name);
        fragmentTransaction.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right);
        fragmentTransaction.addToBackStack(fragment_name);
        fragmentTransaction.commitAllowingStateLoss();
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}
Hardik Vasani
sumber
0

Masalah saya serupa tetapi saya mengatasi saya tanpa menjaga fragmen tetap hidup. Misalkan Anda memiliki aktivitas yang memiliki 2 fragmen - F1 dan F2. F1 dimulai pada awalnya dan katakanlah di berisi beberapa info pengguna dan kemudian pada kondisi tertentu F2 muncul pada meminta pengguna untuk mengisi atribut tambahan - nomor telepon mereka. Selanjutnya, Anda ingin nomor telepon itu muncul kembali ke F1 dan menyelesaikan pendaftaran tetapi Anda menyadari bahwa semua informasi pengguna sebelumnya hilang dan Anda tidak memiliki data sebelumnya. Fragmen dibuat kembali dari awal dan bahkan jika Anda menyimpan informasi ini dalam onSaveInstanceStatebundel kembali nol onActivityCreated.

Solusi: Simpan informasi yang diperlukan sebagai variabel instan dalam aktivitas panggilan. Kemudian masukkan variabel instance ke dalam fragmen Anda.

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    Bundle args = getArguments();

    // this will be null the first time F1 is created. 
    // it will be populated once you replace fragment and provide bundle data
    if (args != null) {
        if (args.get("your_info") != null) {
            // do what you want with restored information
        }
    }
}

Jadi berikut dengan contoh saya: sebelum saya menampilkan F2 saya menyimpan data pengguna dalam variabel instan menggunakan panggilan balik. Lalu saya mulai F2, pengguna mengisi nomor telepon dan menekan simpan. Saya menggunakan panggilan balik lain dalam aktivitas, mengumpulkan informasi ini dan mengganti fragmen F1 saya, kali ini memiliki data paket yang dapat saya gunakan.

@Override
public void onPhoneAdded(String phone) {
        //replace fragment
        F1 f1 = new F1 ();
        Bundle args = new Bundle();
        yourInfo.setPhone(phone);
        args.putSerializable("you_info", yourInfo);
        f1.setArguments(args);

        getFragmentManager().beginTransaction()
                .replace(R.id.fragmentContainer, f1).addToBackStack(null).commit();

    }
}

Informasi lebih lanjut tentang panggilan balik dapat ditemukan di sini: https://developer.android.com/training/basics/fragments/communicating.html

Dodi
sumber
0

pertama : cukup gunakan metode add alih-alih ganti metode kelas FragmentTransaction maka Anda harus menambahkan secondFragment ke stack dengan metode addToBackStack

kedua : pada klik belakang Anda harus memanggil popBackStackImmediate ()

Fragment sourceFragment = new SourceFragment ();
final Fragment secondFragment = new SecondFragment();
final FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.add(R.id.child_fragment_container, secondFragment );
ft.hide(sourceFragment );
ft.addToBackStack(NewsShow.class.getName());
ft.commit();
                                
((SecondFragment)secondFragment).backFragmentInstanceClick = new SecondFragment.backFragmentNewsResult()
{
        @Override
        public void backFragmentNewsResult()
        {                                    
            getChildFragmentManager().popBackStackImmediate();                                
        }
};
Milad Ahmadi
sumber
0

Ganti Fragmen menggunakan kode berikut:

Fragment fragment = new AddPaymentFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frame, fragment, "Tag_AddPayment")
                .addToBackStack("Tag_AddPayment")
                .commit();

Aktivitas diBackPressed () adalah:

  @Override
public void onBackPressed() {
    android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
    if (fm.getBackStackEntryCount() > 1) {

        fm.popBackStack();
    } else {


        finish();

    }
    Log.e("popping BACKSTRACK===> ",""+fm.getBackStackEntryCount());

}
Pratibha Sarode
sumber
0
Public void replaceFragment(Fragment mFragment, int id, String tag, boolean addToStack) {
        FragmentTransaction mTransaction = getSupportFragmentManager().beginTransaction();
        mTransaction.replace(id, mFragment);
        hideKeyboard();
        if (addToStack) {
            mTransaction.addToBackStack(tag);
        }
        mTransaction.commitAllowingStateLoss();
    }
replaceFragment(new Splash_Fragment(), R.id.container, null, false);
Hitesh Manwani
sumber
1
Terima kasih atas cuplikan kode ini, yang mungkin memberikan bantuan terbatas dan segera. Sebuah penjelasan yang tepat akan sangat meningkatkan nilai jangka panjang dengan menunjukkan mengapa ini adalah solusi yang baik untuk masalah ini, dan akan membuatnya lebih bermanfaat untuk pembaca masa depan dengan lainnya, pertanyaan-pertanyaan serupa. Harap edit jawaban Anda untuk menambahkan beberapa penjelasan, termasuk asumsi yang Anda buat.
Machavity
0

Solusi sempurna yang menemukan fragmen lama di tumpukan dan memuatnya jika ada di tumpukan.

/**
     * replace or add fragment to the container
     *
     * @param fragment pass android.support.v4.app.Fragment
     * @param bundle pass your extra bundle if any
     * @param popBackStack if true it will clear back stack
     * @param findInStack if true it will load old fragment if found
     */
    public void replaceFragment(Fragment fragment, @Nullable Bundle bundle, boolean popBackStack, boolean findInStack) {
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        String tag = fragment.getClass().getName();
        Fragment parentFragment;
        if (findInStack && fm.findFragmentByTag(tag) != null) {
            parentFragment = fm.findFragmentByTag(tag);
        } else {
            parentFragment = fragment;
        }
        // if user passes the @bundle in not null, then can be added to the fragment
        if (bundle != null)
            parentFragment.setArguments(bundle);
        else parentFragment.setArguments(null);
        // this is for the very first fragment not to be added into the back stack.
        if (popBackStack) {
            fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        } else {
            ft.addToBackStack(parentFragment.getClass().getName() + "");
        }
        ft.replace(R.id.contenedor_principal, parentFragment, tag);
        ft.commit();
        fm.executePendingTransactions();
    }

gunakan seperti

Fragment f = new YourFragment();
replaceFragment(f, null, boolean true, true); 
Khemraj
sumber