Comments added

This commit is contained in:
Gavriil Sitnikov 2017-07-14 17:45:03 +03:00
parent a6c8882421
commit d579601de6
5 changed files with 27 additions and 6 deletions

View File

@ -40,8 +40,10 @@ class ProfileActivity : LifecycleActivity() {
override fun onDestroy() {
super.onDestroy()
// обнуляем поле profileViewModel
binding.profileViewModel = null
// необходимо вручную вызвать обновление байндингов,
// так как автоматическое обновление не работает на этапе onDestroy
binding.executePendingBindings()
}
}

View File

@ -25,6 +25,8 @@ import android.content.Context
class ProfileRepository(context: Context) {
private val loginKey = "login"
private val preferences = context.getSharedPreferences("app_preferences", Context.MODE_PRIVATE)
// LiveData, на которую можно подписаться
// и получать обновления логина пользователя
private val innerLoggedInUser = LoggedInUserLiveData()
val loggedInUser: LiveData<String?>
@ -32,16 +34,22 @@ class ProfileRepository(context: Context) {
fun login(login: String) {
preferences.edit().putString(loginKey, login).apply()
innerLoggedInUser.update(login)
notifyAboutUpdate(login)
}
fun logout() {
preferences.edit().putString(loginKey, null).apply()
innerLoggedInUser.update(null)
notifyAboutUpdate(null)
}
private fun notifyAboutUpdate(login: String?) {
innerLoggedInUser.update(login)
}
private inner class LoggedInUserLiveData : LiveData<String?>() {
// так лучше не делать в конструкторе, а высчитывать текщее значение асинхронно
// при первом вызове колбека onActive
init {
value = preferences.getString(loginKey, null)
}
@ -52,6 +60,5 @@ class ProfileRepository(context: Context) {
fun update(login: String?) {
postValue(login)
}
}
}

View File

@ -28,23 +28,34 @@ import touchin.aacplusdbtest.utils.TextField
class ProfileViewModel(application: Application) : AndroidViewModel(application) {
private val profileRepository: ProfileRepository = (application as AacPlusDbTestApp).profileRepository
// класс Transformations — это класс-хэлпер для преобразования данных
// метод map, просто конвертирует данные из одного типа в другой - в данном случае из String? в boolean
private val isUserLoggedInLiveData = Transformations.map(profileRepository.loggedInUser) { login -> login != null }
// представляет логин авторизованного пользователя или null
val userLogin = LifecycleLiveDataField(profileRepository.loggedInUser)
// представляет авторизован ли пользователь
val isUserLoggedInLiveData = Transformations.map(profileRepository.loggedInUser) { login -> login != null }
val isUserLoggedIn = LifecycleLiveDataField(isUserLoggedInLiveData)
// представляет логин, введенный пользователем с клавиатуры
// TextField - это ObservableField, реализующий интерфейс TextWatcher
// это нужно, чтобы можно было байндиться к text и addTextChangedListener,
// организовав таким образом двустронний байндинг.
// При вводе текста в EditText изменяется ViewModel, при изменении ViewModel — изменяется в EditText.
val inputLogin = TextField()
fun loginOrLogout() {
// необходимо получить текущее состояние - авторизован пользователь или нет и решить, что делать
isUserLoggedInLiveData.observeForever(object : Observer<Boolean> {
override fun onChanged(loggedIn: Boolean?) {
if (loggedIn!!) {
profileRepository.logout()
} else if (inputLogin.get() != null) {
// вызываем логин только если пользователь что-то ввел в поле ввода
profileRepository.login(inputLogin.get())
} else {
// по идее, тут можно отобразить ошибку "Введите логин"
}
// при выполнении команды приходится отписываться вручную
isUserLoggedInLiveData.removeObserver(this)
}
})

View File

@ -38,6 +38,7 @@ class LifecycleLiveDataField<T>(val source: LiveData<T?>) : ObservableField<T>()
override fun addOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback) {
super.addOnPropertyChangedCallback(callback)
try {
// немножко рефлексии, по-другому никак
val callbackListenerField = callback.javaClass.getDeclaredField("mListener")
callbackListenerField.setAccessible(true)
val callbackListener = callbackListenerField.get(callback) as WeakReference<ViewDataBinding>

View File

@ -26,7 +26,7 @@ import android.databinding.ObservableField
import java.util.concurrent.atomic.AtomicInteger
// наследуем от ObservableField
// имплементируем Observer (интерфейс из-подписчик для LiveData) чтобы синхронизировать значения LiveData и ObservableField
// имплементируем Observer (подписчик для LiveData) чтобы синхронизировать значения LiveData и ObservableField
class LiveDataField<T>(val source: LiveData<T?>) : ObservableField<T>(), Observer<T?> {
// отслеживаем количество подписчиков на этот ObservableField
private var observersCount: AtomicInteger = AtomicInteger(0)