نظرة عامة على LiveData جزء من Android Jetpack.
LiveData
هي فئة لأصحاب بيانات
يمكن ملاحظتها. على عكس أي ملاحظة عادية يمكن ملاحظتها، تعتمد LiveData على مراحل النشاط،
أي أنها تحترم دورة حياة مكوّنات التطبيق الأخرى، مثل الأنشطة أو الأجزاء أو الخدمات. يضمن هذا الوعي أن يتم تحديث LiveData فقط
لمراقبي مكونات التطبيقات الذين يتصفحون دورة حياة نشطة.
تعتبر البيانات المباشرة المراقب، الذي تمثّله الفئة
Observer
، في
حالة نشطة إذا كانت مراحل نشاطه ضمن الحالة
STARTED
أو
RESUMED
. لا تبلّغ LiveData سوى المُراقبين النشطين بالتحديثات. ولا يتم إشعار المستخدمين غير النشطين
المسجّلين لمشاهدة عناصر
LiveData
بالتغييرات.
يمكنك تسجيل مراقِب مقترن بكائن ينفّذ واجهة
LifecycleOwner
. تسمح هذه العلاقة بإزالة المراقب عند تغيير حالة عنصر Lifecycle
المقابل إلى DESTROYED
.
ويكون ذلك مفيدًا على وجه التحديد للأنشطة والأجزاء لأنّها تستطيع رصد عناصر LiveData
بأمان وعدم القلق بشأن تسرُّبها، حيث يتم على الفور إلغاء اشتراك الأنشطة والأجزاء عند تدمير مراحل نشاطها.
لمزيد من المعلومات حول كيفية استخدام LiveData، راجع استخدام كائنات LiveData.
مزايا استخدام البيانات المباشرة
يوفر استخدام البيانات المباشرة المزايا التالية:
- التأكد من تطابق واجهة المستخدم مع حالة بياناتك
- تتّبع LiveData نمط المراقب. ترسِل ميزة LiveData إشعارات إلى عناصر
Observer
عند تعديل البيانات الأساسية. يمكنك دمج الرموز البرمجية لتحديث واجهة المستخدم في عناصرObserver
هذه. بهذه الطريقة، لن تحتاج إلى تعديل واجهة المستخدم في كل مرة تتغير فيها بيانات التطبيق لأنّ المراقب يجري ذلك نيابةً عنك. - عدم تسرُّب الذاكرة
- يتقيّد المراقبون بأغراض
Lifecycle
وينظفونها بعد تدمير مراحل نشاطها المرتبطة بها. - ما مِن أعطال بسبب الأنشطة المتوقفة
- إذا كانت دورة حياة المراقب غير ��شطة، كما هو الحال في حالة نشاط ما في الحزمة الخلفية، لن يتلقّى أي أحداث LiveData.
- لم تعد هناك حاجة إلى المعالجة اليدوية لمراحل النشاط
- تراقب مكونات واجهة المستخدم البيانات ذات الصلة ولا تتوقف عن الملاحظة أو تستأنفها. وتدير ميزة LiveData كل هذا تلقائيًا لأنّها تدرك تغييرات حالة مراحل النشاط ذات الصلة أثناء الملاحظة.
- البيانات المحدّثة دائمًا
- إذا أصبحت إحدى مراحل النشاط غير نشطة، فإنها تتلقى أحدث البيانات عند تنشيطها مجددًا. على سبيل المثال، يتلقى نشاط كان في الخلفية أحدث البيانات مباشرةً بعد عودته إلى المقدمة.
- التغييرات الصحيحة على الإعدادات
- في حال إعادة إنشاء نشاط أو جزء بسبب تغيير في الإعدادات، مثل تدوير الجهاز، سيتم على الفور إرسال أحدث البيانات المتاحة.
- مشاركة المراجع
- يمكنك تمديد عنصر
LiveData
باستخدام نمط "سينغلتون" لالتفاف خدمات النظام بحيث يمكن مشاركتها في تطبيقك. ويتم ربط الكائنLiveData
بخدمة النظام مرة واحدة، وسيتمكّن أي مراقب يحتاج إلى المورد من مشاهدة الكائنLiveData
فقط. لمزيد من المعلومات، يُرجى الاطّلاع على مقالة Extend 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
ويتم الوصول إليه باستخدام طريقة getter، كما هو موضّح في المثال التالي:
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()
إلى ملاحظة واجهة المستخدم وتعديلها.
استخدام "البيانات المباشرة" مع الغرفة
تتوافق مكتبة الاستمرارية في Room مع طلبات البحث القابلة للتتبّع، التي تعرض عناصر LiveData
.
تتم كتابة الاستعلامات القابلة للملاحظة كجزء من كائن الوصول إلى قاعدة البيانات (DAO).
تنشئ الغرفة كل الرموز اللازمة لتعديل عنصر LiveData
عند تعديل قاعدة بيانات. تقوم التعليمة البرمجية التي تم إنشاؤها بتشغيل الاستعلام بشكل غير متزامن على
سلسلة محادثات في الخلفية عند الحاجة. هذا النمط مفيد ��لحفاظ على البيانات المعروضة في
واجهة مستخدم متزامنة مع البيانات المخزنة في قاعدة البيانات. يمكنك الاطّلاع على المزيد من المعلومات
حول الغرف ووحدات DAO في دليل المكتبة الدائمة في "الغرفة".
استخدام الكوروتينات مع LiveData
تشمل LiveData
إ��احة استخدام الكوروتينات في لغة Kotlin. لمزيد من المعلومات، يُرجى الاطّلاع على
استخدام الكوروتينات في لغة Kotlin مع مكونات Android الهندسية.
LiveData في بنية التطبيق
تراعي LiveData
مراحل النشاط، وهي تتتبّع مراحل نشاط الكيانات، مثل الأنشطة والأجزاء. يمكنك استخدام LiveData
للتواصل بين مالكي دورات الحياة هؤلاء والكائنات الأخرى التي لها عمر مختلف، مثل كائنات ViewModel
.
تتمثّل المسؤولية الرئيسية لـ ViewModel
في تحميل البيانات المتعلّقة بواجهة المستخدم وإدارتها،
ما يجعلها مرشحة رائعة للاحتفاظ بكائنات LiveData
. يمكنك إنشاء
كائنات LiveData
في ViewModel
واستخدامها لكشف الحالة لطبقة
واجهة المستخدم.
يجب ألا تتضمّن الأنشطة والأجزاء مثيلات 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
في Kotlin مع LiveData
في هذا الدرس التطبيقي حول الترميز.
بالنسبة إلى قواعد الترميز التي تم إنشاؤها باستخدام لغة Java، يمكنك استخدام أداة Executors
إلى جانب عمليات معاودة الاتصال أو RxJava
.
توسيع 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
مختلف استنادًا إلى قيمة مثيل آخر. توفِّر حزمة
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
الدروس التطبيقية حول الترميز
- غرفة Android مع إطلالة (Java) (Kotlin)
- تعرَّف على الكوروتينات المتطوّرة في Kotlin Flow وLiveData.
المدوّنات
- ViewModels وLiveData: الأنماط + الأنماط المضادة للأنماط
- LiveData خارج إطار العرض: أنماط تفاعلية باستخدام عمليات التحويل وMediatorLiveData
- LiveData مع SnackBar والتنقل والأحداث الأخرى (حالة IndividualLiveEvent)
الفيديوهات الطويلة
أفلام مُقترَحة لك
- ملاحظة: يتم عرض نص الرابط عند إيقاف JavaScript.
- استخدام الكوروتينات في لغة Kotlin مع مكوّنات تراعي مراحل النشاط
- التعامل مع مراحل النشاط باستخدام مكونات حسب مراحل النشاط
- اختبار تنفيذ عملية الترحيل