Bu codelab, Android Kotlin Hakkında Temel Bilgiler kursunun bir parçasıdır. Bu kurstan en iyi şekilde yararlanmak için codelab'leri sırayla tamamlamanızı öneririz. Kursla ilgili tüm codelab'ler Android Kotlin Hakkında Temel Bilgiler codelab'leri açılış sayfasında listelenir.
Başlık ekranı |
Oyun ekranı |
Puan ekranı |
Giriş
Bu codelab'de, Android Mimari Bileşenlerinden biri olan ViewModel hakkında bilgi edineceksiniz:
- Kullanıcı arayüzüyle ilgili verileri yaşam döngüsüne duyarlı bir şekilde depolamak ve yönetmek için
ViewModelsınıfını kullanırsınız.ViewModelsınıfı, ekran döndürme ve klavye kullanılabilirliğinde değişiklik gibi cihaz yapılandırması değişikliklerinde verilerin korunmasını sağlar. - Yapılandırma değişikliklerinden etkilenmeyen
ViewModelnesnesini oluşturup döndürmek içinViewModelFactorysınıfını kullanırsınız.
Bilmeniz gerekenler
- Kotlin'de temel Android uygulamaları oluşturma
- Uygulamanızda gezinmeyi uygulamak için gezinme grafiğini kullanma
- Uygulamanızın hedefleri arasında gezinmek ve gezinme hedefleri arasında veri aktarmak için kod ekleme
- Etkinlik ve parça yaşam döngülerinin işleyiş şekli.
- Bir uygulamaya günlük kaydı bilgilerini ekleme ve Android Studio'da Logcat'i kullanarak günlükleri okuma
Neler öğreneceksiniz?
- Önerilen Android uygulama mimarisini kullanma
- Uygulamanızda
Lifecycle,ViewModelveViewModelFactorysınıflarını kullanma - Cihaz yapılandırması değişiklikleri sırasında kullanıcı arayüzü verilerini koruma
- Fabrika yöntemi tasarım kalıbının ne olduğu ve nasıl kullanılacağı.
- Arayüzü kullanarak
ViewModelnesnesi oluşturmaViewModelProvider.Factory
Yapacaklarınız
- Uygulamanın verilerini kaydetmek için uygulamaya
ViewModelekleyin. Böylece veriler, yapılandırma değişikliklerinden etkilenmez. - Oluşturucu parametreleriyle bir
ViewModelnesnesi oluşturmak içinViewModelFactoryve fabrika yöntemi tasarım kalıbını kullanın.
5. dersteki codelab'lerde, başlangıç koduyla başlayarak GuessTheWord uygulamasını geliştirirsiniz. GuessTheWord, iki oyuncunun mümkün olan en yüksek puanı elde etmek için işbirliği yaptığı, sessiz sinema tarzı bir oyundur.
Birinci oyuncu, uygulamadaki kelimelere bakar ve her birini sırayla canlandırır. Kelimeyi ikinci oyuncuya göstermemeye dikkat eder. İkinci oyuncu kelimeyi tahmin etmeye çalışır.
Oyunu oynamak için ilk oyuncu cihazda uygulamayı açar ve aşağıdaki ekran görüntüsünde gösterildiği gibi bir kelime (ör. "gitar") görür.
İlk oyuncu, kelimeyi söylememeye dikkat ederek kelimeyi canlandırır.
- İkinci oyuncu kelimeyi doğru tahmin ettiğinde birinci oyuncu Bildim düğmesine basar. Bu işlem, sayıyı bir artırır ve sonraki kelimeyi gösterir.
- İkinci oyuncu kelimeyi tahmin edemezse birinci oyuncu Atla düğmesine basar. Bu durumda sayı bir azalır ve bir sonraki kelimeye geçilir.
- Oyunu sonlandırmak için End Game (Oyunu Sonlandır) düğmesine basın. (Bu işlev, serideki ilk codelab'in başlangıç kodunda yer almaz.)
Bu görevde, başlangıç uygulamasını indirip çalıştıracak ve kodu inceleyeceksiniz.
1. adım: Başlayın
- GuessTheWord başlangıç kodunu indirin ve projeyi Android Studio'da açın.
- Uygulamayı Android destekli bir cihazda veya emülatörde çalıştırın.
- Düğmelere dokunun. Atla düğmesinin sonraki kelimeyi gösterdiğini ve puanı bir azalttığını, Anladım düğmesinin ise sonraki kelimeyi gösterdiğini ve puanı bir artırdığını unutmayın. Oyunu Bitir düğmesi uygulanmadığından bu düğmeye dokunduğunuzda herhangi bir işlem yapılmaz.
2. adım: Kod incelemesi yapın
- Uygulamanın nasıl çalıştığını anlamak için Android Studio'da kodu inceleyin.
- Özellikle önemli olan aşağıdaki dosyalara göz atmayı unutmayın.
MainActivity.kt
Bu dosya yalnızca varsayılan, şablonla oluşturulmuş kodu içeriyor.
res/layout/main_activity.xml
Bu dosya, uygulamanın ana düzenini içerir. Kullanıcı uygulamada gezinirken NavHostFragment diğer parçaları barındırır.
Kullanıcı arayüzü parçaları
Başlangıç kodunda, com.example.android.guesstheword.screens paketi altında üç farklı pakette üç parça bulunur:
- Başlık ekranı için
title/TitleFragment - Oyun ekranı için
game/GameFragment - Skor ekranı için
score/ScoreFragment
screens/title/TitleFragment.kt
Başlık parçası, uygulama başlatıldığında görüntülenen ilk ekrandır. Oyun ekranına gitmek için Oyna düğmesine bir tıklama işleyicisi ayarlanır.
screens/game/GameFragment.kt
Bu, oyunun büyük bir bölümünün geçtiği ana parçadır:
- Değişkenler, mevcut kelime ve mevcut puan için tanımlanır.
resetList()yöntemi içinde tanımlananwordList, oyunda kullanılacak kelimelerin örnek listesidir.onSkip()yöntemi, Atla düğmesinin tıklama işleyicisidir. Puanı 1 azaltır venextWord()yöntemini kullanarak sonraki kelimeyi gösterir.onCorrect()yöntemi, Anladım düğmesinin tıklama işleyicisidir. Bu yöntem,onSkip()yöntemine benzer şekilde uygulanır. Tek fark, bu yöntemin puanı azaltmak yerine 1 puan artırmasıdır.
screens/score/ScoreFragment.kt
ScoreFragment, oyundaki son ekrandır ve oyuncunun nihai puanını gösterir. Bu codelab'de, bu ekranı görüntülemek ve nihai puanı göstermek için uygulama ekleyeceksiniz.
res/navigation/main_navigation.xml
Gezinme grafiği, parçaların gezinme yoluyla nasıl bağlandığını gösterir:
- Kullanıcı, başlık parçasından oyun parçasına gidebilir.
- Kullanıcı, oyun fragmentinden skor fragmentine gidebilir.
- Kullanıcı, skor fragmentinden oyun fragmentine geri dönebilir.
Bu görevde, GuessTheWord başlangıç uygulamasındaki sorunları bulursunuz.
- Başlangıç kodunu çalıştırın ve oyunu birkaç kelime boyunca oynayın. Her kelimeden sonra Atla veya Anladım'a dokunun.
- Oyun ekranında artık bir kelime ve mevcut skor gösteriliyor. Cihazı veya emülatörü döndürerek ekran yönünü değiştirin. Mevcut puanın kaybolduğunu unutmayın.
- Oyunu birkaç kelime daha kullanarak açıklayın. Oyun ekranı bir skorla gösterildiğinde uygulamayı kapatıp yeniden açın. Uygulama durumu kaydedilmediği için oyunun baştan başladığını fark edeceksiniz.
- Oyunu birkaç kelimeyle oynayın, ardından Oyunu Bitir düğmesine dokunun. Hiçbir şey olmadığını fark edeceksiniz.
Uygulamadaki sorunlar:
- Başlangıç uygulaması, yapılandırma değişiklikleri sırasında (ör. cihaz yönü değiştiğinde veya uygulama kapatılıp yeniden başlatıldığında) uygulama durumunu kaydetmez ve geri yüklemez.
Bu sorunuonSaveInstanceState()geri çağırmasını kullanarak çözebilirsiniz. AncakonSaveInstanceState()yöntemini kullanmak için durumu bir pakette kaydetmek ve bu durumu almak üzere mantığı uygulamak için ek kod yazmanız gerekir. Ayrıca, depolanabilecek veri miktarı da minimum düzeydedir. - Kullanıcı Oyunu Bitir düğmesine dokunduğunda oyun ekranı, skor ekranına gitmiyor.
Bu sorunları, bu codelab'de öğrendiğiniz uygulama mimarisi bileşenlerini kullanarak çözebilirsiniz.
Uygulama mimarisi
Uygulama mimarisi, uygulamalarınızın sınıflarını ve aralarındaki ilişkileri, kodun düzenli olması, belirli senaryolarda iyi performans göstermesi ve kolayca kullanılabilmesi için tasarlama yöntemidir. Bu dört codelab'den oluşan seride, GuessTheWord uygulamasında yaptığınız iyileştirmeler Android uygulama mimarisi yönergelerine uygun olur ve Android Architecture Components'ı kullanırsınız. Android uygulama mimarisi, MVVM (model-view-viewmodel) mimari desenine benzer.
GuessTheWord uygulaması, ilgi alanlarının ayrılması tasarım ilkesine uyar ve sınıflara ayrılır. Her sınıf ayrı bir ilgi alanını ele alır. Dersin bu ilk codelab'inde, çalıştığınız sınıflar bir kullanıcı arayüzü denetleyicisi, bir ViewModel ve bir ViewModelFactory'dir.
Kullanıcı arayüzü denetleyicisi
Kullanıcı arayüzü denetleyicisi, Activity veya Fragment gibi kullanıcı arayüzü tabanlı bir sınıftır. Bir kullanıcı arayüzü denetleyicisi yalnızca görünümleri görüntüleme ve kullanıcı girişini yakalama gibi kullanıcı arayüzü ve işletim sistemi etkileşimlerini işleyen mantığı içermelidir. Gösterilecek metni belirleyen mantık gibi karar verme mantığını kullanıcı arayüzü denetleyicisine yerleştirmeyin.
GuessTheWord başlangıç kodunda, kullanıcı arayüzü denetleyicileri üç parçadır: GameFragment, ScoreFragment, ve TitleFragment. "İlgi alanlarının ayrılması" tasarım ilkesine göre GameFragment yalnızca oyun öğelerini ekrana çizmekten ve kullanıcının düğmelere ne zaman dokunduğunu bilmekten sorumludur. Kullanıcı bir düğmeye dokunduğunda bu bilgiler GameViewModel'ya iletilir.
ViewModel
Bir ViewModel, ViewModel ile ilişkili bir parçada veya etkinlikte gösterilecek verileri tutar. Bir ViewModel, verilerin kullanıcı arayüzü denetleyicisi tarafından görüntülenmeye hazırlanması için veriler üzerinde basit hesaplamalar ve dönüşümler yapabilir. Bu mimaride ViewModel karar verme işlemini gerçekleştirir.GameViewModel, ekranda gösterilecek veriler olduğu için puan değeri, kelime listesi ve mevcut kelime gibi verileri tutar. GameViewModel, verilerin mevcut durumuna karar vermek için basit hesaplamalar yapmaya yönelik iş mantığını da içerir.
ViewModelFactory
ViewModelFactory, oluşturucu parametreleriyle veya parametreler olmadan ViewModel nesnelerini oluşturur.

Sonraki codelab'lerde, kullanıcı arayüzü denetleyicileri ve ViewModel ile ilgili diğer Android Architecture Components hakkında bilgi edineceksiniz.
ViewModel sınıfı, kullanıcı arayüzüyle ilgili verileri depolamak ve yönetmek için tasarlanmıştır. Bu uygulamada her ViewModel bir parçayla ilişkilendirilir.
Bu görevde, uygulamanıza ilk ViewModel öğenizi (GameFragment için GameViewModel) eklersiniz. Ayrıca ViewModel simgesinin yaşam döngüsüne duyarlı olmasının ne anlama geldiğini de öğrenirsiniz.
1. adım: GameViewModel sınıfını ekleyin
build.gradle(module:app)dosyasını açın.dependenciesbloğunun içineViewModeliçin Gradle bağımlılığını ekleyin.
Kitaplığın en son sürümünü kullanırsanız çözüm uygulaması beklendiği gibi derlenir. Çalışmıyorsa sorunu çözmeyi deneyin veya aşağıda gösterilen sürüme geri dönün.
//ViewModel
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'screens/game/paket klasöründeGameViewModeladlı yeni bir Kotlin sınıfı oluşturun.GameViewModelsınıfınınViewModelsoyut sınıfını genişletmesini sağlayın.ViewModel'ın yaşam döngüsüne nasıl duyarlı olduğunu daha iyi anlamanıza yardımcı olmak içinlogifadesi içeren birinitbloğu ekleyin.
class GameViewModel : ViewModel() {
init {
Log.i("GameViewModel", "GameViewModel created!")
}
}2. adım: onCleared() işlevini geçersiz kılın ve günlük kaydı ekleyin
İlişkili parça ayrıldığında veya etkinlik tamamlandığında ViewModel yok edilir. ViewModel yok edilmeden hemen önce kaynakları temizlemek için onCleared() geri çağırma işlevi çağrılır.
GameViewModelsınıfındaonCleared()yöntemini geçersiz kılın.onCleared()içine bir günlük ifadesi ekleyerekGameViewModelyaşam döngüsünü izleyin.
override fun onCleared() {
super.onCleared()
Log.i("GameViewModel", "GameViewModel destroyed!")
}3. adım: GameViewModel'ı oyun parçasıyla ilişkilendirin
Bir ViewModel, kullanıcı arayüzü denetleyicisiyle ilişkilendirilmelidir. İkisini ilişkilendirmek için kullanıcı arayüzü denetleyicisinde ViewModel öğesine bir referans oluşturursunuz.
Bu adımda, ilgili kullanıcı arayüzü denetleyicisi olan GameFragment içinde GameViewModel öğesinin referansını oluşturursunuz.
GameFragmentsınıfında, üst düzeyde sınıf değişkeni olarakGameViewModeltüründe bir alan ekleyin.
private lateinit var viewModel: GameViewModel4. adım: ViewModel'i başlatın
Ekran döndürme gibi yapılandırma değişiklikleri sırasında parçalar gibi kullanıcı arayüzü denetleyicileri yeniden oluşturulur. Ancak ViewModel örnekleri kalır. ViewModel sınıfını kullanarak ViewModel örneğini oluşturursanız parça her yeniden oluşturulduğunda yeni bir nesne oluşturulur. Bunun yerine, ViewModelProvider kullanarak ViewModel örneğini oluşturun.

ViewModelProvider nasıl çalışır?
ViewModelProvider, mevcut birViewModelvarsa onu döndürür, yoksa yeni birViewModeloluşturur.ViewModelProvider, verilen kapsamla (bir etkinlik veya bir parça) ilişkili birViewModelörneği oluşturur.- Oluşturulan
ViewModel, kapsam geçerli olduğu sürece saklanır. Örneğin, kapsam bir parçaysaViewModel, parça ayrılana kadar korunur.
ViewModel öğesini başlatın. ViewModelProviders.of() yöntemini kullanarak ViewModelProvider oluşturun:
GameFragmentsınıfındaviewModeldeğişkenini başlatın. Bu koduonCreateView()içine, bağlama değişkeninin tanımından sonra yerleştirin.ViewModelProviders.of()yöntemini kullanın ve ilişkiliGameFragmentbağlamını veGameViewModelsınıfını iletin.ViewModelnesnesinin başlatılmasının üstüne,ViewModelProviders.of()yöntem çağrısını günlüğe kaydetmek için bir günlük ifadesi ekleyin.
Log.i("GameFragment", "Called ViewModelProviders.of")
viewModel = ViewModelProviders.of(this).get(GameViewModel::class.java)- Uygulamayı çalıştırın. Android Studio'da Logcat bölmesini açın ve
Gameile filtreleyin. Cihazınızda veya emülatörünüzde Oynat düğmesine dokunun. Oyun ekranı açılır.
Logcat'te gösterildiği gibi,GameFragmentöğesininonCreateView()yöntemi,GameViewModelöğesini oluşturmak içinViewModelProviders.of()yöntemini çağırır.GameFragmentveGameViewModelöğesine eklediğiniz günlük kaydı ifadeleri Logcat'te gösterilir.

- Cihazınızda veya emülatörünüzde otomatik döndürme ayarını etkinleştirin ve ekran yönünü birkaç kez değiştirin.
GameFragmenther seferinde yok edilip yeniden oluşturulduğundanViewModelProviders.of()her seferinde çağrılır. AncakGameViewModelyalnızca bir kez oluşturulur ve her çağrı için yeniden oluşturulmaz veya yok edilmez.
I/GameFragment: Called ViewModelProviders.of I/GameViewModel: GameViewModel created! I/GameFragment: Called ViewModelProviders.of I/GameFragment: Called ViewModelProviders.of I/GameFragment: Called ViewModelProviders.of
- Oyundan çıkın veya oyun parçasından çıkın.
GameFragmentyok edildi. İlişkiliGameViewModelde yok edilir ve geri çağırmaonCleared()çağrılır.
I/GameFragment: Called ViewModelProviders.of I/GameViewModel: GameViewModel created! I/GameFragment: Called ViewModelProviders.of I/GameFragment: Called ViewModelProviders.of I/GameFragment: Called ViewModelProviders.of I/GameViewModel: GameViewModel destroyed!
ViewModel, yapılandırma değişikliklerinden etkilenmez. Bu nedenle, yapılandırma değişikliklerinden etkilenmemesi gereken veriler için iyi bir yerdir:
- Ekranda gösterilecek verileri ve bu verileri işleyecek kodu
ViewModeliçine yerleştirin. - Etkinlikler, parçalar ve görünümler yapılandırma değişikliklerinden etkilenmediği için
ViewModelhiçbir zaman parçalara, etkinliklere veya görünümlere referans içermemelidir.

Karşılaştırma için, GameFragment kullanıcı arayüzü verilerinin ViewModel eklenmeden önce ve eklendikten sonra başlangıç uygulamasında nasıl işlendiği aşağıda açıklanmıştır:ViewModel
ViewModeleklemeden önce:
Uygulamanın ekran döndürme gibi bir yapılandırma değişikliği geçirdiği sırada oyun parçası yok edilir ve yeniden oluşturulur. Veriler kaybolur.ViewModelekleyip oyun fragmentinin kullanıcı arayüzü verileriniViewModeliçine taşıdıktan sonra:
Fragmentin göstermesi gereken tüm veriler artıkViewModel. Uygulama yapılandırma değişikliği geçirdiğindeViewModelkorunur ve veriler saklanır.

Bu görevde, uygulamanın kullanıcı arayüzü verilerini, verileri işleme yöntemleriyle birlikte GameViewModel sınıfına taşırsınız. Bunu, yapılandırma değişiklikleri sırasında verilerin saklanması için yaparsınız.
1. adım: Veri alanlarını ve veri işlemeyi ViewModel'e taşıyın
Aşağıdaki veri alanlarını ve yöntemlerini GameFragment konumundan GameViewModel konumuna taşıyın:
word,scorevewordListveri alanlarını taşıyın.wordvescoreöğelerininprivateolmadığından emin olun.
Görünümlere referans içerdiğinden bağlama değişkeniGameFragmentBindingtaşınmamalıdır. Bu değişken, düzeni genişletmek, tıklama dinleyicilerini ayarlamak ve verileri ekranda göstermek için kullanılır. Bunlar, parçanın sorumluluklarıdır.resetList()venextWord()yöntemlerini taşıyın. Bu yöntemler, ekranda hangi kelimenin gösterileceğine karar verir.onCreateView()yönteminin içinden, yöntem çağrılarınıresetList()venextWord()ileGameViewModel'ininitbloğuna taşıyın.
Bu yöntemlerinitbloğunda olmalıdır. Bunun nedeni,ViewModeloluşturulduğunda kelime listesini sıfırlamanız gerektiğidir. Parça her oluşturulduğunda sıfırlamanız gerekmez. Günlük ifadesiniGameFragmentöğesinininitbloğunda silebilirsiniz.
GameFragment içindeki onSkip() ve onCorrect() tıklama işleyicileri, verileri işleme ve kullanıcı arayüzünü güncelleme kodunu içerir. Kullanıcı arayüzünü güncelleme kodu parçada kalmalı ancak verileri işleme kodu ViewModel taşınmalıdır.
Şimdilik, her iki yere de aynı yöntemleri yerleştirin:
onSkip()veonCorrect()yöntemleriniGameFragment'denGameViewModel'ye kopyalayın.GameViewModeliçinde,onSkip()veonCorrect()yöntemlerininprivateolmadığından emin olun. Çünkü bu yöntemlere parçadan referans vereceksiniz.
Yeniden düzenlemeden sonra GameViewModel sınıfının kodu:
class GameViewModel : ViewModel() {
// The current word
var word = ""
// The current score
var score = 0
// The list of words - the front of the list is the next word to guess
private lateinit var wordList: MutableList<String>
/**
* Resets the list of words and randomizes the order
*/
private fun resetList() {
wordList = mutableListOf(
"queen",
"hospital",
"basketball",
"cat",
"change",
"snail",
"soup",
"calendar",
"sad",
"desk",
"guitar",
"home",
"railway",
"zebra",
"jelly",
"car",
"crow",
"trade",
"bag",
"roll",
"bubble"
)
wordList.shuffle()
}
init {
resetList()
nextWord()
Log.i("GameViewModel", "GameViewModel created!")
}
/**
* Moves to the next word in the list
*/
private fun nextWord() {
if (!wordList.isEmpty()) {
//Select and remove a word from the list
word = wordList.removeAt(0)
}
updateWordText()
updateScoreText()
}
/** Methods for buttons presses **/
fun onSkip() {
if (!wordList.isEmpty()) {
score--
}
nextWord()
}
fun onCorrect() {
if (!wordList.isEmpty()) {
score++
}
nextWord()
}
override fun onCleared() {
super.onCleared()
Log.i("GameViewModel", "GameViewModel destroyed!")
}
}Aşağıda, yeniden düzenlemeden sonraki GameFragment sınıfının kodu verilmiştir:
/**
* Fragment where the game is played
*/
class GameFragment : Fragment() {
private lateinit var binding: GameFragmentBinding
private lateinit var viewModel: GameViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate view and obtain an instance of the binding class
binding = DataBindingUtil.inflate(
inflater,
R.layout.game_fragment,
container,
false
)
Log.i("GameFragment", "Called ViewModelProviders.of")
viewModel = ViewModelProviders.of(this).get(GameViewModel::class.java)
binding.correctButton.setOnClickListener { onCorrect() }
binding.skipButton.setOnClickListener { onSkip() }
updateScoreText()
updateWordText()
return binding.root
}
/** Methods for button click handlers **/
private fun onSkip() {
if (!wordList.isEmpty()) {
score--
}
nextWord()
}
private fun onCorrect() {
if (!wordList.isEmpty()) {
score++
}
nextWord()
}
/** Methods for updating the UI **/
private fun updateWordText() {
binding.wordText.text = word
}
private fun updateScoreText() {
binding.scoreText.text = score.toString()
}
}2. adım: GameFragment'teki tıklama işleyicileri ve veri alanlarıyla ilgili referansları güncelleyin
GameFragmentbölümündeonSkip()veonCorrect()yöntemlerini güncelleyin. Puanı güncellemek için kodu kaldırın ve bunun yerineviewModelüzerinde ilgilionSkip()veonCorrect()yöntemlerini çağırın.nextWord()yönteminiViewModel'ye taşıdığınız için oyun parçası artık bu yönteme erişemiyor.
GameFragment'dekionSkip()veonCorrect()yöntemlerindenextWord()çağrısınıupdateScoreText()veupdateWordText()ile değiştirin. Bu yöntemler, verileri ekranda gösterir.
private fun onSkip() {
viewModel.onSkip()
updateWordText()
updateScoreText()
}
private fun onCorrect() {
viewModel.onCorrect()
updateScoreText()
updateWordText()
}GameFragmentiçinde,scoreveworddeğişkenleriniGameViewModeldeğişkenlerini kullanacak şekilde güncelleyin. Çünkü bu değişkenler artıkGameViewModeliçinde yer alıyor.
private fun updateWordText() {
binding.wordText.text = viewModel.word
}
private fun updateScoreText() {
binding.scoreText.text = viewModel.score.toString()
}GameViewModeliçinde,nextWord()yöntemindeupdateWordText()veupdateScoreText()yöntemlerine yapılan çağrıları kaldırın. Bu yöntemler artıkGameFragmentüzerinden çağrılıyor.- Uygulamayı oluşturun ve hata olmadığından emin olun. Hata varsa projeyi temizleyip yeniden oluşturun.
- Uygulamayı çalıştırın ve oyunu bazı kelimelerle oynayın. Oyun ekranındayken cihazı döndürün. Yön değişikliğinden sonra mevcut puanın ve mevcut kelimenin korunduğuna dikkat edin.
Tebrikler! Artık uygulamanızın tüm verileri ViewModel içinde depolandığı için yapılandırma değişiklikleri sırasında korunur.
Bu görevde, End Game (Oyunu Bitir) düğmesi için tıklama işleyiciyi uygulayacaksınız.
GameFragmentiçindeonEndGame()adlı bir yöntem ekleyin. Kullanıcı Oyunu Bitir düğmesine dokunduğundaonEndGame()yöntemi çağrılır.
private fun onEndGame() {
}GameFragmentiçinde,onCreateView()yönteminde Anladım ve Atla düğmeleri için tıklama dinleyicilerini ayarlayan kodu bulun. Bu iki satırın hemen altında, End Game (Oyunu Bitir) düğmesi için bir tıklama işleyicisi ayarlayın. Bağlama değişkenini (binding) kullanın. Tıklama işleyicisinin içindeonEndGame()yöntemini çağırın.
binding.endGameButton.setOnClickListener { onEndGame() }GameFragmentiçinde, uygulamada puan ekranına gitmek içingameFinished()adlı bir yöntem ekleyin. Safe Args'ı kullanarak puanı bağımsız değişken olarak iletin.
/**
* Called when the game is finished
*/
private fun gameFinished() {
Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
val action = GameFragmentDirections.actionGameToScore()
action.score = viewModel.score
NavHostFragment.findNavController(this).navigate(action)
}onEndGame()yöntemindegameFinished()yöntemini çağırın.
private fun onEndGame() {
gameFinished()
}- Uygulamayı çalıştırın, oyunu oynayın ve bazı kelimeler arasında geçiş yapın. Oyunu Bitir düğmesine dokunun. Uygulamanın puan ekranına gittiğini ancak nihai puanın gösterilmediğini fark edin. Bunu bir sonraki görevde düzelteceksiniz.
|
|
Kullanıcı oyunu bitirdiğinde ScoreFragment puanı göstermez. ScoreFragment tarafından gösterilecek puanı tutacak bir ViewModel istiyorsunuz. Fabrika yöntemi kalıbını kullanarak ViewModel başlatma sırasında puan değerini iletirsiniz.
Fabrika yöntemi deseni, nesne oluşturmak için fabrika yöntemlerini kullanan bir yapısal tasarım desenidir. Fabrika yöntemi, aynı sınıfın bir örneğini döndüren bir yöntemdir.
Bu görevde, puan parçası için parametreli bir oluşturucu ve ViewModel öğesini oluşturmak için bir fabrika yöntemi içeren bir ViewModel oluşturacaksınız.
scorepaketi altındaScoreViewModeladlı yeni bir Kotlin sınıfı oluşturun. Bu sınıf, puan fragment'ı içinViewModelolacak.ScoreViewModelsınıfınıViewModel.sınıfından genişletin. Son puan için bir oluşturucu parametresi ekleyin. Günlük ifadesi içeren birinitbloğu ekleyin.ScoreViewModelsınıfına, son puanı kaydetmek içinscoreadlı bir değişken ekleyin.
class ScoreViewModel(finalScore: Int) : ViewModel() {
// The final score
var score = finalScore
init {
Log.i("ScoreViewModel", "Final score is $finalScore")
}
}scorepaketi altındaScoreViewModelFactoryadlı başka bir Kotlin sınıfı oluşturun. Bu sınıf,ScoreViewModelnesnesinin oluşturulmasından sorumludur.ScoreViewModelFactorydersiniViewModelProvider.Factorytarihinden itibaren uzatın. Nihai skor için bir oluşturucu parametresi ekleyin.
class ScoreViewModelFactory(private val finalScore: Int) : ViewModelProvider.Factory {
}ScoreViewModelFactoryiçinde Android Studio, uygulanmamış bir soyut üye hakkında hata gösteriyor. Hatayı düzeltmek içincreate()yöntemini geçersiz kılın.create()yönteminde, yeni oluşturulanScoreViewModelnesnesini döndürün.
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(ScoreViewModel::class.java)) {
return ScoreViewModel(finalScore) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}ScoreFragmentiçindeScoreViewModelveScoreViewModelFactoryiçin sınıf değişkenleri oluşturun.
private lateinit var viewModel: ScoreViewModel
private lateinit var viewModelFactory: ScoreViewModelFactoryScoreFragmentiçinde,onCreateView()içinde,bindingdeğişkenini başlatma işleminden sonraviewModelFactorydeğişkenini başlatın.ScoreViewModelFactorykullanın. Nihai puanı, bağımsız değişken paketindenScoreViewModelFactory()için oluşturucu parametresi olarak iletin.
viewModelFactory = ScoreViewModelFactory(ScoreFragmentArgs.fromBundle(arguments!!).score)onCreateView(içinde,viewModelFactorybaşlatıldıktan sonraviewModelnesnesini başlatın.ViewModelProviders.of()yöntemini çağırın, ilişkili puan parçası bağlamını veviewModelFactoryöğesini iletin. Bu işlem,viewModelFactorysınıfında tanımlanan fabrika yöntemi kullanılarakScoreViewModelnesnesini oluşturur..
viewModel = ViewModelProviders.of(this, viewModelFactory)
.get(ScoreViewModel::class.java)onCreateView()yönteminde,viewModelbaşlatıldıktan sonrascoreTextgörünümünün metniniScoreViewModeliçinde tanımlanan nihai puana ayarlayın.
binding.scoreText.text = viewModel.score.toString()- Uygulamanızı çalıştırın ve oyunu oynayın. Kelimelerin bir kısmını veya tamamını inceleyip Oyunu Bitir'e dokunun. Puan snippet'inde artık nihai puanın gösterildiğini fark edeceksiniz.

- İsteğe bağlı:
ScoreViewModelüzerinde filtreleme yaparak Logcat'tekiScoreViewModelgünlüklerini kontrol edin. Puan değeri gösterilmelidir.
2019-02-07 10:50:18.328 com.example.android.guesstheword I/ScoreViewModel: Final score is 15
Bu görevde, ViewModel kullanmak için ScoreFragment uyguladınız. Ayrıca, ViewModelFactory arayüzünü kullanarak ViewModel için parametreli bir oluşturucu oluşturmayı da öğrendiniz.
Tebrikler! Uygulamanızın mimarisini, Android Architecture Components'tan birini kullanacak şekilde değiştirdiniz, ViewModel. Uygulamanın yaşam döngüsü sorununu çözdünüz ve artık oyunun verileri yapılandırma değişikliklerinden etkilenmiyor. Ayrıca, ViewModelFactory arayüzünü kullanarak ViewModel oluşturmak için parametreli bir oluşturucu oluşturmayı da öğrendiniz.
Android Studio projesi: GuessTheWord
- Android uygulama mimarisi yönergelerinde, farklı sorumluluklara sahip sınıfların ayrılması önerilir.
- Kullanıcı arayüzü denetleyicisi,
ActivityveyaFragmentgibi kullanıcı arayüzü tabanlı bir sınıftır. Kullanıcı arayüzü denetleyicileri yalnızca kullanıcı arayüzü ve işletim sistemi etkileşimlerini işleyen mantığı içermeli, kullanıcı arayüzünde gösterilecek verileri içermemelidir. Bu verileriViewModeliçine yerleştirin. ViewModelsınıfı, kullanıcı arayüzüyle ilgili verileri depolar ve yönetir.ViewModelsınıfı, verilerin ekran döndürme gibi yapılandırma değişikliklerinden etkilenmemesini sağlar.ViewModel, önerilen Android Mimari Bileşenleri'nden biridir.ViewModelProvider.Factory,ViewModelnesnesi oluşturmak için kullanabileceğiniz bir arayüzdür.
Aşağıdaki tabloda, kullanıcı arayüzü denetleyicileri ile bunlar için veri tutan ViewModel örnekleri karşılaştırılmaktadır:
Kullanıcı arayüzü denetleyicisi | ViewModel |
Bu codelab'de oluşturduğunuz |
|
Kullanıcı arayüzünde gösterilecek veri içermiyor. | Kullanıcı arayüzü denetleyicisinin kullanıcı arayüzünde gösterdiği verileri içerir. |
Verileri görüntüleme kodu ve tıklama dinleyicileri gibi kullanıcı etkinliği kodu içerir. | Veri işleme için kod içerir. |
Her yapılandırma değişikliği sırasında yok edilir ve yeniden oluşturulur. | Yalnızca ilişkili kullanıcı arayüzü denetleyicisi kalıcı olarak kaldırıldığında (ör. bir etkinlik için etkinlik tamamlandığında veya bir parça için parça ayrıldığında) yok edilir. |
Görünümler içerir. | Yapılandırma değişikliklerinden sonra etkinlikler, parçalar veya görünümler korunmaz ancak |
İlişkili | İlişkili kullanıcı arayüzü denetleyicisine herhangi bir referans içermez. |
Udacity kursu:
Android geliştirici belgeleri:
- ViewModel'e Genel Bakış
- Yaşam Döngüsüne Duyarlı Bileşenlerle Yaşam Döngülerini İşleme
- Uygulama mimarisi kılavuzu
ViewModelProviderViewModelProvider.Factory
Diğer:
- MVVM (model-view-viewmodel) mimari kalıbı.
- İlgi alanlarının ayrılması (SoC) tasarım ilkesi
- Fabrika yöntemi kalıbı
Bu bölümde, bir eğitmenin yönettiği kurs kapsamında bu codelab'i tamamlayan öğrenciler için olası ödevler listelenmektedir. Eğitmen, aşağıdakileri yapmalıdır:
- Gerekirse ödev atayın.
- Öğrencilere ev ödevi ödevlerini nasıl göndereceklerini bildirin.
- Ödevlere not verin.
Eğitmenler bu önerileri istedikleri kadar kullanabilir ve uygun olduğunu düşündükleri diğer ödevleri verebilirler.
Bu codelab'i kendi başınıza tamamlıyorsanız bilginizi test etmek için bu ödevleri kullanabilirsiniz.
Bu soruları yanıtlayın
1. Soru
Cihaz yapılandırması değişikliği sırasında veri kaybını önlemek için uygulama verilerini hangi sınıfa kaydetmelisiniz?
ViewModelLiveDataFragmentActivity
2. Soru
Bir ViewModel hiçbir zaman parçalara, etkinliklere veya görünümlere referans içermemelidir. Doğru mu yanlış mı?
- Doğru
- Yanlış
3. Soru
ViewModel ne zaman yok edilir?
- İlişkili kullanıcı arayüzü denetleyicisi, cihaz yönü değişikliği sırasında yok edilip yeniden oluşturulduğunda.
- Yön değişikliğinde
- İlişkili kullanıcı arayüzü denetleyicisi tamamlandığında (etkinlikse) veya ayrıldığında (parçaysa).
- Kullanıcı Geri düğmesine bastığında.
4. Soru
ViewModelFactory arayüzü ne için kullanılır?
ViewModelnesnesi oluşturma.- Yön değişiklikleri sırasında verileri koruma.
- Ekranda gösterilen veriler yenilenir.
- Uygulama verileri değiştirildiğinde bildirim alma
Sonraki derse başlayın:
Bu kurstaki diğer codelab'lerin bağlantılarını Android Kotlin Hakkında Temel Bilgiler codelab'leri açılış sayfasında bulabilirsiniz.




