Android Kotlin Fundamentals 05.2: LiveData و LiveData ناظران

این کد لبه بخشی از دوره آموزشی Android Kotlin Fundamentals است. اگر به ترتیب روی کدها کار کنید، بیشترین ارزش را از این دوره خواهید گرفت. همه کدهای دوره در صفحه فرود کد لبه های کدهای Android Kotlin Fundamentals فهرست شده اند.

مقدمه

در لبه کد قبلی، از ViewModel در برنامه GuessTheWord استفاده کردید تا به داده های برنامه اجازه دهید از تغییرات پیکربندی دستگاه جان سالم به در ببرند. در این کد لبه، یاد می گیرید که چگونه LiveData را با داده های کلاس های ViewModel ادغام کنید. LiveData ، که یکی از اجزای معماری اندروید است، به شما امکان می دهد تا اشیاء داده بسازید که هنگام تغییر پایگاه داده زیربنایی، نماها را مطلع می کنند.

برای استفاده از کلاس LiveData ، "ناظرها" (به عنوان مثال، فعالیت ها یا قطعات) را تنظیم می کنید که تغییرات در داده های برنامه را مشاهده می کنند. LiveData از چرخه حیات آگاه است، بنابراین فقط ناظران مؤلفه برنامه را که در حالت چرخه حیات فعال هستند به روز می کند.

آنچه از قبل باید بدانید

  • نحوه ایجاد برنامه های اساسی اندروید در Kotlin.
  • چگونه بین مقاصد برنامه خود حرکت کنید.
  • فعالیت و چرخه حیات قطعه
  • نحوه استفاده از اشیاء ViewModel در برنامه خود
  • نحوه ایجاد اشیاء ViewModel با استفاده از رابط ViewModelProvider.Factory .

چیزی که یاد خواهید گرفت

  • چه چیزی اشیاء LiveData را مفید می کند.
  • چگونه LiveData را به داده های ذخیره شده در ViewModel اضافه کنیم.
  • زمان و نحوه استفاده از MutableLiveData .
  • نحوه اضافه کردن متدهای مشاهدهگر برای مشاهده تغییرات در LiveData.
  • نحوه کپسوله کردن LiveData با استفاده از ویژگی پشتیبان.
  • نحوه برقراری ارتباط بین یک کنترلر UI و ViewModel مربوطه آن.

کاری که خواهی کرد

  • از LiveData برای کلمه و امتیاز در برنامه GuessTheWord استفاده کنید.
  • ناظرانی را اضافه کنید که متوجه تغییر کلمه یا امتیاز می شوند.
  • نماهای متنی را که مقادیر تغییر یافته را نمایش می دهند، به روز کنید.
  • از الگوی مشاهده LiveData برای اضافه کردن یک رویداد تمام شده بازی استفاده کنید.
  • دکمه Play Again را اجرا کنید.

در بخش کدهای درس 5، برنامه GuessTheWord را توسعه می‌دهید که با کد شروع شروع می‌شود. GuessTheWord یک بازی دو نفره به سبک charades است که در آن بازیکنان برای دستیابی به بالاترین امتیاز ممکن با یکدیگر همکاری می کنند.

بازیکن اول به کلمات موجود در برنامه نگاه می کند و هر کدام را به نوبه خود عمل می کند و مطمئن می شود که کلمه را به بازیکن دوم نشان نمی دهد. بازیکن دوم سعی می کند کلمه را حدس بزند.

برای انجام بازی، اولین بازیکن برنامه را روی دستگاه باز می کند و کلمه ای را می بیند، به عنوان مثال "گیتار"، همانطور که در تصویر زیر نشان داده شده است.

اولین بازیکن کلمه را اجرا می کند و مراقب است که در واقع خود کلمه را نگوید.

  • وقتی بازیکن دوم کلمه را به درستی حدس زد، بازیکن اول دکمه Got It را فشار می دهد که تعداد را یک عدد افزایش می دهد و کلمه بعدی را نشان می دهد.
  • اگر بازیکن دوم نتواند کلمه را حدس بزند، بازیکن اول دکمه Skip را فشار می‌دهد که تعداد را یک کاهش می‌دهد و به کلمه بعدی می‌رود.
  • برای پایان بازی، دکمه پایان بازی را فشار دهید. (این قابلیت در کد شروع برای اولین آزمایشگاه کد در سری نیست.)

در این لبه کد، برنامه GuessTheWord را با افزودن یک رویداد برای پایان دادن به بازی، زمانی که کاربر در تمام کلمات موجود در برنامه چرخش می‌کند، بهبود می‌بخشید. شما همچنین یک دکمه Play Again را در قسمت امتیاز اضافه می کنید تا کاربر بتواند بازی را دوباره انجام دهد.

صفحه عنوان

صفحه نمایش بازی

صفحه نمایش امتیاز

در این کار، کد شروع خود را برای این کد لبه پیدا کرده و اجرا می کنید. می‌توانید از برنامه GuessTheWord که در Codelab قبلی ساخته‌اید به‌عنوان کد شروع استفاده کنید، یا می‌توانید یک برنامه شروع را دانلود کنید.

  1. (اختیاری) اگر از کد خود از کد آزمایشگاه قبلی استفاده نمی کنید، کد شروع را برای این کد لبه دانلود کنید. کد را از حالت فشرده خارج کرده و پروژه را در Android Studio باز کنید.
  2. برنامه را اجرا کنید و بازی را انجام دهید.
  3. توجه داشته باشید که دکمه Skip کلمه بعدی را نمایش می دهد و یک امتیاز را کاهش می دهد و دکمه Got It کلمه بعدی را نشان می دهد و امتیاز را یک افزایش می دهد. دکمه پایان بازی بازی را به پایان می رساند.

LiveData یک کلاس دارنده داده قابل مشاهده است که از چرخه حیات آگاه است. برای مثال، می‌توانید یک LiveData را حول امتیاز فعلی در برنامه GuessTheWord بپیچید. در این کد لبه با چندین ویژگی LiveData آشنا می شوید:

  • LiveData قابل مشاهده است، به این معنی که هنگامی که داده های نگهداری شده توسط شی LiveData تغییر می کند، یک ناظر مطلع می شود.
  • LiveData داده ها را نگه می دارد. LiveData یک بسته بندی است که می تواند با هر داده ای استفاده شود
  • LiveData از چرخه حیات آگاه است، به این معنی که فقط ناظرانی را که در یک وضعیت چرخه حیات فعال هستند مانند STARTED یا RESUMED به روز می کند.

در این کار، می‌آموزید که چگونه با تبدیل امتیاز فعلی و داده‌های کلمه فعلی در GameViewModel به LiveData ، هر نوع داده را در اشیاء LiveData قرار دهید. در کار بعدی، یک ناظر به این اشیاء LiveData اضافه می‌کنید و یاد می‌گیرید که چگونه LiveData را مشاهده کنید.

مرحله 1: امتیاز و کلمه را برای استفاده از LiveData تغییر دهید

  1. در زیر بسته screens/game ، فایل GameViewModel را باز کنید.
  2. نوع score و word متغیرها را به MutableLiveData .

    MutableLiveData یک LiveData است که مقدار آن قابل تغییر است. MutableLiveData یک کلاس عمومی است، بنابراین باید نوع داده ای که در آن نگهداری می شود را مشخص کنید.
// The current word
val word = MutableLiveData<String>()
// The current score
val score = MutableLiveData<Int>()
  1. در GameViewModel ، در داخل بلوک init ، score و word را مقداردهی اولیه کنید. برای تغییر مقدار متغیر LiveData ، از متد setValue() روی متغیر استفاده می کنید. در Kotlin، می توانید setValue() را با استفاده از ویژگی value فراخوانی کنید.
init {

   word.value = ""
   score.value = 0
  ...
}

مرحله 2: مرجع شی LiveData را به روز کنید

متغیرهای score و word اکنون از نوع LiveData هستند. در این مرحله با استفاده از ویژگی value ، ارجاعات را به این متغیرها تغییر می دهید.

  1. در GameViewModel ، در onSkip() score را به score.value تغییر دهید. به خطای احتمال null بودن score توجه کنید. در مرحله بعد این خطا را رفع می کنید.
  2. برای رفع خطا، یک چک null به score.value در onSkip() اضافه کنید. سپس تابع minus() را در score فراخوانی می‌کند، که تفریق را با امنیت null انجام می‌دهد.
fun onSkip() {
   if (!wordList.isEmpty()) {
       score.value = (score.value)?.minus(1)
   }
   nextWord()
}
  1. onCorrect() را به همین روش به روز کنید: یک چک null به متغیر score اضافه کنید و از تابع plus() استفاده کنید.
fun onCorrect() {
   if (!wordList.isEmpty()) {
       score.value = (score.value)?.plus(1)
   }
   nextWord()
}
  1. در GameViewModel ، در nextWord() ، word reference را به word تغییر دهید . value .
private fun nextWord() {
   if (!wordList.isEmpty()) {
       //Select and remove a word from the list
       word.value = wordList.removeAt(0)
   }
}
  1. در GameFragment ، در updateWordText() مرجع را به viewModel به .word viewModel دهید . word . value.
/** Methods for updating the UI **/
private fun updateWordText() {
   binding.wordText.text = viewModel.word.value
}
  1. در GameFragment ، در updateScoreText() updateScoreText، مرجع را به viewModel به .score viewModel . score . value.
private fun updateScoreText() {
   binding.scoreText.text = viewModel.score.value.toString()
}
  1. در GameFragment ، در داخل gameFinished() ، مرجع را به viewModel به .score viewModel دهید . score . value . چک ایمنی null مورد نیاز را اضافه کنید.
private fun gameFinished() {
   Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
   val action = GameFragmentDirections.actionGameToScore()
   action.score = viewModel.score.value?:0
   NavHostFragment.findNavController(this).navigate(action)
}
  1. مطمئن شوید که هیچ خطایی در کد شما وجود ندارد. برنامه خود را کامپایل و اجرا کنید. عملکرد برنامه باید مانند قبل باشد.

این کار ارتباط نزدیکی با کار قبلی دارد، جایی که شما داده های امتیاز و کلمه را به آبجکت های LiveData تبدیل کردید. در این کار، اشیاء Observer را به آن اشیاء LiveData متصل می کنید.

  1. در GameFragment, در داخل onCreateView() ، یک شی Observer را به شی LiveData برای امتیاز فعلی، viewModel.score کنید. از متد observe() observer استفاده کنید و کد را بعد از مقداردهی اولیه viewModel قرار دهید. از عبارت lambda برای ساده کردن کد استفاده کنید. (یک عبارت لامبدا یک تابع ناشناس است که اعلان نمی شود، اما بلافاصله به عنوان یک عبارت ارسال می شود.)
viewModel.score.observe(this, Observer { newScore ->
})

ارجاع به Observer را حل کنید. برای انجام این کار، روی Observer کلیک کنید، Alt+Enter ( Option+Enter در مک) را فشار دهید و androidx.lifecycle.Observer وارد کنید.

  1. ناظری که به تازگی ایجاد کرده اید، زمانی که داده های نگهداری شده توسط شی LiveData مشاهده شده تغییر می کند، یک رویداد دریافت می کند. در داخل مشاهده گر، امتیاز TextView را با امتیاز جدید به روز کنید.
/** Setting up LiveData observation relationship **/
viewModel.score.observe(this, Observer { newScore ->
   binding.scoreText.text = newScore.toString()
})
  1. یک شی Observer را به شیء فعلی LiveData کنید. این کار را به همان روشی انجام دهید که یک شی Observer را به امتیاز فعلی متصل کردید.
/** Setting up LiveData observation relationship **/
viewModel.word.observe(this, Observer { newWord ->
   binding.wordText.text = newWord
})

وقتی مقدار score یا word تغییر می کند، score یا word نمایش داده شده روی صفحه اکنون به طور خودکار به روز می شود.

  1. در GameFragment ، متدهای updateWordText() و updateScoreText( updateScoreText() و تمام ارجاعات به آنها را حذف کنید. شما دیگر به آنها نیاز ندارید، زیرا نماهای متنی با روش های مشاهده LiveData به روز می شوند.
  2. برنامه خود را اجرا کنید برنامه بازی شما باید دقیقاً مانند قبل کار کند، اما اکنون از ناظران LiveData و LiveData استفاده می کند.

کپسولاسیون راهی برای محدود کردن دسترسی مستقیم به برخی از فیلدهای یک شی است. وقتی یک شی را کپسوله می‌کنید، مجموعه‌ای از روش‌های عمومی را نشان می‌دهید که فیلدهای داخلی خصوصی را تغییر می‌دهند. با استفاده از کپسوله کردن، شما کنترل می کنید که کلاس های دیگر چگونه این فیلدهای داخلی را دستکاری می کنند.

در کد فعلی شما، هر کلاس خارجی می تواند متغیرهای score و word را با استفاده از ویژگی value تغییر دهد، برای مثال با استفاده از viewModel.score.value . ممکن است در برنامه‌ای که در این کد لبه توسعه می‌دهید مهم نباشد، اما در یک برنامه تولیدی، می‌خواهید روی داده‌های موجود در اشیاء ViewModel کنترل داشته باشید.

فقط ViewModel باید داده های برنامه شما را ویرایش کند. اما کنترل‌کننده‌های رابط کاربری باید داده‌ها را بخوانند، بنابراین فیلدهای داده نمی‌توانند کاملاً خصوصی باشند. برای کپسوله کردن داده های برنامه خود، از هر دو MutableLiveData و LiveData استفاده می کنید.

MutableLiveData در مقابل LiveData :

  • همانطور که از نام آن پیداست داده های موجود در یک شی MutableLiveData را می توان تغییر داد. در داخل ViewModel ، داده ها باید قابل ویرایش باشند، بنابراین از MutableLiveData استفاده می کند.
  • داده ها در یک شی LiveData قابل خواندن هستند، اما تغییر نمی کنند. از خارج از ViewModel ، داده ها باید قابل خواندن باشند، اما قابل ویرایش نباشند، بنابراین داده ها باید به عنوان LiveData در معرض نمایش قرار گیرند.

برای اجرای این استراتژی، از ویژگی پشتیبان Kotlin استفاده می کنید. یک ویژگی پشتیبان به شما امکان می دهد چیزی را از یک گیرنده غیر از شی دقیق برگردانید. در این کار، یک ویژگی پشتیبان برای اشیاء score و word در برنامه GuessTheWord پیاده سازی می کنید.

یک ویژگی پشتوانه به امتیاز و کلمه اضافه کنید

  1. در GameViewModel ، شی score فعلی را private کنید.
  2. برای پیروی از قرارداد نامگذاری مورد استفاده در ویژگی های پشتیبان، score را به _score تغییر دهید. ویژگی _score اکنون نسخه قابل تغییر امتیاز بازی است که به صورت داخلی مورد استفاده قرار می گیرد.
  3. یک نسخه عمومی از نوع LiveData به نام score ایجاد کنید.
// The current score
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
  1. شما یک خطای اولیه را مشاهده می کنید. این خطا به این دلیل رخ می دهد که در داخل GameFragment ، score یک مرجع LiveData است و score دیگر نمی تواند به تنظیم کننده آن دسترسی داشته باشد. برای کسب اطلاعات بیشتر در مورد گیرنده ها و ستترها در کاتلین، به Getters and Setters مراجعه کنید.

    برای رفع خطا، متد get() را برای شی score در GameViewModel و ویژگی پشتیبان _score را برگردانید.
val score: LiveData<Int>
   get() = _score
  1. در GameViewModel ، ارجاع score را به نسخه قابل تغییر داخلی آن، _score تغییر دهید.
init {
   ...
   _score.value = 0
   ...
}

...
fun onSkip() {
   if (!wordList.isEmpty()) {
       _score.value = (score.value)?.minus(1)
   }
  ...
}

fun onCorrect() {
   if (!wordList.isEmpty()) {
       _score.value = (score.value)?.plus(1)
   }
   ...
}
  1. word شی را به _word تغییر نام دهید و یک ویژگی پشتیبان برای آن اضافه کنید، همانطور که برای شی score انجام دادید.
// The current word
private val _word = MutableLiveData<String>()
val word: LiveData<String>
   get() = _word
...
init {
   _word.value = ""
   ...
}
...
private fun nextWord() {
   if (!wordList.isEmpty()) {
       //Select and remove a word from the list
       _word.value = wordList.removeAt(0)
   }
}

کار عالی، شما word و score اشیاء LiveData را کپسوله کرده اید.

وقتی کاربر روی دکمه پایان بازی ضربه می‌زند، برنامه فعلی شما به صفحه امتیاز حرکت می‌کند. همچنین می‌خواهید وقتی بازیکنان تمام کلمات را چرخانده باشند، برنامه به صفحه امتیاز حرکت کند. بعد از اینکه بازیکنان با کلمه آخر تمام شدند، می خواهید بازی به طور خودکار تمام شود تا کاربر مجبور نباشد روی دکمه ضربه بزند.

برای پیاده‌سازی این عملکرد، باید یک رویداد راه‌اندازی شود و زمانی که همه کلمات نشان داده شدند، از ViewModel به قطعه ارسال شود. برای انجام این کار، از الگوی مشاهده‌گر LiveData برای مدل‌سازی یک رویداد تمام‌شده بازی استفاده می‌کنید.

الگوی مشاهده گر

الگوی مشاهده گر یک الگوی طراحی نرم افزار است. این ارتباط بین اشیاء را مشخص می کند: یک قابل مشاهده («موضوع» مشاهده) و ناظران . قابل مشاهده شیئی است که ناظران را از تغییرات حالت خود آگاه می کند.

در مورد LiveData در این برنامه، قابل مشاهده (موضوع) شی LiveData است و مشاهده‌گرها روش‌هایی هستند که در کنترل‌کننده‌های UI، مانند قطعات، وجود دارد. هر زمان که داده های پیچیده شده در LiveData تغییر کنند، تغییر حالت اتفاق می افتد. کلاس های LiveData در برقراری ارتباط از ViewModel به قطعه بسیار مهم هستند.

مرحله 1: از LiveData برای شناسایی یک رویداد پایان یافته استفاده کنید

در این کار، شما از الگوی مشاهده‌گر LiveData برای مدل‌سازی یک رویداد تمام‌شده بازی استفاده می‌کنید.

  1. در GameViewModel ، یک شی Boolean MutableLiveData به نام _eventGameFinish کنید. این شی رویداد پایان بازی را برگزار می کند.
  2. پس از مقداردهی اولیه شی _eventGameFinish ، یک ویژگی پشتیبان به نام eventGameFinish ایجاد و مقداردهی اولیه کنید.
// Event which triggers the end of the game
private val _eventGameFinish = MutableLiveData<Boolean>()
val eventGameFinish: LiveData<Boolean>
   get() = _eventGameFinish
  1. در GameViewModel ، یک onGameFinish() اضافه کنید. در این روش، رویداد پایان بازی، eventGameFinish را روی true تنظیم کنید.
/** Method for the game completed event **/
fun onGameFinish() {
   _eventGameFinish.value = true
}
  1. در GameViewModel ، در داخل nextWord() ، اگر لیست کلمات خالی بود، بازی را تمام کنید.
private fun nextWord() {
   if (wordList.isEmpty()) {
       onGameFinish()
   } else {
       //Select and remove a _word from the list
       _word.value = wordList.removeAt(0)
   }
}
  1. در GameFragment ، داخل onCreateView() ، پس از مقداردهی اولیه viewModel ، یک مشاهدهگر را به eventGameFinish کنید. از متد observe() observer استفاده کنید. در داخل تابع لامبدا، gameFinished() را فراخوانی کنید.
// Observer for the Game finished event
viewModel.eventGameFinish.observe(this, Observer<Boolean> { hasFinished ->
   if (hasFinished) gameFinished()
})
  1. برنامه خود را اجرا کنید، بازی را انجام دهید و تمام کلمات را مرور کنید. برنامه به‌جای ماندن در بخش بازی تا زمانی که روی پایان بازی ضربه بزنید، به‌طور خودکار به صفحه امتیاز حرکت می‌کند.

    پس از خالی شدن فهرست کلمات، eventGameFinish تنظیم می‌شود، متد مشاهده‌گر مرتبط در قطعه بازی فراخوانی می‌شود و برنامه به قطعه صفحه هدایت می‌شود.
  2. کدی که اضافه کردید یک مشکل چرخه حیات ایجاد کرده است. برای درک موضوع، در کلاس GameFragment ، کد پیمایش را در gameFinished() . مطمئن شوید که پیام Toast را در روش نگه دارید.
private fun gameFinished() {
       Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
//        val action = GameFragmentDirections.actionGameToScore()
//        action.score = viewModel.score.value?:0
//        NavHostFragment.findNavController(this).navigate(action)
   }
  1. برنامه خود را اجرا کنید، بازی را انجام دهید و تمام کلمات را مرور کنید. یک پیام نان تست که می گوید "بازی به تازگی تمام شد" به طور خلاصه در پایین صفحه بازی ظاهر می شود که رفتار مورد انتظار است.

اکنون دستگاه یا شبیه ساز را بچرخانید. نان تست دوباره نمایش داده می شود! دستگاه را چند بار دیگر بچرخانید و احتمالاً هر بار نان تست را خواهید دید. این یک اشکال است، زیرا نان تست فقط یک بار، زمانی که بازی تمام شد، نمایش داده شود. نان تست نباید هر بار که قطعه دوباره ایجاد می شود نمایش داده شود. شما این مشکل را در کار بعدی حل می کنید.

مرحله 2: رویداد پایان بازی را بازنشانی کنید

معمولاً LiveData فقط زمانی که داده ها تغییر می کند به روز رسانی را به ناظران ارائه می دهد. یک استثنا در این رفتار این است که ناظران همچنین به‌روزرسانی‌هایی را دریافت می‌کنند که ناظر از حالت غیرفعال به حالت فعال تغییر کند.

به همین دلیل است که نان تست تمام شده بازی به طور مکرر در برنامه شما فعال می شود. وقتی قطعه بازی پس از چرخش صفحه دوباره ایجاد می شود، از حالت غیرفعال به حالت فعال می رود. مشاهده‌گر در قطعه مجدداً به ViewModel موجود متصل می‌شود و داده‌های جاری را دریافت می‌کند. gameFinished() دوباره راه اندازی می شود و نان تست نمایش داده می شود.

در این کار، با تنظیم مجدد پرچم eventGameFinish در GameViewModel ، این مشکل را برطرف کرده و نان تست را تنها یک بار نمایش می دهید.

  1. در GameViewModel ، یک onGameFinishComplete() برای بازنشانی رویداد پایان یافته بازی، _eventGameFinish کنید.
/** Method for the game completed event **/

fun onGameFinishComplete() {
   _eventGameFinish.value = false
}
  1. در GameFragment ، در انتهای gameFinished() onGameFinishComplete() را در شی viewModel کنید. (کد پیمایش را فعلاً در gameFinished() که نظر داده شده است بگذارید.)
private fun gameFinished() {
   ...
   viewModel.onGameFinishComplete()
}
  1. برنامه را اجرا کنید و بازی را انجام دهید. تمام کلمات را مرور کنید، سپس جهت صفحه نمایش دستگاه را تغییر دهید. نان تست فقط یک بار نمایش داده می شود.
  2. در GameFragment ، در داخل gameFinished() ، کد ناوبری را از کامنت بردارید.

    برای لغو نظر در اندروید استودیو، خطوطی را که نظر داده می‌شوند انتخاب کنید و Control+/ ( Command+/ در مک) را فشار دهید.
private fun gameFinished() {
   Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
   val action = GameFragmentDirections.actionGameToScore()
   action.score = viewModel.score.value?:0
   findNavController(this).navigate(action)
   viewModel.onGameFinishComplete()
}

اگر Android Studio از شما خواسته است، androidx.navigation.fragment.NavHostFragment.findNavController وارد کنید.

  1. برنامه را اجرا کنید و بازی را انجام دهید. مطمئن شوید که برنامه پس از مرور همه کلمات به طور خودکار به صفحه امتیاز نهایی هدایت می شود.

کارت عالی بود! برنامه شما از LiveData استفاده می کند تا یک رویداد تمام شده بازی را راه اندازی کند تا از GameViewModel به قطعه بازی که لیست کلمات خالی است، ارتباط برقرار کند. قطعه بازی سپس به قطعه امتیاز حرکت می کند.

در این کار، امتیاز را به یک شی LiveData در ScoreViewModel و یک مشاهده‌گر را به آن متصل می‌کنید. این کار شبیه کاری است که هنگام افزودن LiveData به GameViewModel انجام دادید.

شما این تغییرات را برای کامل شدن در ScoreViewModel انجام می دهید تا همه داده های برنامه شما از LiveData استفاده کنند.

  1. در ScoreViewModel ، نوع متغیر score را به MutableLiveData تغییر دهید. نام آن را طبق قرارداد به _score و یک ویژگی پشتیبان اضافه کنید.
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
   get() = _score
  1. در ScoreViewModel ، داخل بلوک init ، _score را مقداردهی اولیه کنید. شما می توانید گزارش را به دلخواه حذف یا در بلوک init بگذارید.
init {
   _score.value = finalScore
}
  1. در ScoreFragment ، در onCreateView() ، پس از مقداردهی اولیه viewModel ، یک ناظر برای شی امتیاز LiveData متصل کنید. در داخل عبارت لامبدا، مقدار امتیاز را روی نمای متنی امتیاز قرار دهید. کدی را که مستقیماً نمای متن را با مقدار امتیاز تخصیص می دهد از ViewModel حذف کنید.

کد برای افزودن:

// Add observer for score
viewModel.score.observe(this, Observer { newScore ->
   binding.scoreText.text = newScore.toString()
})

کد برای حذف:

binding.scoreText.text = viewModel.score.toString()

وقتی Android Studio از شما خواسته شد، androidx.lifecycle.Observer وارد کنید.

  1. برنامه خود را اجرا کنید و بازی را انجام دهید. برنامه باید مانند قبل کار کند، اما اکنون از LiveData و یک ناظر برای به روز رسانی امتیاز استفاده می کند.

در این کار، یک دکمه Play Again را به صفحه امتیاز اضافه می‌کنید و با استفاده از رویداد LiveData ، شنونده کلیک آن را پیاده‌سازی می‌کنید. این دکمه یک رویداد را برای حرکت از صفحه امتیاز به صفحه بازی راه اندازی می کند.

کد شروع برنامه شامل دکمه Play Again است، اما دکمه پنهان است.

  1. در res/layout/score_fragment.xml ، برای دکمه play_again_button ، مقدار ویژگی visibility را به visible تغییر دهید.
<Button
   android:id="@+id/play_again_button"
...
   android:visibility="visible"
 />
  1. در ScoreViewModel ، یک شی LiveData اضافه کنید تا یک Boolean به نام _eventPlayAgain دارد. این شیء برای ذخیره رویداد LiveData برای حرکت از صفحه امتیاز به صفحه بازی استفاده می شود.
private val _eventPlayAgain = MutableLiveData<Boolean>()
val eventPlayAgain: LiveData<Boolean>
   get() = _eventPlayAgain
  1. در ScoreViewModel ، روش هایی را برای تنظیم و بازنشانی رویداد تعریف کنید، _eventPlayAgain .
fun onPlayAgain() {
   _eventPlayAgain.value = true
}
fun onPlayAgainComplete() {
   _eventPlayAgain.value = false
}
  1. در ScoreFragment ، یک ناظر برای eventPlayAgain اضافه کنید. کد را در انتهای onCreateView() قبل از عبارت return قرار دهید. در داخل عبارت lambda، به صفحه بازی بازگردید و eventPlayAgain بازنشانی کنید.
// Navigates back to game when button is pressed
viewModel.eventPlayAgain.observe(this, Observer { playAgain ->
   if (playAgain) {
      findNavController().navigate(ScoreFragmentDirections.actionRestart())
       viewModel.onPlayAgainComplete()
   }
})

وقتی Android Studio از شما خواسته شد androidx.navigation.fragment.findNavController وارد کنید.

  1. در ScoreFragment ، داخل onCreateView() یک کلیک شنونده به دکمه PlayAgain اضافه کنید و viewModel .onPlayAgain() را فراخوانی کنید.
binding.playAgainButton.setOnClickListener {  viewModel.onPlayAgain()  }
  1. برنامه خود را اجرا کنید و بازی را انجام دهید. پس از پایان بازی، صفحه امتیاز، امتیاز نهایی و دکمه Play Again را نشان می دهد. روی دکمه PlayAgain ضربه بزنید و برنامه به صفحه بازی هدایت می شود تا بتوانید دوباره بازی را انجام دهید.

کار خوب! شما معماری برنامه خود را برای استفاده از اشیاء LiveData در ViewModel تغییر دادید و ناظران را به اشیاء LiveData متصل کردید. LiveData هنگامی که مقدار نگهداری شده توسط LiveData تغییر می کند، به اشیاء ناظر اطلاع می دهد.

پروژه اندروید استودیو: GuessTheWord

LiveData

  • LiveData یک کلاس دارنده داده قابل مشاهده است که از چرخه حیات آگاه است، یکی از اجزای معماری Android .
  • می‌توانید از LiveData برای فعال کردن رابط کاربری خود برای به‌روزرسانی خودکار هنگام به‌روزرسانی داده‌ها استفاده کنید.
  • LiveData قابل مشاهده است، به این معنی که یک ناظر مانند یک فعالیت یا یک قطعه می تواند هنگام تغییر داده های نگهداری شده توسط شی LiveData مطلع شود.
  • LiveData داده ها را نگه می دارد. این یک لفاف است که می تواند با هر داده ای استفاده شود.
  • LiveData از چرخه حیات آگاه است، به این معنی که فقط ناظرانی را که در یک وضعیت چرخه حیات فعال هستند مانند STARTED یا RESUMED به روز می کند.

برای افزودن LiveData

  • نوع متغیرهای داده در ViewModel را به LiveData یا MutableLiveData .

MutableLiveData یک شی LiveData است که مقدار آن قابل تغییر است. MutableLiveData یک کلاس عمومی است، بنابراین باید نوع داده ای که در آن نگهداری می شود را مشخص کنید.

  • برای تغییر مقدار داده های نگهداری شده توسط LiveData ، از متد setValue() در متغیر LiveData استفاده کنید.

برای کپسوله کردن LiveData

  • LiveData داخل ViewModel باید قابل ویرایش باشد. در خارج از ViewModel ، LiveData باید قابل خواندن باشد. این را می توان با استفاده از ویژگی پشتیبان Kotlin پیاده سازی کرد.
  • یک ویژگی پشتیبان Kotlin به شما امکان می دهد چیزی را از یک گیرنده غیر از شی دقیق برگردانید.
  • برای کپسوله کردن LiveData ، از MutableLiveData private در داخل ViewModel استفاده کنید و یک ویژگی پشتیبان LiveData را خارج از ViewModel .

LiveData قابل مشاهده

  • LiveData از یک الگوی ناظر پیروی می کند. «مشاهده‌پذیر» شی LiveData است و ناظرها روش‌هایی هستند که در کنترل‌کننده‌های UI، مانند قطعات، هستند. هر زمان که داده‌های پیچیده شده در LiveData تغییر کند، روش‌های مشاهده‌گر در کنترل‌کننده‌های UI مطلع می‌شوند.
  • برای اینکه LiveData قابل مشاهده باشد، با استفاده از متد Observer() یک شی مشاهده گر را به مرجع LiveData در مشاهدهگرها (مانند فعالیت ها و قطعات) متصل observe() .
  • این الگوی مشاهده LiveData می تواند برای برقراری ارتباط از ViewModel به کنترل کننده های UI استفاده شود.

دوره بی ادبی:

مستندات توسعه دهنده اندروید:

دیگر:

این بخش، تکالیف احتمالی را برای دانش‌آموزانی که در این آزمایشگاه کد به عنوان بخشی از دوره‌ای که توسط یک مربی هدایت می‌شود، فهرست می‌کند. این وظیفه مربی است که موارد زیر را انجام دهد:

  • در صورت نیاز تکالیف را تعیین کنید.
  • نحوه ارسال تکالیف را با دانش آموزان در میان بگذارید.
  • تکالیف را درجه بندی کنید.

مربیان می‌توانند از این پیشنهادات به اندازه‌ای که می‌خواهند استفاده کنند، و باید با خیال راحت هر تکلیف دیگری را که فکر می‌کنند مناسب است به آنها اختصاص دهند.

اگر به تنهایی بر روی این کدها کار می کنید، از این تکالیف برای آزمایش دانش خود استفاده کنید.

یه این سوالات پاسخ دهید

سوال 1

چگونه می توان LiveData ذخیره شده در ViewModel را کپسوله کرد تا اشیاء خارجی بتوانند داده ها را بدون امکان به روز رسانی بخوانند؟

  • در داخل شی ViewModel ، نوع داده داده ها را به private LiveData تغییر دهید. از یک ویژگی پشتیبان برای نمایش داده های فقط خواندنی از نوع MutableLiveData استفاده کنید.
  • در داخل شی ViewModel ، نوع داده داده ها را به MutableLiveData private تغییر دهید. از یک ویژگی پشتیبان برای نمایش داده های فقط خواندنی از نوع LiveData استفاده کنید.
  • در داخل کنترلر UI، نوع داده داده ها را به MutableLiveData private تغییر دهید. از یک ویژگی پشتیبان برای نمایش داده های فقط خواندنی از نوع LiveData استفاده کنید.
  • در داخل شی ViewModel ، نوع داده داده ها را به LiveData تغییر دهید. از یک ویژگی پشتیبان برای نمایش داده های فقط خواندنی از نوع LiveData استفاده کنید.

سوال 2

اگر کنترلر UI در کدام یک از حالت های زیر باشد، LiveData یک کنترلر UI (مانند یک قطعه) را به روز می کند؟

  • از سر گرفته شد
  • در پس زمینه
  • مکث شد
  • متوقف شد

سوال 3

در الگوی ناظر LiveData ، آیتم قابل مشاهده (آنچه مشاهده می شود) چیست؟

  • روش مشاهده گر
  • داده های موجود در یک شی LiveData
  • کنترلر رابط کاربری
  • شی ViewModel

درس بعدی را شروع کنید: 5.3: اتصال داده ها با ViewModel و LiveData

برای پیوند به دیگر کدهای این دوره، به صفحه فرود کد لبه‌های کد پایه Android Kotlin Fundamentals مراجعه کنید.