Saat ini saya memiliki fragmen dalam overlay. Ini untuk masuk ke layanan. Di aplikasi ponsel, setiap langkah yang ingin saya tampilkan di hamparan adalah layar dan aktivitasnya sendiri. Ada 3 bagian proses masuk dan masing-masing memiliki aktivitasnya sendiri yang dipanggil dengan startActivityForResult ().
Sekarang saya ingin melakukan hal yang sama menggunakan fragmen dan overlay. Overlay akan menampilkan fragmen yang sesuai dengan setiap aktivitas. Masalahnya adalah fragmen ini dihosting dalam aktivitas di API Honeycomb. Saya bisa mendapatkan fragmen pertama berfungsi, tetapi kemudian saya perlu startActivityForResult (), yang tidak mungkin dilakukan. Apakah ada sesuatu di sepanjang baris startFragmentForResult () di mana saya bisa memulai sebuah fragmen baru dan setelah selesai apakah itu mengembalikan hasil ke fragmen sebelumnya?
sumber
onActivityResult
jika diinginkan.Jika Anda mau, ada beberapa metode komunikasi antar Fragmen,
setTargetFragment(Fragment fragment, int requestCode) getTargetFragment() getTargetRequestCode()
Anda dapat menelepon balik menggunakan ini.
Fragment invoker = getTargetFragment(); if(invoker != null) { invoker.callPublicMethod(); }
sumber
setTargetFragment()
.setTargetFragment
saat ini tidak digunakan lagi. LihatsetResultListener
di stackoverflow.com/a/61881149/2914140 di sini.Kita cukup berbagi ViewModel yang sama antar fragmen
SharedViewModel
import android.arch.lifecycle.MutableLiveData import android.arch.lifecycle.ViewModel class SharedViewModel : ViewModel() { val stringData: MutableLiveData<String> by lazy { MutableLiveData<String>() } }
FirstFragment
import android.arch.lifecycle.Observer import android.os.Bundle import android.arch.lifecycle.ViewModelProviders import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup class FirstFragment : Fragment() { private lateinit var sharedViewModel: SharedViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) activity?.run { sharedViewModel = ViewModelProviders.of(activity).get(SharedViewModel::class.java) } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_first, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedViewModel.stringData.observe(this, Observer { dateString -> // get the changed String }) } }
SecondFragment
import android.arch.lifecycle.ViewModelProviders import android.os.Bundle import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGrou class SecondFragment : Fragment() { private lateinit var sharedViewModel: SharedViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) activity?.run { sharedViewModel = ViewModelProviders.of(activity).get(SharedViewModel::class.java) } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_first, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) changeString() } private fun changeString() { sharedViewModel.stringData.value = "Test" } }
sumber
Baru-baru ini, Google baru saja menambahkan kemampuan baru
FragmentManager
yang membuatnyaFragmentManager
dapat bertindak sebagai penyimpanan pusat untuk hasil fragmen. Kami dapat mengirimkan data bolak-balik antar Fragmen dengan mudah.Fragmen awal.
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Use the Kotlin extension in the fragment-ktx artifact setResultListener("requestKey") { key, bundle -> // We use a String here, but any type that can be put in a Bundle is supported val result = bundle.getString("bundleKey") // Do something with the result... } }
Fragmen yang kami inginkan hasilnya kembali.
button.setOnClickListener { val result = "result" // Use the Kotlin extension in the fragment-ktx artifact setResult("requestKey", bundleOf("bundleKey" to result)) }
Cuplikan tersebut diambil dari dokumen resmi Google. https://developer.android.com/training/basics/fragments/pass-data-between#kotlin
Pada data jawaban ini tertulis, fitur ini masih dalam
alpha
status. Anda dapat mencobanya menggunakan ketergantungan ini.androidx.fragment:fragment:1.3.0-alpha05
sumber
2 sen saya.
Saya mengganti beberapa fragmen dengan menukar fragmen lama dengan yang baru menggunakan hide and show / add (existing / new). Jadi jawaban ini untuk developer yang menggunakan fragmen seperti yang saya lakukan.
Kemudian saya menggunakan
onHiddenChanged
metode ini untuk mengetahui bahwa fragmen lama dialihkan ke belakang dari yang baru. Lihat kode di bawah ini.Sebelum meninggalkan fragmen baru, saya menetapkan hasil dalam parameter global untuk ditanyai oleh fragmen lama. Ini adalah solusi yang sangat naif.
@Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); if (hidden) return; Result result = Result.getAndReset(); if (result == Result.Refresh) { refresh(); } } public enum Result { Refresh; private static Result RESULT; public static void set(Result result) { if (RESULT == Refresh) { // Refresh already requested - no point in setting anything else; return; } RESULT = result; } public static Result getAndReset() { Result result = RESULT; RESULT = null; return result; } }
sumber
getAndReset()
metodenya?onResume()
dipanggil pada fragmen pertama saat yang kedua ditutup?Dalam fragmen Anda, Anda bisa memanggil getActivity (). Ini akan memberi Anda akses ke aktivitas yang membuat fragmen. Dari sana Anda dapat memanggil metode kustomisasi Anda untuk menyetel nilai atau meneruskan nilai.
sumber
Ada pustaka Android - FlowR yang memungkinkan Anda memulai fragmen untuk mendapatkan hasil.
Memulai fragmen untuk hasil.
Flowr.open(RequestFragment.class) .displayFragmentForResults(getFragmentId(), REQUEST_CODE);
Penanganan menghasilkan fragmen pemanggil.
@Override protected void onFragmentResults(int requestCode, int resultCode, Bundle data) { super.onFragmentResults(requestCode, resultCode, data); if (requestCode == REQUEST_CODE) { if (resultCode == Activity.RESULT_OK) { demoTextView.setText("Result OK"); } else { demoTextView.setText("Result CANCELED"); } } }
Menetapkan hasil di Fragmen.
Flowr.closeWithResults(getResultsResponse(resultCode, resultData));
sumber
Solusi yang menggunakan antarmuka (dan Kotlin). Ide intinya adalah mendefinisikan antarmuka callback, mengimplementasikannya dalam aktivitas Anda, lalu memanggilnya dari fragmen Anda.
Pertama, buat antarmuka
ActionHandler
:interface ActionHandler { fun handleAction(actionCode: String, result: Int) }
Selanjutnya, panggil ini dari anak Anda (dalam hal ini, fragmen Anda):
companion object { const val FRAGMENT_A_CLOSED = "com.example.fragment_a_closed" } fun closeFragment() { try { (activity as ActionHandler).handleAction(FRAGMENT_A_CLOSED, 1234) } catch (e: ClassCastException) { Timber.e("Calling activity can't get callback!") } dismiss() }
Terakhir, terapkan ini pada orang tua Anda untuk menerima callback (dalam hal ini, Aktivitas Anda):
class MainActivity: ActionHandler { override fun handleAction(actionCode: String, result: Int) { when { actionCode == FragmentA.FRAGMENT_A_CLOSED -> { doSomething(result) } actionCode == FragmentB.FRAGMENT_B_CLOSED -> { doSomethingElse(result) } actionCode == FragmentC.FRAGMENT_C_CLOSED -> { doAnotherThing(result) } } }
sumber
Cara termudah untuk meneruskan data kembali adalah dengan setArgument (). Misalnya, Anda memiliki fragment1 yang memanggil fragment2 yang memanggil fragment3, fragment1 -> framgnet2 -> fargment3
Dalam fragment1
public void navigateToFragment2() { if (fragmentManager == null) return; Fragment2 fragment = Fragment2.newInstance(); String tag = "Fragment 2 here"; fragmentManager.beginTransaction() .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) .add(R.id.flContent, fragment, tag) .addToBackStack(null) .commitAllowingStateLoss(); }
Dalam fragment2 kami memanggil fragment3 seperti biasa
private void navigateToFragment3() { if (fragmentManager == null) return; Fragment3 fragment = new Fragment3(); fragmentManager.beginTransaction() .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) .replace(R.id.flContent, fragment, tag) .addToBackStack(null) .commit(); }
Ketika kami menyelesaikan tugas kami di fragment3 sekarang kami memanggil seperti ini:
FragmentManager fragmentManager = getActivity().getSupportFragmentManager(); if (fragmentManager == null) return; fragmentManager.popBackStack(); Bundle bundle = new Bundle(); bundle.putString("bundle_filter", "data"); fragmentManager.findFragmentByTag("Fragment 2 here").setArguments(bundle);
Sekarang di fragment2 kita dapat dengan mudah memanggil argumen
@Override public void onResume() { super.onResume(); Bundle rgs = getArguments(); if (args != null) String data = rgs.getString("bundle_filter"); }
sumber
Hal lain yang dapat Anda lakukan bergantung pada arsitektur Anda adalah menggunakan ViewModel bersama di antara fragmen. Jadi dalam kasus saya FragmentA adalah formulir, dan FragmentB adalah tampilan pemilihan item di mana pengguna dapat mencari dan memilih item, menyimpannya di ViewModel. Lalu ketika saya kembali ke FragmentA, informasinya sudah disimpan!
sumber