Parçaları yeniden kullanmak için, bunları kendi düzen ve davranışlarını tanımlayan, tamamen bağımsız bileşenler olarak oluşturun. Yeniden kullanılabilir bu parçaları tanımladıktan sonra, bunları bir etkinlikle ilişkilendirebilir ve genel birleşik kullanıcı arayüzünü elde etmek için bunları uygulama mantığına bağlayabilirsiniz.
Kullanıcı etkinliklerine doğru şekilde tepki vermek ve durum bilgilerini paylaşmak için genellikle bir etkinlik ile onun parçaları ya da iki veya daha fazla parça arasında iletişim kanalları olması gerekir. Parçaların bağımsız kalması için doğrudan diğer parçalarla veya ana makine etkinlikleriyle iletişim kuran parçalar kullanmayın.
Fragment
kitaplığı iki iletişim seçeneği sunar: paylaşılan ViewModel
ve Fragment Result API. Önerilen seçenek, kullanım alanına bağlıdır. Kalıcı verileri özel API'lerle paylaşmak için ViewModel
kullanın. Bundle
içine yerleştirilebilen verilerle tek seferlik bir sonuç almak için FragmentResult API'yi kullanın.
Aşağıdaki bölümlerde, parçalarınız ve etkinlikleriniz arasında iletişim kurmak için ViewModel
ve FragmentResult API'yi nasıl kullanacağınız gösterilmektedir.
ViewModel kullanarak verileri paylaşma
ViewModel
, birden fazla parça arasında veya parçalar ile bunların ana makine etkinlikleri arasında veri paylaşmanız gerektiğinde ideal bir seçenektir.
ViewModel
nesneleri, kullanıcı arayüzü verilerini depolar ve yönetir. ViewModel
hakkında daha fazla bilgi için ViewModel'e genel bakış bölümüne bakın.
Düzenleyen etkinliğiyle veri paylaşma
Bazı durumlarda, parçalar ve bunların ana makine etkinlikleri arasında veri paylaşmanız gerekebilir. Örneğin, global kullanıcı arayüzü bileşenini parça içindeki etkileşime dayalı olarak değiştirmek isteyebilirsiniz.
Şunları göz önünde bulundurun: ItemViewModel
:
Kotlin
class ItemViewModel : ViewModel() { private val mutableSelectedItem = MutableLiveData<Item>() val selectedItem: LiveData<Item> get() = mutableSelectedItem fun selectItem(item: Item) { mutableSelectedItem.value = item } }
Java
public class ItemViewModel extends ViewModel { private final MutableLiveData<Item> selectedItem = new MutableLiveData<Item>(); public void selectItem(Item item) { selectedItem.setValue(item); } public LiveData<Item> getSelectedItem() { return selectedItem; } }
Bu örnekte, depolanan veriler bir MutableLiveData
sınıfı içine alınmıştır.
LiveData
, yaşam döngüsüne duyarlı bir gözlemlenebilir veri sahibi sınıfıdır. MutableLiveData
, değerinin değiştirilmesine izin verir. LiveData
hakkında daha fazla bilgi için LiveData'ya genel bakış sayfasını inceleyin.
Hem parçanız hem de ana makine etkinliği, etkinliği ViewModelProvider
oluşturucuya ileterek etkinlik kapsamına sahip bir ViewModel
öğesinin paylaşılan örneğini alabilir. ViewModelProvider
, ViewModel
örneğini veya varsa geri almayı yönetir. Her iki bileşen de bu verileri
gözlemleyip değiştirebilir.
Kotlin
class MainActivity : AppCompatActivity() { // Using the viewModels() Kotlin property delegate from the activity-ktx // artifact to retrieve the ViewModel in the activity scope. private val viewModel: ItemViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) viewModel.selectedItem.observe(this, Observer { item -> // Perform an action with the latest item data. }) } } class ListFragment : Fragment() { // Using the activityViewModels() Kotlin property delegate from the // fragment-ktx artifact to retrieve the ViewModel in the activity scope. private val viewModel: ItemViewModel by activityViewModels() // Called when the item is clicked. fun onItemClicked(item: Item) { // Set a new item. viewModel.selectItem(item) } }
Java
public class MainActivity extends AppCompatActivity { private ItemViewModel viewModel; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this).get(ItemViewModel.class); viewModel.getSelectedItem().observe(this, item -> { // Perform an action with the latest item data. }); } } public class ListFragment extends Fragment { private ItemViewModel viewModel; @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); viewModel = new ViewModelProvider(requireActivity()).get(ItemViewModel.class); ... items.setOnClickListener(item -> { // Set a new item. viewModel.select(item); }); } }
Parçalar arasında veri paylaşma
Aynı etkinlikteki iki veya daha fazla parçanın genellikle birbiriyle iletişim kurması gerekir. Örneğin, bir liste görüntüleyen bir parça ve kullanıcının listeye çeşitli filtreler uygulamasına olanak tanıyan başka bir parça düşünün. Parçalar doğrudan bir şekilde iletişim kurmadan bu örneği uygulamak önemsiz olmayacak, ancak daha sonra artık bağımsız olmaz. Buna ek olarak, her iki parça da diğer parçanın henüz oluşturulmadığı veya görünür olmadığı senaryoyu işlemelidir.
Bu parçalar, bu iletişimi yönetmek için etkinlik kapsamlarını kullanarak bir ViewModel
öğesini paylaşabilir. ViewModel
bu şekilde paylaşıldığında parçaların birbirlerini bilmesi gerekmez ve etkinliğin iletişimi kolaylaştırmak için herhangi bir şey yapmasına gerek yoktur.
Aşağıdaki örnekte iki parçanın iletişim kurmak için paylaşılan bir ViewModel
'yi nasıl kullanabileceği gösterilmektedir:
Kotlin
class ListViewModel : ViewModel() { val filters = MutableLiveData<Set<Filter>>() private val originalList: LiveData<List<Item>>() = ... val filteredList: LiveData<List<Item>> = ... fun addFilter(filter: Filter) { ... } fun removeFilter(filter: Filter) { ... } } class ListFragment : Fragment() { // Using the activityViewModels() Kotlin property delegate from the // fragment-ktx artifact to retrieve the ViewModel in the activity scope. private val viewModel: ListViewModel by activityViewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { viewModel.filteredList.observe(viewLifecycleOwner, Observer { list -> // Update the list UI. } } } class FilterFragment : Fragment() { private val viewModel: ListViewModel by activityViewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { viewModel.filters.observe(viewLifecycleOwner, Observer { set -> // Update the selected filters UI. } } fun onFilterSelected(filter: Filter) = viewModel.addFilter(filter) fun onFilterDeselected(filter: Filter) = viewModel.removeFilter(filter) }
Java
public class ListViewModel extends ViewModel { private final MutableLiveData<Set<Filter>> filters = new MutableLiveData<>(); private final LiveData<List<Item>> originalList = ...; private final LiveData<List<Item>> filteredList = ...; public LiveData<List<Item>> getFilteredList() { return filteredList; } public LiveData<Set<Filter>> getFilters() { return filters; } public void addFilter(Filter filter) { ... } public void removeFilter(Filter filter) { ... } } public class ListFragment extends Fragment { private ListViewModel viewModel; @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); viewModel = new ViewModelProvider(requireActivity()).get(ListViewModel.class); viewModel.getFilteredList().observe(getViewLifecycleOwner(), list -> { // Update the list UI. }); } } public class FilterFragment extends Fragment { private ListViewModel viewModel; @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { viewModel = new ViewModelProvider(requireActivity()).get(ListViewModel.class); viewModel.getFilters().observe(getViewLifecycleOwner(), set -> { // Update the selected filters UI. }); } public void onFilterSelected(Filter filter) { viewModel.addFilter(filter); } public void onFilterDeselected(Filter filter) { viewModel.removeFilter(filter); } }
Her iki parça da ViewModelProvider
için kapsam olarak ana makine etkinliğini kullanır. Parçalar aynı kapsamı kullandığından aynı ViewModel
örneğini alırlar. Bu da iki parçanın birbiriyle iletişim kurmasını sağlar.
Üst ve alt parça arasında veri paylaşma
Alt parçalarla çalışırken üst parçanızın ve alt parçalarının verileri birbirleriyle paylaşması gerekebilir. Bu parçalar arasında veri paylaşmak için üst parçayı aşağıdaki örnekte gösterildiği gibi ViewModel
kapsamı olarak kullanın:
Kotlin
class ListFragment: Fragment() { // Using the viewModels() Kotlin property delegate from the fragment-ktx // artifact to retrieve the ViewModel. private val viewModel: ListViewModel by viewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { viewModel.filteredList.observe(viewLifecycleOwner, Observer { list -> // Update the list UI. } } } class ChildFragment: Fragment() { // Using the viewModels() Kotlin property delegate from the fragment-ktx // artifact to retrieve the ViewModel using the parent fragment's scope private val viewModel: ListViewModel by viewModels({requireParentFragment()}) ... }
Java
public class ListFragment extends Fragment { private ListViewModel viewModel; @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { viewModel = new ViewModelProvider(this).get(ListViewModel.class); viewModel.getFilteredList().observe(getViewLifecycleOwner(), list -> { // Update the list UI. } } } public class ChildFragment extends Fragment { private ListViewModel viewModel; @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { viewModel = new ViewModelProvider(requireParentFragment()).get(ListViewModel.class); ... } }
ViewModel'i Gezinme Grafiğine Alma
Gezinme kitaplığı kullanıyorsanız bir hedefin NavBackStackEntry
yaşam döngüsüne ViewModel
de dahil edebilirsiniz. Örneğin, ViewModel
, ListFragment
için NavBackStackEntry
olarak ayarlanabilir:
Kotlin
class ListFragment: Fragment() { // Using the navGraphViewModels() Kotlin property delegate from the fragment-ktx // artifact to retrieve the ViewModel using the NavBackStackEntry scope. // R.id.list_fragment == the destination id of the ListFragment destination private val viewModel: ListViewModel by navGraphViewModels(R.id.list_fragment) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { viewModel.filteredList.observe(viewLifecycleOwner, Observer { item -> // Update the list UI. } } }
Java
public class ListFragment extends Fragment { private ListViewModel viewModel; @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { NavController navController = NavHostFragment.findNavController(this); NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.list_fragment) viewModel = new ViewModelProvider(backStackEntry).get(ListViewModel.class); viewModel.getFilteredList().observe(getViewLifecycleOwner(), list -> { // Update the list UI. } } }
Bir ViewModel
için NavBackStackEntry
kapsamını belirleme hakkında daha fazla bilgi edinmek istiyorsanız Gezinme bileşeniyle programatik olarak etkileşime geçme bölümüne bakın.
Fragment Result API'yi kullanarak sonuç alma
Bazı durumlarda, iki parça veya bir parça ile ana makine etkinliği arasında tek seferlik bir değer geçirmek isteyebilirsiniz. Örneğin, QR kodlarını okuyan ve verileri tekrar önceki bir parçaya ileten bir parçanız olabilir.
Fragment 1.3.0 ve sonraki sürümlerde her FragmentManager
FragmentResultOwner
kodunu uygular.
Bu, FragmentManager
öğesinin parça sonuçları için merkezi bir depolama alanı görevi görebileceği anlamına gelir. Bu değişiklik, bileşenlerin birbirine doğrudan referansları olmasını gerektirmeden, parça sonuçlarını ayarlayıp bu sonuçları dinleyerek birbirleriyle iletişim kurmasına olanak tanır.
Sonuçları parçalar arasında geçirme
Verileri B parçasından A parçasına geri aktarmak için önce sonucu alan parça olan A parçasında bir sonuç işleyici ayarlayın. Aşağıdaki örnekte gösterildiği gibi A parçasının FragmentManager
öğesinde setFragmentResultListener()
çağrısı yapın:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Use the Kotlin extension in the fragment-ktx artifact. setFragmentResultListener("requestKey") { requestKey, 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. } }
Java
@Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); getParentFragmentManager().setFragmentResultListener("requestKey", this, new FragmentResultListener() { @Override public void onFragmentResult(@NonNull String requestKey, @NonNull Bundle bundle) { // We use a String here, but any type that can be put in a Bundle is supported. String result = bundle.getString("bundleKey"); // Do something with the result. } }); }
B parçasında, sonucu üreten parça, aynı requestKey
öğesini kullanarak sonucu aynı FragmentManager
ile ayarlar. Bunu setFragmentResult()
API'sini kullanarak yapabilirsiniz:
Kotlin
button.setOnClickListener { val result = "result" // Use the Kotlin extension in the fragment-ktx artifact. setFragmentResult("requestKey", bundleOf("bundleKey" to result)) }
Java
button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Bundle result = new Bundle(); result.putString("bundleKey", "result"); getParentFragmentManager().setFragmentResult("requestKey", result); } });
Daha sonra A parçası, sonucu alır ve parça STARTED
olduğunda işleyici geri çağırma işlemini yürütür.
Belirli bir anahtar için yalnızca tek bir işleyiciniz ve sonucunuz olabilir. Aynı anahtar için setFragmentResult()
öğesini birden fazla kez çağırırsanız ve işleyici STARTED
değilse sistem bekleyen sonuçları güncellenmiş sonucunuzla değiştirir.
Bir sonucu almak için karşılık gelen bir işleyici olmadan ayarlarsanız sonuç, aynı anahtarla bir işleyici ayarlanana kadar FragmentManager
içinde depolanır. İşleyici bir sonuç alıp onFragmentResult()
geri çağırmasını tetiklediğinde sonuç temizlenir. Bu davranışın iki ana sonucu vardır:
- Arka yığındaki parçalar, açılıp
STARTED
olana kadar sonuç almaz. - Sonuç ayarlanırken bir sonuç için dinleme parçası
STARTED
olursa dinleyicinin geri çağırması hemen etkinleşir.
Test parçası sonuçları
setFragmentResult()
ve setFragmentResultListener()
çağrılarını test etmek için FragmentScenario
aracını kullanın.
launchFragmentInContainer
veya launchFragment
kullanarak test edilen parça için bir senaryo oluşturun, ardından test edilmeyen yöntemi manuel olarak çağırın.
setFragmentResultListener()
öğesini test etmek için setFragmentResultListener()
çağrısını yapan parçayla bir senaryo oluşturun. Ardından, doğrudan setFragmentResult()
numaralı telefonu arayın ve sonucu doğrulayın:
@Test
fun testFragmentResultListener() {
val scenario = launchFragmentInContainer<ResultListenerFragment>()
scenario.onFragment { fragment ->
val expectedResult = "result"
fragment.parentFragmentManager.setFragmentResult("requestKey", bundleOf("bundleKey" to expectedResult))
assertThat(fragment.result).isEqualTo(expectedResult)
}
}
class ResultListenerFragment : Fragment() {
var result : String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Use the Kotlin extension in the fragment-ktx artifact.
setFragmentResultListener("requestKey") { requestKey, bundle ->
result = bundle.getString("bundleKey")
}
}
}
setFragmentResult()
öğesini test etmek için setFragmentResult()
çağrısını yapan parçayla bir senaryo oluşturun. Daha sonra, doğrudan setFragmentResultListener()
telefonunu arayın ve sonucu doğrulayın:
@Test
fun testFragmentResult() {
val scenario = launchFragmentInContainer<ResultFragment>()
lateinit var actualResult: String?
scenario.onFragment { fragment ->
fragment.parentFragmentManager
.setFragmentResultListener("requestKey") { requestKey, bundle ->
actualResult = bundle.getString("bundleKey")
}
}
onView(withId(R.id.result_button)).perform(click())
assertThat(actualResult).isEqualTo("result")
}
class ResultFragment : Fragment(R.layout.fragment_result) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
view.findViewById(R.id.result_button).setOnClickListener {
val result = "result"
// Use the Kotlin extension in the fragment-ktx artifact.
setFragmentResult("requestKey", bundleOf("bundleKey" to result))
}
}
}
Sonuçları üst ve alt parçalar arasında geçirme
Bir alt parçadaki sonucu üst parçaya aktarmak için setFragmentResultListener()
yöntemini çağırırken getParentFragmentManager()
yerine üst parçadan getChildFragmentManager()
kullanın.
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Set the listener on the child fragmentManager. childFragmentManager.setFragmentResultListener("requestKey") { key, bundle -> val result = bundle.getString("bundleKey") // Do something with the result. } }
Java
@Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Set the listener on the child fragmentManager. getChildFragmentManager() .setFragmentResultListener("requestKey", this, new FragmentResultListener() { @Override public void onFragmentResult(@NonNull String requestKey, @NonNull Bundle bundle) { String result = bundle.getString("bundleKey"); // Do something with the result. } }); }
Alt parça, sonucu FragmentManager
öğesine ayarlar. Üst öğe, parça STARTED
olduğunda sonucu alır:
Kotlin
button.setOnClickListener { val result = "result" // Use the Kotlin extension in the fragment-ktx artifact. setFragmentResult("requestKey", bundleOf("bundleKey" to result)) }
Java
button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Bundle result = new Bundle(); result.putString("bundleKey", "result"); // The child fragment needs to still set the result on its parent fragment manager. getParentFragmentManager().setFragmentResult("requestKey", result); } });
Ana makine etkinliğindeki sonuçları alma
Ana makine etkinliğinde bir parça sonucu almak için parça yöneticisinde getSupportFragmentManager()
kodunu kullanarak bir sonuç işleyici ayarlayın.
Kotlin
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) supportFragmentManager .setFragmentResultListener("requestKey", this) { requestKey, 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. } } }
Java
class MainActivity extends AppCompatActivity { @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); getSupportFragmentManager().setFragmentResultListener("requestKey", this, new FragmentResultListener() { @Override public void onFragmentResult(@NonNull String requestKey, @NonNull Bundle bundle) { // We use a String here, but any type that can be put in a Bundle is supported. String result = bundle.getString("bundleKey"); // Do something with the result. } }); } }