Parçaları yeniden kullanmak için bunları tamamen bağımsız bileşenler olarak derleyin birçok farklı reklam bulunur. Bu görevleri tanımladıktan sonra bunları bir etkinlikle ilişkilendirip bunları bir etkinlikte uygulama mantığıyla birleştirdiğinizi düşünün.
Kullanıcı etkinliklerine uygun şekilde tepki vermek ve durum bilgilerini paylaşmak için genellikle Bir etkinlik ile onun etkinliği arasında bir iletişim kanalı olması parça veya iki ya da daha fazla parça arasında geçiş yapar. Parçaların bağımsız olmaları için parçaların doğrudan diğer parçalarla iletişim kurmasını sağlamayın veya etkinliğiyle eşleştirilir.
Fragment
kitaplığı iki iletişim seçeneği sunar: paylaşılan
ViewModel
ve Parça
Result API'si. Önerilen seçenek, kullanım alanına bağlıdır. Paylaşmak için
özel API'lerle kalıcı veriler sağlamak için ViewModel
kullanın. Örneğin,
verileri içeren tek seferlik bir sonuç
Bundle
, Parçayı kullanın
Result API'si.
Aşağıdaki bölümlerde ViewModel
ve Parçanın nasıl kullanılacağı gösterilmektedir
Parçalarınız ve etkinlikleriniz arasında iletişim kurmak için Result API'si.
ViewModel kullanarak veri paylaşma
Aşağıdaki durumlarda ViewModel
ideal seçenektir:
ortak bir aktiviteye
dahil olmak için
parçalar ve ana makine etkinlikleri arasında geçiş yapar.
ViewModel
nesne depolanır ve
kullanıcı arayüzü verilerini yönetmenizi sağlar. ViewModel
hakkında daha fazla bilgi için bkz.
ViewModel'e genel bakış.
Verileri, düzenleyen kişiyle paylaşma
Bazı durumlarda, parçalar ve davet eder. Örneğin, genel bir kullanıcı arayüzünü açıp kapatmak isteyebilirsiniz. parça içindeki etkileşimi temel alır.
Aşağıdaki ItemViewModel
göz önünde bulundurulmalıdır:
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
MutableLiveData
sınıfı.
LiveData
, yaşam döngüsüne duyarlı bir
gözlemlenebilir veri sahibi sınıfını kullanır. MutableLiveData
, değerinin
değiştirildi. LiveData
hakkında daha fazla bilgi için bkz.
LiveData'ya genel bakış.
Hem parçanız hem de parçanızın ana makine etkinliği, paylaşılan bir örneği alabilir
etkinliğiViewModel
ViewModelProvider
kurucusu. ViewModelProvider
, ViewModel
örneklendirmeyi işler
dosya zaten varsa alın. Her iki bileşen de
bu verileri 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 bir iletişim kurmaktır. Mesela bir parçanın bir listede yer aldığını Kullanıcının listeye çeşitli filtreler uygulamasına olanak tanıyan başka bir filtre de oluşturabilirsiniz. Parçalar olmadan bu senaryoyu uygulamak önemsiz değil. ancak doğrudan iletişim kurmayıp bağımsız olması gerekir. Ayrıca, her iki parçanın da senaryoya uygun olması gerekir. olması gerekir.
Bu parçalar, etkinlik kapsamlarını kullanarak bir ViewModel
paylaşabilir
çok iyi bir fikir olabilir. ViewModel
bu şekilde paylaşıldığında,
parçaların birbirlerinden haberdar olmaları gerekmez ve etkinlik
ve iletişimi kolaylaştırmak için
bir şey yapması gerekmez.
Aşağıdaki örnekte, iki parçanın paylaşılan bir öğeyi nasıl kullanabileceği gösterilmektedir
İletişim için ViewModel
:
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 ana makine etkinliğini
ViewModelProvider
Parçalar aynı kapsamı kullandığından
iletişim kurmalarına olanak tanıyan aynı ViewModel
örneği
iletişim kurabiliyorsunuz.
Üst ve alt parça arasında veri paylaşma
Alt parçalarla çalışırken üst parçanız ve alt parçanız
parçaların birbirleriyle veri paylaşması gerekebilir. Şu hizmetler arasında veri paylaşmak için:
için, üst parçayı gösterildiği gibi ViewModel
kapsamı olarak kullanın
aşağıdaki örnekte:
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); ... } }
Bir ViewModel'in Kapsamını Gezinme Grafiği'ne ekleme
Navigasyon kitaplığını kullanıyorsanız şunları da bulabilirsiniz:
bir ViewModel
kapsamını bir hedefin yaşam döngüsüne
NavBackStackEntry
. Örneğin,
örnek olarak, ViewModel
metriği NavBackStackEntry
olarak ayarlanabilir.
ListFragment
için:
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
kapsamının NavBackStackEntry
olarak belirlenmesi hakkında daha fazla bilgi için bkz.
Gezinme bileşeniyle programlı bir şekilde etkileşim kurun.
Fragment Result API'sini kullanarak sonuç alma
Bazı durumlarda, iki parça arasında tek seferlik bir değer aktarmak isteyebilirsiniz veya parça ile ana makine etkinliği arasında. Örneğin, bir hafta içinde QR kodlarını okuyan ve verileri önceki bir parçaya geri ileten parça.
Parça sürüm 1.3.0 ve sonraki sürümlerde
her FragmentManager
implements
FragmentResultOwner
.
Bu, bir FragmentManager
öğesinin parça için merkezi bir depo olarak kullanabileceği anlamına gelir
sonuç. Bu değişiklik, bileşenlerin birbiriyle iletişim kurmasını sağlayan
gerek kalmadan parçalı sonuçları ayarlama ve bu sonuçları dinleme
bu bileşenlerin birbirine doğrudan referanslar içermesini sağlar.
Sonuçları parçalar arasında iletme
Verileri B parçasından A parçasına geri iletmek için önce bir sonuç işleyici ayarlayın
A parçasında, sonucu alan parça olur. Telefonla arama
setFragmentResultListener()
aşağıdaki örnekte gösterildiği gibi A parçasının FragmentManager
üzerinde:
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
kullanarak aynı FragmentManager
üzerinde. Yapabilecekleriniz
Bu nedenle,
setFragmentResult()
API:
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); } });
A parçası daha sonra sonucu alır ve dinleyici geri çağırmasını yürütür
parça daha sonra
STARTED
.
Belirli bir anahtar için yalnızca tek bir işleyici ve sonuç olabilir. Arama yaptığınızda
setFragmentResult()
aynı tuş için birden fazla kez ve dinleyici
STARTED
değil, sistem bekleyen sonuçları güncel
yardımcı olur.
Karşılık gelen bir dinleyici olmadan bir sonucu ayarlarsanız
bir işleyici ayarlanana kadar sonuç FragmentManager
içinde saklanır
aynı tuşa sahiptir. Dinleyici bir sonuç aldıktan sonra
onFragmentResult()
geri çağırması, sonuç temizlendi. Bu davranış
şu iki çıkarıma denk gelir:
- Arka yığındaki parçalar, oluşturulana kadar
patlatıldı ve
STARTED
. - Sonuç ayarlandığında bir sonucu dinleyen parça
STARTED
ise dinleyicinin geri araması hemen tetiklenir.
Parça sonuçlarını test et
Tekliflerinizi otomatikleştirmek ve optimize etmek için
FragmentScenario
setFragmentResult()
ve setFragmentResultListener()
numaralı telefona yapılan aramaları test edin.
Aşağıdaki kodu kullanarak test edilen parça için bir senaryo oluşturun:
launchFragmentInContainer
veya
launchFragment
,
ardından test edilmeyen yöntemi manuel olarak çağırın.
setFragmentResultListener()
test etmek için
setFragmentResultListener()
çağrısını yapan parçası. Sonra,
setFragmentResult()
adlı kişiyi doğrudan çağırı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()
numaralı telefona sesli arama yapın. Sonra setFragmentResultListener()
numaralı telefonu arayın
girin 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 iletme
Bir alt parçadan elde edilen sonucu üst öğeye iletmek için
yerine üst parçadan getChildFragmentManager()
kullan
setFragmentResultListener()
aranıyor getParentFragmentManager()
.
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
öğesinde ayarlar. Üst öğe
ve 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); } });
Düzenleyen etkinliğiyle ilgili sonuçları al
Ana makine etkinliğinde bir parça sonucu almak için sonuç işleyici ayarlayın
parça yöneticisinde
getSupportFragmentManager()
.
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. } }); } }