因此,我有一个ViewPager,它有2个片段,LogInFragment
和SignUpFragment
。它们都共享使用AuthViewModel
的相同ViewModel AuthRepository
。从AuthRepository
中的Firebase接收到结果后,就将其传递到AuthViewModel
中,并且将数据设置为在两个片段中都可以观察到的LiveData
。但是,即使更改是从SignUpFragment
开始的,实时数据总是在LogInFragment
中触发,而在LogInFragment
中却从未观察到。我读了一些书,有人提到也许两个片段都应该使用单独的viewmodel,实际上它们仍然是相同的AuthViewModel
,但是应该由Key
提供,所以这就是我所做的ViewModelProviders.of(this, viewModelFactory).get(currentKey, getViewModel())
,但是仍然,没有运气。我尝试过将SignUpFragment
隐藏起来,并且仅将LogInFragment
留在viewpager中,并且可以使用,但是仍然不能解决问题。
AuthRepository
@Singleton
class AuthRepository @Inject constructor() {
@Inject
lateinit var firebaseAuth: FirebaseAuth
@Inject
lateinit var firebaseDatabase: FirebaseDatabase
private var listener: FirebaseDataListener<Any>? = null
private var firebaseAuthResult: Any? = null
fun setFirebaseListener(listener: FirebaseDataListener<Any>) {
this.listener = listener
}
fun removeFirebaseListener() {
this.listener = null
}
fun register(email: String, password: String, name: String, lastName: String, city: String): Single<Task<AuthResult>?> {
return Single.create {
firebaseAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener { authTask ->
if (authTask.isSuccessful) {
firebaseAuthResult = authTask.result
listener?.onDataFetched(authTask, FirebaseResultType.SIGN_UP_COMPLETE_RESULT)
val userId = firebaseAuth.currentUser?.uid
userId?.let {
val user = User(userId, email, name, lastName, city)
firebaseDatabase.getReference(Constants.FIREBASE_USERS).push().setValue(user).addOnCompleteListener(updateUserCompleteListener)
}
if (!it.isDisposed) {
it.onSuccess(authTask)
}
} else {
handleUnsuccessfulAuth(authTask, it)
}
}
}
}
fun signIn(email: String, password: String): Single<Task<AuthResult>?> {
return Single.create {
firebaseAuth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener { authTask ->
if (authTask.isSuccessful) {
firebaseAuthResult = authTask.result
listener?.onDataFetched(authTask, FirebaseResultType.SIGN_IN_COMPLETE_RESULT)
if (!it.isDisposed) {
it.onSuccess(authTask)
}
} else {
handleUnsuccessfulAuth(authTask, it)
}
}
}
}
private fun handleUnsuccessfulAuth(authTask: Task<AuthResult>, it: SingleEmitter<Task<AuthResult>?>) {
firebaseAuthResult = authTask.exception
firebaseAuthResult?.let {
listener?.onDataFetched(firebaseAuthResult!!, FirebaseResultType.ERROR_RESULT)
}
it.onError(Throwable(authTask.exception?.localizedMessage, authTask.exception))
}
private val updateUserCompleteListener = OnCompleteListener<Void> {
if (it.isSuccessful) {
Timber.i("#updateUserCompleteListener successful update user $it")
} else {
Timber.e("#updateUserCompleteListener unsuccessful update user ${it.exception}")
}
}
}
AuthViewModel
class AuthViewModel @Inject constructor(
private val authRepository: AuthRepository,
private val scheduler: SchedulerProviderManager
) : ViewModel(), FirebaseDataListener<Any> {
var isLoading = ObservableField(false)
var firebaseResult = MutableLiveData<FirebaseResult>()
private val compositeDisposable by lazy { CompositeDisposable() }
override fun onDataFetched(data: Any, firebaseResultType: FirebaseResultType) {
val firebaseResultObject = FirebaseResult(data, firebaseResultType)
firebaseResult.value = firebaseResultObject
}
fun setAuthRepositoryListener() {
authRepository.setFirebaseListener(this)
}
fun register(email: String, password: String, name: String, lastName: String, city: String) {
isLoading.set(true)
compositeDisposable.addAll(authRepository.register(email, password, name, lastName, city)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
Timber.i("#register onSuccess $it")
isLoading.set(false)
}, {
Timber.e("#register onError ${it.cause}")
isLoading.set(false)
}))
}
fun signIn(email: String, password: String) {
isLoading.set(true)
compositeDisposable.addAll(authRepository.signIn(email, password)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
Timber.i("#signIn onSuccess $it")
isLoading.set(false)
},
{
Timber.e("#signIn onError ${it.cause}")
isLoading.set(false)
}
))
}
fun getFirebaseResult(): LiveData<FirebaseResult> = firebaseResult
override fun onCleared() {
authRepository.removeFirebaseListener()
super.onCleared()
}
}
LogInFragment
class LogInFragment : BaseFragment<AuthViewModel, FragmentLogInBinding>(true, LogInFragment::class.java.name) {
companion object {
val ACTION_LOG_IN = LogInFragment::javaClass.name + ".action_log_in"
val ACTION_SIGN_UP = LogInFragment::javaClass.name + ".action_sign_up"
fun newInstance(): LogInFragment {
val fragment = LogInFragment()
val args = Bundle()
fragment.arguments = args
return fragment
}
}
override fun getLayoutRes(): Int {
return R.layout.fragment_log_in
}
override fun getViewModel(): Class<AuthViewModel> {
return AuthViewModel::class.java
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binder = DataBindingUtil.inflate(inflater, getLayoutRes(), container, false)
init()
setListeners()
return binder.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
signInUser()
}
override fun getFirebaseAnalyticsName(): String {
return getString(R.string.screen_log_in)
}
fun init() {
binder.viewModel = viewModel
binder.executePendingBindings()
binder.progressbar.indeterminateDrawable.setColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY)
viewModel.setAuthRepositoryListener()
}
private fun setListeners() {
binder.tvRegisterNow.setOnClickListener { UtilsManager.sendActionToActivity(fragmentInteractionCallback, ACTION_SIGN_UP) }
binder.logInHolder.setOnClickListener {
if (resolveInputFields()) {
viewModel.signIn(binder.etEmail.text.toString(), binder.etPassword.text.toString())
}
}
}
private fun signInUser() {
viewModel.getFirebaseResult().observe(this, Observer<FirebaseResult> { result ->
when (result.firebaseResult) {
FirebaseResultType.SIGN_IN_COMPLETE_RESULT -> UtilsManager.sendActionToActivity(fragmentInteractionCallback, ACTION_LOG_IN)
FirebaseResultType.ERROR_RESULT -> {
if (result.data is Exception) {
when {
result.data is FirebaseAuthInvalidUserException -> longToast(R.string.wrong_email_pass).show()
}
}
}
else -> Timber.i("signInUser ${result.firebaseResult}")
}
})
}
}