首页 > 解决方案 > 在应用程序被发送到后台之前应用程序无法运行

问题描述

我正在 Kotlin + Firebase 中制作 Instagram 克隆,试图添加“查找要关注的用户”功能。它工作正常,从 Firebase 加载信息,但在我重构代码后,它不会向用户显示,直到我锁定屏幕或折叠/展开应用程序。之后信息就会弹出来。

我只是从 Firebase 查询所有用户并显示除活跃用户之外的所有人。我试图调试这个问题,发现it.children.map { it.asUser()!! }由于某种原因在活动开始时不会触发。

这是我的代码:

FindUsersActivity

package com.example.imagegram.screens.findusers

import android.os.Bundle
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.imagegram.R
import com.example.imagegram.screens.common.BaseActivity
import com.example.imagegram.models.User
import kotlinx.android.synthetic.main.activity_find_users.*

//@Suppress("DEPRECATION")
class FindUsersActivity : BaseActivity(),
    UsersAdapter.Listener {

    private lateinit var mUser: User
    private lateinit var mUsers: List<User>
    private lateinit var mAdapter: UsersAdapter
    private lateinit var mViewModel: FindUsersViewModel


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_find_users)

        mAdapter = UsersAdapter(this)

        mViewModel = initViewModel()

        find_users_back_image.setOnClickListener { finish() }

        find_users_recycler.adapter = mAdapter
        find_users_recycler.layoutManager = LinearLayoutManager(this)

        mViewModel.userAndFriends.observe(this, Observer {
            it?.let { (user, otherUsers) ->
                mUser = user
                mUsers = otherUsers

                mAdapter.update(mUsers, mUser.follows)
            }
        })
    }


    override fun follow(uid: String) {
        setFollow(uid, true) {
            mAdapter.followed(uid)
        }

    }

    override fun unfollow(uid: String) {
        setFollow(uid, false) {
            mAdapter.unfollowed(uid)

        }
    }

    private fun setFollow(uid: String, follow: Boolean, onSuccess: () -> Unit) {
        mViewModel.setFollow(mUser.uid, uid, follow)
            .addOnSuccessListener { onSuccess() }
    }

    companion object {
        const val TAG = "FindUsersActivity"
    }
}

FindUsersViewModel

package com.example.imagegram.screens.findusers

import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import com.example.imagegram.data.FeedPostsRepository
import com.example.imagegram.data.UsersRepository
import com.example.imagegram.data.common.map
import com.example.imagegram.models.User
import com.google.android.gms.tasks.OnFailureListener
import com.google.android.gms.tasks.Task
import com.google.android.gms.tasks.Tasks

class FindUsersViewModel(
    private val onFailureListener: OnFailureListener,
    private val usersRepo: UsersRepository,
    private val FeedPostsRepo: FeedPostsRepository
) : ViewModel() {

    // only let Activity work with LiveData
    // so that it could not change anything itself but could access it for reading
    val userAndFriends: LiveData<Pair<User, List<User>>> =
        usersRepo.getUsers().map { allUsers ->
            val (userList, otherUsersList) = allUsers.partition {
                it.uid == usersRepo.currentUid()
            }
            userList.first() to otherUsersList
        }

    fun setFollow(currentUid: String, uid: String, follow: Boolean): Task<Void> {
        return if (follow) {
            Tasks.whenAll(
                usersRepo.addFollow(currentUid, uid),
                usersRepo.addFollower(currentUid, uid),
                FeedPostsRepo.copyFeedPosts(postsAuthorUid = uid, toUid = currentUid)
            )
        } else {
            Tasks.whenAll(
                usersRepo.deleteFollow(currentUid, uid),
                usersRepo.deleteFollower(currentUid, uid),
                FeedPostsRepo.deleteFeedPosts(postsAuthorUid = uid, toUid = currentUid)
            )
        }.addOnFailureListener(onFailureListener)


    }
}

用户存储库

package com.example.imagegram.data

import android.net.Uri
import androidx.lifecycle.LiveData
import com.example.imagegram.models.User
import com.google.android.gms.tasks.Task

interface UsersRepository {
    fun getUsers(): LiveData<List<User>>
    fun currentUid(): String?
    fun addFollow(fromUid: String, toUid: String): Task<Unit>
    fun deleteFollow(fromUid: String, toUid: String): Task<Unit>
    fun addFollower(fromUid: String, toUid: String): Task<Unit>
    fun deleteFollower(fromUid: String, toUid: String): Task<Unit>

    fun getUser(): LiveData<User>
    fun uploadUserPhoto(localImage: Uri): Task<Uri>
    fun updateUserPhoto(downloadUrl: Uri): Task<Unit>
    fun updateEmail(currentEmail: String, newEmail: String, password: String): Task<Unit>
    fun updateUserProfile(currentUser: User, newUser: User): Task<Unit>
}

FirebaseUsers 存储库:

package com.example.imagegram.data.firebase

import android.net.Uri
import androidx.lifecycle.LiveData
//import androidx.lifecycle.map
import com.example.imagegram.data.firebase.common.asUser
import com.example.imagegram.utils.toUnit
//import com.example.imagegram.activities.map
import com.example.imagegram.common.task
import com.example.imagegram.data.UsersRepository
import com.example.imagegram.data.common.map
import com.example.imagegram.models.User
import com.example.imagegram.utils.*
import com.google.android.gms.tasks.Task
import com.google.android.gms.tasks.Tasks
import com.google.firebase.auth.EmailAuthProvider
import com.google.firebase.auth.FirebaseAuth

class FirebaseUsersRepository :
    UsersRepository {
    override fun uploadUserPhoto(localImage: Uri): Task<Uri> =
        task { taskSource ->
            storage.child("users/${currentUid()!!}/photo").putFile(localImage)
                .addOnSuccessListener {
                    getUrl().addOnCompleteListener {
                        taskSource.setResult(it.result!!)
                    }
//                    Tasks.forResult(getUrl().result!!) //it?.downloadUrl!!)
                }
        }

    override fun getUsers(): LiveData<List<User>> = database.child("users").liveData().map {
        it.children.map { it.asUser()!! }
    }

    override fun addFollow(fromUid: String, toUid: String): Task<Unit> =
        getFollowsRef(fromUid, toUid).setValue(true).toUnit()

    override fun deleteFollow(fromUid: String, toUid: String): Task<Unit> =
        getFollowsRef(fromUid, toUid).removeValue().toUnit()

    override fun addFollower(fromUid: String, toUid: String): Task<Unit> =
        getFollowersRef(fromUid, toUid).setValue(true).toUnit()

    override fun deleteFollower(fromUid: String, toUid: String): Task<Unit> =
        getFollowersRef(fromUid, toUid).removeValue().toUnit()

    private fun getFollowsRef(fromUid: String, toUid: String) =
        database.child("users").child(fromUid).child("follows").child(toUid)

    private fun getFollowersRef(fromUid: String, toUid: String) =
        database.child("users").child(toUid).child("followers")
            .child(fromUid)

    override fun currentUid() = FirebaseAuth.getInstance().currentUser?.uid


    private fun getUrl() = storage.child("users/${currentUid()!!}/photo").downloadUrl

    override fun updateUserPhoto(downloadUrl: Uri): Task<Unit> =
        database.child("users/${currentUid()!!}/photo").setValue(downloadUrl.toString()).toUnit()

    override fun updateEmail(currentEmail: String, newEmail: String, password: String): Task<Unit> {
        val credential = EmailAuthProvider.getCredential(currentEmail, password) // get credential
        val currentUser = auth.currentUser
        return if (currentUser != null) {

            currentUser.reauthenticate(credential).onSuccessTask {//try to re-authentiate
                currentUser.updateEmail(newEmail)
            }.toUnit()
        } else {
            Tasks.forException(IllegalStateException("User is not authenticated"))
        }

    }

    override fun updateUserProfile(currentUser: User, newUser: User): Task<Unit> {
        val updatesMap = mutableMapOf<String, Any?>()
        if (newUser.name != currentUser.name) updatesMap["name"] = newUser.name
        if (newUser.username != currentUser.username) updatesMap["username"] = newUser.username
        if (newUser.email != currentUser.email) updatesMap["email"] = newUser.email

        return database.child("users").child(currentUid()!!).updateChildren(updatesMap).toUnit()

    }


    override fun getUser(): LiveData<User> =
        database.child("users").child(currentUid()!!).liveData().map {
            it.asUser()!!
        }


}

你知道可能是什么问题吗?任何帮助将不胜感激<3

标签: androidkotlinviewmodelunlock

解决方案


推荐阅读