نظرة عامة على LiveData جزء من Android Jetpack.
LiveData
هي فئة حامل بيانات
قابلة للتتبّع. على عكس العنصر القابل للتتبّع العادي، يراعي LiveData دورة الحياة،
أي أنّه يراعي دورة حياة مكوّنات التطبيق الأخرى، مثل الأنشطة أو
المقاطع أو الخدمات. يضمن هذا الوعي أنّ LiveData لا تعدّل إلا مراقبي
مكونات التطبيق الذين هم في حالة نشطة من دورة الحياة.
تُعتبر فئة مراقب LiveData، التي تمثّلها فئة
Observer
، في حالة
نشطة إذا كانت دورة حياتها في حالة
STARTED
أو
RESUMED
. لا تُرسِل LiveData إشعارات إلا للمراقِبين النشطين بشأن التعديلات. لا يتم إشعار المراقِبين غير النشطين المُسجَّلين لمشاهدة مواد عرض
LiveData
بالتغييرات.
يمكنك تسجيل مراقب مقترن بعنصر ينفذ واجهة
LifecycleOwner
. تسمح هذه العلاقة بإزالة المراقب عندما تتغيّر حالة
كائن
Lifecycle
المقابل
إلى
DESTROYED
.
ويُعدّ ذلك مفيدًا بشكل خاص للأنشطة والمقاطع لأنّه يمكنها
مراقبة عناصر LiveData
بأمان
ولا داعي للقلق بشأن عمليات التسرب، إذ يتم
إلغاء اشتراك الأنشطة والمقاطع على الفور عند إتلاف دورات حياتها.
لمزيد من المعلومات حول كيفية استخدام LiveData، راجِع مقالة العمل مع مثيلات LiveData.
مزايا استخدام LiveData
يوفّر استخدام LiveData المزايا التالية:
- ضمان تطابق واجهة المستخدم مع حالة بياناتك
- تتبع LiveData نمط المراقب. تُرسِل فئة LiveData إشعارًا إلى عناصر
Observer
عند تغيُّر البيانات الأساسية. يمكنك توحيد الرمز البرمجي لتعديل واجهة المستخدم في عناصرObserver
هذه. بهذه الطريقة، لن تحتاج إلى تعديل واجهة المستخدم في كل مرّة تتغيّر فيها بيانات التطبيق لأنّ أداة المراقبة ستُجري ذلك نيابةً عنك. - عدم تسرّب الذاكرة
- ترتبط مراقبي الأداء بعناصر
Lifecycle
، ويقومون بتنظيف البيانات بعد انتهاء دورة نشاطها. - عدم حدوث أعطال بسبب الأنشطة المتوقفة
- إذا كانت دورة حياة المُراقِب غير نشطة، مثل نشاط في الحزمة الخلفية، لن يتلقّى أي أحداث LiveData.
- التوقف عن التعامل اليدوي مع دورة الحياة
- ترصد مكونات واجهة المستخدم البيانات ذات الصلة فقط ولا تتوقف عن الرصد أو تستأنفه. تدير LiveData كل هذا تلقائيًا لأنّها على دراية بتغييرات حالة دورة الحياة ذات الصلة أثناء المراقبة.
- بيانات محدَّثة دائمًا
- إذا أصبحت رحلة المستخدِم غير نشطة، ستتلقّى أحدث البيانات عند عودتها إلى النشاط مرة أخرى. على سبيل المثال، يتلقّى النشاط الذي كان في الخلفية أحدث البيانات مباشرةً بعد عودته إلى المقدّمة.
- تغييرات الإعداد المناسبة
- في حال إعادة إنشاء نشاط أو جزء بسبب تغيير في الإعدادات، مثل تبديل وضع الجهاز، يتلقّى على الفور أحدث البيانات المتاحة.
- مشاركة الموارد
- يمكنك توسيع
LiveData
العنصر باستخدام نمط العنصر الفردي لتضمين خدمات النظام حتى يمكن مشاركتها في تطبيقك. يتصل عنصرLiveData
بخدمة النظام مرة واحدة، ثم يمكن لأي مراقب يحتاج إلى المورد مشاهدةLiveData
العنصر فقط. لمزيد من المعلومات، يُرجى الاطّلاع على مقالة توسيع نطاق LiveData.
العمل مع عناصر LiveData
اتّبِع الخطوات التالية للعمل مع عناصر
LiveData
:
- أنشئ مثيلًا من
LiveData
لتخزين نوع معيّن من البيانات. يتم ذلك عادةً في صفViewModel
. - أنشئ عنصر
Observer
يحدِّدonChanged()
الطريقة التي تتحكّم في ما يحدث عند تغيير البيانات المخزّنة في عنصرLiveData
. يتم عادةً إنشاء عنصرObserver
في وحدة تحكّم في واجهة المستخدم، مثل نشاط أو جزء. اربط كائن
Observer
بكائنLiveData
باستخدام الطريقةobserve()
. تأخذ الطريقةobserve()
عنصرًا من نوعLifecycleOwner
. يؤدي ذلك إلى اشتراك عنصرObserver
في عنصرLiveData
لكي يتم إعلامه بالتغييرات. يتم عادةً إرفاق عنصرObserver
في ملف عنصر تحكّم في واجهة المستخدم، مثل نشاط أو جزء.
عند تعديل القيمة المخزّنة في عنصر LiveData
، يتم تشغيل جميع
المراقبين المسجّلين ما دام LifecycleOwner
المرفق في الحالة
النشطة.
تسمح LiveData لمراقبي عنصر التحكّم في واجهة المستخدم بالاشتراك في آخر الأخبار. عندما تتغيّر البيانات
التي يحتفظ بها عنصر LiveData
، يتم تعديل واجهة المستخدم تلقائيًا استجابةً لذلك.
إنشاء عناصر LiveData
LiveData هو عنصر تغليف يمكن استخدامه مع أي بيانات، بما في ذلك الكائنات التي
تنفِّذ Collections
، مثل List
. يتم عادةً
تخزين كائن
LiveData
ضمن كائن ViewModel
ويتم الوصول إليه من خلال طريقة جلب، كما هو موضّح في المثال التالي:
Kotlin
class NameViewModel : ViewModel() { // Create a LiveData with a String val currentName: MutableLiveData<String> by lazy { MutableLiveData<String>() } // Rest of the ViewModel... }
Java
public class NameViewModel extends ViewModel { // Create a LiveData with a String private MutableLiveData<String> currentName; public MutableLiveData<String> getCurrentName() { if (currentName == null) { currentName = new MutableLiveData<String>(); } return currentName; } // Rest of the ViewModel... }
في البداية، لا يتمّ ضبط البيانات في عنصر LiveData
.
يمكنك قراءة المزيد من المعلومات عن مزايا فئة ViewModel
وكيفية استخدامها في
دليل ViewModel.
مراقبة عناصر LiveData
في معظم الحالات، تكون طريقة onCreate()
لمكوّن التطبيق هي المكان المناسب لبدء مراقبة ملف شخصي على
LiveData
للأسباب التالية:
- لضمان عدم إجراء النظام لطلبات متكرّرة من طريقة
onResume()
في النشاط أو القطعة - لضمان أن يحتوي النشاط أو المقتطف على بيانات يمكن عرضها فورًا
بعد أن يصبح نشطًا بعد أن يصبح مكوّن التطبيق في حالة
STARTED
، يتلقّى أحدث قيمة من عناصرLiveData
التي يراقبها. ولا يحدث ذلك إلّا إذا تم ضبط عنصرLiveData
المطلوب رصده.
بشكل عام، لا تُرسِل LiveData آخر المعلومات إلا عند تغيير البيانات، ولا تُرسِلها إلا إلى المراقبين النشطين. يُستثنى من هذا السلوك أنّ المراقبين يتلقّون أيضًا إشعارًا عند تغيير حالتهم من غير نشطة إلى نشطة. بالإضافة إلى ذلك، إذا تغيّر حالة المراقِب من غير نشط إلى نشط للمرة الثانية، لن يتلقّى سوى تعديل إذا تغيّرت القيمة منذ آخر مرة أصبح فيها نشطًا.
يوضّح الرمز البرمجي النموذجي التالي كيفية بدء مراقبة LiveData
عنصر:
Kotlin
class NameActivity : AppCompatActivity() { // Use the 'by viewModels()' Kotlin property delegate // from the activity-ktx artifact private val model: NameViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Other code to setup the activity... // Create the observer which updates the UI. val nameObserver = Observer<String> { newName -> // Update the UI, in this case, a TextView. nameTextView.text = newName } // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer. model.currentName.observe(this, nameObserver) } }
Java
public class NameActivity extends AppCompatActivity { private NameViewModel model; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Other code to setup the activity... // Get the ViewModel. model = new ViewModelProvider(this).get(NameViewModel.class); // Create the observer which updates the UI. final Observer<String> nameObserver = new Observer<String>() { @Override public void onChanged(@Nullable final String newName) { // Update the UI, in this case, a TextView. nameTextView.setText(newName); } }; // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer. model.getCurrentName().observe(this, nameObserver); } }
بعد استدعاء
observe()
مع تمرير nameObserver
كمَعلمة
، يتم استدعاء
onChanged()
على الفور لتوفير أحدث قيمة مخزّنة في mCurrentName
.
إذا لم يضبط عنصر LiveData
قيمة في mCurrentName
، لن يتم
استدعاء onChanged()
.
تعديل عناصر LiveData
لا تتوفّر في LiveData طرق متاحة للجميع لتعديل البيانات المخزّنة. تعرض فئة
MutableLiveData
الطريقتَين
setValue(T)
و
postValue(T)
علنًا، ويجب استخدامهما إذا كنت بحاجة إلى تعديل القيمة المخزّنة في
عنصر LiveData
. عادةً ما يتم استخدام
MutableLiveData
في
ViewModel
، ثم يعرِض
ViewModel
كائنات LiveData
غير قابلة للتغيير للمراقبين فقط.
بعد إعداد علاقة المراقب، يمكنك بعد ذلك تعديل قيمة
العنصر LiveData
، كما هو موضّح في المثال التالي الذي يؤدي
إلى تنشيط جميع المراقبين عندما ينقر المستخدم على زر:
Kotlin
button.setOnClickListener { val anotherName = "John Doe" model.currentName.setValue(anotherName) }
Java
button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { String anotherName = "John Doe"; model.getCurrentName().setValue(anotherName); } });
يؤدي استدعاء setValue(T)
في المثال إلى استدعاء المراقبين لطريقة
onChanged()
بالقيمة John Doe
. يعرض المثال الضغط على زر، ولكن يمكن استدعاء setValue()
أو postValue()
لتعديل mName
لأسباب مختلفة، بما في ذلك استجابةً لطلب شبكة أو اكتمال تحميل قاعدة بيانات. وفي جميع الحالات، يؤدي استدعاء setValue()
أو postValue()
إلى تنشيط مراقبي الأداء وتعديل واجهة المستخدم.
استخدام LiveData مع Room
تتوافق مكتبة الثبات في Room مع
طلبات البحث القابلة للتتبّع، والتي تعرض
كائنات LiveData
.
يتم كتابة طلبات البحث القابلة للتتبّع كجزء من كائن الوصول إلى قاعدة البيانات (DAO).
ينشئ Room كل الرمز البرمجي اللازم لتعديل عنصر LiveData
عند تعديل
قاعدة بيانات. يُشغِّل الرمز الذي تم إنشاؤه طلب البحث بشكل غير متزامن على سلسلسة مهام في background عند الحاجة. يُعدّ هذا النمط مفيدًا للحفاظ على مزامنة البيانات التي يتم عرضها في واجهة مستخدِم مع البيانات المخزّنة في قاعدة بيانات. يمكنك الاطّلاع على مزيد من المعلومات
حول Room وDAO في دليل مكتبة Room الثابتة.
استخدام وظائف التشغيل المتعدّد في وقت واحد مع LiveData
يتضمّن الإصدار LiveData
دعمًا لعمليات التشغيل المتعدّدة في Kotlin. لمزيد من المعلومات، يُرجى الاطّلاع على مقالة
استخدام مهام Kotlin المتعدّدة المهام مع مكونات بنية Android.
LiveData في بنية التطبيق
LiveData
يراعي دورة الحياة، ويتتبّع دورة حياة الكيانات، مثل
الأنشطة والمقاطع. استخدِم LiveData
للتواصل بين مالكي LiveData
وعناصر أخرى ذات مدة صلاحية مختلفة، مثل عناصر ViewModel
.
تتمثل المسؤولية الرئيسية لعنصر ViewModel
في تحميل بيانات ملف تعريف المستخدم
وإدارتها، ما يجعله مرشحًا رائعًا لحمل عناصر LiveData
. أنشئ LiveData
في ViewModel
واستخدِمها لعرض الحالة على LiveData
يجب ألا تحتفظ الأنشطة والشرائح بنماذج LiveData
لأنّ دورها هو عرض البيانات، وليس الاحتفاظ بالحالة. بالإضافة إلى ذلك، فإنّ إبقاء الأنشطة والمقاطع خالية
من الاحتفاظ بالبيانات يسهّل كتابة اختبارات الوحدة.
قد يكون من المغري استخدام عناصر LiveData
في فئة طبقة البيانات، ولكن
LiveData
غير مصمّمة لمعالجة مصادر البيانات غير المتزامنة. على الرغم من
أنّه يمكنك استخدام عمليات تحويل LiveData
وMediatorLiveData
لتحقيق ذلك، إلا أنّ هذا النهج له عيوب: إنّ إمكانية دمج تدفّقات
البيانات محدودة جدًا ويتم رصد جميع عناصر LiveData
(بما في ذلك العناصر التي تم إنشاؤها
من خلال عمليات التحويل) في سلسلة المهام الرئيسية. الرمز البرمجي أدناه هو مثال على كيفية حظر السلسلة الأساسية
بواسطة عقد LiveData
في Repository
:
Kotlin
class UserRepository { // DON'T DO THIS! LiveData objects should not live in the repository. fun getUsers(): LiveData<List<User>> { ... } fun getNewPremiumUsers(): LiveData<List<User>> { return getUsers().map { users -> // This is an expensive call being made on the main thread and may // cause noticeable jank in the UI! users .filter { user -> user.isPremium } .filter { user -> val lastSyncedTime = dao.getLastSyncedTime() user.timeCreated > lastSyncedTime } } }
Java
class UserRepository { // DON'T DO THIS! LiveData objects should not live in the repository. LiveData<List<User>> getUsers() { ... } LiveData<List<User>> getNewPremiumUsers() { return Transformations.map(getUsers(), // This is an expensive call being made on the main thread and may cause // noticeable jank in the UI! users -> users.stream() .filter(User::isPremium) .filter(user -> user.getTimeCreated() > dao.getLastSyncedTime()) .collect(Collectors.toList())); } }
إذا كنت بحاجة إلى استخدام مصادر بيانات في طبقات أخرى من تطبيقك، ننصحك باستخدام
عمليات تدفق Kotlin ثم تحويلها إلى LiveData
في
ViewModel
باستخدام asLiveData()
.
اطّلِع على مزيد من المعلومات حول استخدام Flow
مع LiveData
في هذه الدورة التدريبية حول الترميز.
بالنسبة إلى قواعد البيانات التي تم إنشاؤها باستخدام Java، ننصحك باستخدام المنفِّذين
بالاشتراك مع وظائف الاستدعاء أو RxJava
.
توسيع نطاق LiveData
تُعتبر أداة LiveData أنّ المراقب في حالة نشطة إذا كانت مرحلته المتعلّقة بالرصد في حالتَي STARTED
أو RESUMED
. يوضّح الرمز البرمجي النموذجي التالي كيفية توسيع فئة
LiveData
:
Kotlin
class StockLiveData(symbol: String) : LiveData<BigDecimal>() { private val stockManager = StockManager(symbol) private val listener = { price: BigDecimal -> value = price } override fun onActive() { stockManager.requestPriceUpdates(listener) } override fun onInactive() { stockManager.removeUpdates(listener) } }
Java
public class StockLiveData extends LiveData<BigDecimal> { private StockManager stockManager; private SimplePriceListener listener = new SimplePriceListener() { @Override public void onPriceChanged(BigDecimal price) { setValue(price); } }; public StockLiveData(String symbol) { stockManager = new StockManager(symbol); } @Override protected void onActive() { stockManager.requestPriceUpdates(listener); } @Override protected void onInactive() { stockManager.removeUpdates(listener); } }
يتضمّن تنفيذ مستمع الأسعار في هذا المثال الطرق المهمة التالية:
- يتمّ استدعاء الطريقة
onActive()
عندما يكون لكائنLiveData
مراقب نشط. وهذا يعني أنّك تحتاج إلى بدء مراقبة تعديلات أسعار الأسهم من خلال هذه الطريقة. - يتمّ استدعاء الطريقة
onInactive()
عندما لا يتضمّن عنصرLiveData
أيّ مراقبين نشطين. بما أنّه لا يوجد مراقبون يستمعون إلى المكالمة، ما مِن سبب للبقاء متصلاً بخدمةStockManager
. - تعمل الطريقة
setValue(T)
على تعديل قيمة مثيلLiveData
وإرسال إشعار إلى أي مراقبين فعالين بشأن التغيير.
يمكنك استخدام فئة StockLiveData
على النحو التالي:
Kotlin
public class MyFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val myPriceListener: LiveData<BigDecimal> = ... myPriceListener.observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? -> // Update the UI. }) } }
Java
public class MyFragment extends Fragment { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); LiveData<BigDecimal> myPriceListener = ...; myPriceListener.observe(getViewLifecycleOwner(), price -> { // Update the UI. }); } }
تُرسِل الطريقة
observe()
العنصر LifecycleOwner
المرتبط بعرض المقتطف كوسيطة أولى. ويشير ذلك إلى أنّه
يكون هذا المُراقب مرتبطًا بعنصر Lifecycle
المرتبط بالمالك، أي:
- إذا لم يكن عنصر
Lifecycle
في حالة نشطة، لن يتم استدعاء المُراقب حتى إذا تغيّرت القيمة. - بعد تدمير العنصر
Lifecycle
، تتم إزالة المراقب تلقائيًا.
بما أنّ عناصر LiveData
تكون على دراية بالحالة، يمكنك مشاركتها
بين أنشطة وشظايا وخدمات متعددة. للحفاظ على مثال
بسيط، يمكنك تنفيذ فئة LiveData
كعنصر وحيد على النحو التالي:
Kotlin
class StockLiveData(symbol: String) : LiveData<BigDecimal>() { private val stockManager: StockManager = StockManager(symbol) private val listener = { price: BigDecimal -> value = price } override fun onActive() { stockManager.requestPriceUpdates(listener) } override fun onInactive() { stockManager.removeUpdates(listener) } companion object { private lateinit var sInstance: StockLiveData @MainThread fun get(symbol: String): StockLiveData { sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol) return sInstance } } }
Java
public class StockLiveData extends LiveData<BigDecimal> { private static StockLiveData sInstance; private StockManager stockManager; private SimplePriceListener listener = new SimplePriceListener() { @Override public void onPriceChanged(BigDecimal price) { setValue(price); } }; @MainThread public static StockLiveData get(String symbol) { if (sInstance == null) { sInstance = new StockLiveData(symbol); } return sInstance; } private StockLiveData(String symbol) { stockManager = new StockManager(symbol); } @Override protected void onActive() { stockManager.requestPriceUpdates(listener); } @Override protected void onInactive() { stockManager.removeUpdates(listener); } }
ويمكنك استخدامها في المقتطف على النحو التالي:
Kotlin
class MyFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) StockLiveData.get(symbol).observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? -> // Update the UI. }) }
Java
public class MyFragment extends Fragment { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); StockLiveData.get(symbol).observe(getViewLifecycleOwner(), price -> { // Update the UI. }); } }
يمكن لعدة أقسام وأنشطة مراقبة مثيل MyPriceListener
.
لا تتصل LiveData بخدمة النظام إلا إذا كان هناك خدمة واحدة أو أكثر مرئية
ونشطة.
تحويل LiveData
قد تحتاج إلى إجراء تغييرات على القيمة المخزّنة في عنصر
LiveData
قبل
إرساله إلى المراقبين، أو قد تحتاج إلى عرض مثيل مختلف
LiveData
استنادًا إلى قيمة مثيل آخر. تقدِّم حزمة
Lifecycle
الفئة
Transformations
التي تتضمّن طرق مساعدة تتيح هذه السيناريوهات.
Transformations.map()
- تطبّق دالة على القيمة المخزّنة في عنصر
LiveData
، ويؤدي ذلك إلى نشر النتيجة في مسار الإحالة الناجحة.
Kotlin
val userLiveData: LiveData<User> = UserLiveData() val userName: LiveData<String> = userLiveData.map { user -> "${user.name} ${user.lastName}" }
Java
LiveData<User> userLiveData = ...; LiveData<String> userName = Transformations.map(userLiveData, user -> { user.name + " " + user.lastName });
Transformations.switchMap()
- على غرار
map()
، تطبِّق دالة على القيمة المخزّنة فيLiveData
العنصر وتزيل تغليفه وتُرسِله إلى أسفل السلسلة. يجب أن تعرِض الدالة التي تم تمريرها إلىswitchMap()
عنصرLiveData
، كما هو موضّح في المثال التالي:
Kotlin
private fun getUser(id: String): LiveData<User> { ... } val userId: LiveData<String> = ... val user = userId.switchMap { id -> getUser(id) }
Java
private LiveData<User> getUser(String id) { ...; } LiveData<String> userId = ...; LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );
يمكنك استخدام طرق التحويل لنقل المعلومات على مستوى
رحلة المراقب. لا يتم احتساب عمليات التحويل ما لم يكن هناك مراقب يشاهد
عنصر LiveData
الذي تم إرجاعه. وبما أنّ عمليات التحويل يتم احتسابها
ببطء، يتم بشكل ضمني تمرير السلوك المرتبط بالدورة الحيوية بدون الحاجة إلى
طلبات أو تبعيات صريحة إضافية.
إذا كنت تعتقد أنّك بحاجة إلى عنصر Lifecycle
داخل عنصر
ViewModel
، من المحتمل أنّ التحويل هو الحلّ الأفضل. على سبيل المثال، لنفترض أنّ لديك
مكوّن واجهة مستخدم يقبل عنوانًا ويعرض الرمز البريدي لذلك
العنوان. يمكنك تنفيذ ViewModel
البسيط لهذا المكوّن كما هو موضح في الرمز البرمجي النموذجي التالي:
Kotlin
class MyViewModel(private val repository: PostalCodeRepository) : ViewModel() { private fun getPostalCode(address: String): LiveData<String> { // DON'T DO THIS return repository.getPostCode(address) } }
Java
class MyViewModel extends ViewModel { private final PostalCodeRepository repository; public MyViewModel(PostalCodeRepository repository) { this.repository = repository; } private LiveData<String> getPostalCode(String address) { // DON'T DO THIS return repository.getPostCode(address); } }
بعد ذلك، يجب أن يُلغي مكوّن واجهة المستخدم تسجيله من عنصر LiveData
السابق ويُسجِّله في المثيل الجديد في كل مرة يُطلِب فيها getPostalCode()
. بالإضافة إلى ذلك، في حال إعادة إنشاء مكوّن واجهة المستخدم، يؤدي ذلك إلى إجراء طلب آخر إلى الأسلوب
repository.getPostCode()
بدلاً من استخدام نتيجة الطلب السابق.
بدلاً من ذلك، يمكنك تنفيذ البحث عن الرمز البريدي كتحويل لإدخال العنوان، كما هو موضّح في المثال التالي:
Kotlin
class MyViewModel(private val repository: PostalCodeRepository) : ViewModel() { private val addressInput = MutableLiveData<String>() val postalCode: LiveData<String> = addressInput.switchMap { address -> repository.getPostCode(address) } private fun setInput(address: String) { addressInput.value = address } }
Java
class MyViewModel extends ViewModel { private final PostalCodeRepository repository; private final MutableLiveData<String> addressInput = new MutableLiveData(); public final LiveData<String> postalCode = Transformations.switchMap(addressInput, (address) -> { return repository.getPostCode(address); }); public MyViewModel(PostalCodeRepository repository) { this.repository = repository } private void setInput(String address) { addressInput.setValue(address); } }
في هذه الحالة، يتم تعريف الحقل postalCode
على أنّه تحويل لمحاولة
addressInput
. ما دام تطبيقك يتضمّن مراقبًا نشطًا مرتبطًا بحقل
postalCode
، تتم إعادة احتساب قيمة الحقل واستردادها عند تغيُّر
addressInput
.
تسمح هذه الآلية للمستويات الدنيا من التطبيق بإنشاء عناصر LiveData
يتم حسابها بشكلٍ كسول عند الطلب. يمكن لعنصر ViewModel
الحصول بسهولة على
مراجع إلى عناصر LiveData
، ثم تحديد قواعد التحويل بالإضافة إلى
هذه العناصر.
إنشاء عمليات تحويل جديدة
هناك اثنا عشر عملية تحويل مختلفة قد تكون مفيدة في
تطبيقك، ولكن لا يتم توفيرها تلقائيًا. لتنفيذ عملية التحويل الخاصة بك،
يمكنك استخدام فئة MediatorLiveData
التي تستمع إلى مثيلات
LiveData
الأخرى ومعالجتها للأحداث التي تطلقها. ينشر MediatorLiveData
حالته بشكل صحيح إلى عنصر المصدر LiveData
. لمزيد من المعلومات عن هذا النمط، اطّلِع على مستندات مرجعية للفئة
Transformations
.
دمج مصادر LiveData متعددة
MediatorLiveData
هو
فئة فرعية من LiveData
تسمح
بدمج مصادر LiveData متعددة. بعد ذلك، يتم تنشيط مراقبي MediatorLiveData
كائنات عند تغيُّر أي من كائنات مصدر LiveData الأصلية.
على سبيل المثال، إذا كان لديك عنصر LiveData
في واجهة المستخدم يمكن تعديله من
قاعدة بيانات محلية أو شبكة، يمكنك إضافة المصادر التالية إلى MediatorLiveData
:
- عنصر
LiveData
مرتبط بالبيانات المخزّنة في قاعدة البيانات - عنصر
LiveData
مرتبط بالبيانات التي يتم الوصول إليها من الشبكة
ما عليك سوى مراقبة عنصر MediatorLiveData
لتلقّي ข้อมูล مثبّتة من كلا المصدرَين. للحصول على مثال مفصّل، اطّلِع على قسم الملحق: عرض حالة الشبكة
في دليل بنية التطبيقات.
مصادر إضافية
لمزيد من المعلومات حول فئة
LiveData
، يمكنك الرجوع إلى
المراجع التالية.
نماذج
- Sunflower، تطبيق تجريبي يعرض أفضل الممارسات المتعلّقة بمكونات البنية
الدروس التطبيقية حول الترميز
- Android Room مع عرض (Java) (Kotlin)
- التعرّف على الكوروتينات المتقدّمة باستخدام Kotlin Flow وLiveData
المدوّنات
- ViewModels وLiveData: الأنماط وممارسات التصميم غير المرغوب فيها
- استخدام LiveData خارج ViewModel: الأنماط التفاعلية باستخدام Transformations وMediatorLiveData
- LiveData مع SnackBar وNavigation والأحداث الأخرى (حالة SingleLiveEvent)
الفيديوهات
أفلام مُقترَحة لك
- ملاحظة: يتم عرض نص الرابط عندما تكون لغة JavaScript غير مفعّلة.
- استخدام مهام Kotlin المتعدّدة المهام مع المكونات المدرِكة لدورة الحياة
- معالجة دورات الحياة باستخدام المكوّنات المدركِة لدورة الحياة
- اختبار عملية تنفيذ ميزة "التنقّل في البيانات"