LiveData Observer停止进行配置更改

时间:2019-02-18 21:38:20

标签: android android-livedata

这有点疯狂,但是观察者停止进行配置更改。奇怪的是,观察者在onActivityCreated中执行时可以完美地工作,但是如果我在另一部分中执行观察者,它将停止进行配置更改。

这是我的代码,第一个代码效果很好,但是第二个代码是问题。调用视图模型的方式是相同的,所以我不太了解哪个是真正的问题。

从已创建活动的服务器中获取数据

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    binding = DataBindingUtil.inflate(inflater, R.layout.user_fragment, container, false)
    return binding.root
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)

    userViewModel = ViewModelProviders.of(this, viewModelFactory).get(UserViewModel::class.java)
    binding.viewModel = userViewModel

    userViewModel.loadData().observe(
            viewLifecycleOwner,
            Observer<Resource<Response<UserModel>>> {this.handleResponse(it)}
    )
}

private fun handleResponse(response: Resource<Response<UserModel>>?) {
    when (response.estado) {
        State.ERROR -> {
            hideProgressBar()
        }
        State.LOADING -> {
            showProgressBar()
        }
        State.SUCCESS -> {
            hideProgressBar()
            // Display data
        }
    }
}

虽然我正在从服务器中获取数据并且设备已旋转,但观察者仍处于活动状态并继续获取数据。问题出在哪里?这里没有问题。继续阅读:


现在我有了数据,我已经进行了一些修改,我想调用我的API。所以:

binding.btSubmit.setOnClickListener {
    userViewModel.saveUser().observe(
            viewLifecycleOwner,
            Observer<Resource<Response<SuccessModel>>> {this.handleSaveResponse(it)}
    )
}


private fun handleSaveResponse(response: Resource<Response<SuccessModel>>?) {
    when (response.estado) {
        State.ERROR -> {
            hideProgressBar()
        }
        State.LOADING -> {
            showProgressBar()
        }
        State.SUCCESS -> {
            hideProgressBar()
            // Call another fragment
        }
    }
}

这是问题所在!当我保存数据并旋转设备时,观察者停止工作(进度消失,并且从未调用State.SUCCESS)

我不会粘贴与存储库或视图模型有关的信息,因为使用相同的存储库和相同的Viewmodel,一个观察者可以工作,而另一个则不行。所以我认为与此无关。

谢谢!

编辑

UserViewModel

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.project.db.entity.*
import com.project.repository.ApplicationRepository
import javax.inject.Inject

class UserViewModel @Inject constructor(repository: ApplicationRepository)
    : ViewModel() {
    var userModel: MutableLiveData<UserModel> = MutableLiveData()

    init {
        userModel.value = UserModel()
    }

    val data = repository.getData() 

    fun saveUser(): LiveData<Resource<Response<SuccessModel>>> {
        return repository.saveUser(userModel.value!!)
    }
}

ApplicationRepository

import androidx.lifecycle.LiveData
import com.project.repository.util.ApiResponse
import com.project.repository.util.AppExecutors
import com.project.repository.util.NetworkOnlyBoundResource
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class ApplicationRepository @Inject
internal constructor(
        val mAppExecutors: AppExecutors){

    fun saveUser(userModel: UserModel): LiveData<Response<Response<SuccessModel>>> {
        return object : NetworkOnlyBoundResource<Response<SuccessModel>>(mAppExecutors) {
            override fun saveResponse(item: Response<SuccessModel>) {
                userDao.saveUser(item.model!!)
            }
            override fun crearLlamada(): LiveData<ApiResponse<Response<SuccessModel>>> {
                return userService.saveUser(userModel)
            }
        }.asLiveData()
    }
}

编辑2 这就是我称呼另一个片段的方式:

fragmentManager.beginTransaction()
    .setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out)
    .replace(containerId, fragment)
    .setReorderingAllowed(true)
    .addToBackStack(fragment.javaClass.simpleName)
    .commitAllowingStateLoss()

1 个答案:

答案 0 :(得分:0)

旋转设备onStop时,将删除所有观察者服务器。由于onActivityCreated在生命周期路径上,因此将重新观察实时数据。但是,由于您的onClick观察是事件驱动的,因此不会自动重新观察。另一个问题是,由于实时数据是在saveUser调用中生成的,由于引用丢失,您将无法重新观察它。

编辑:

这是一个潜在的解决方案。

class UserViewModel @Inject constructor(repository: ApplicationRepository)
: ViewModel() {
    private val userModel: MutableLiveData<UserModel> = MutableLiveData()

    val data = repository.sincronizarExpedienteDos() // You only need to load this once calling loadData every onCreate wastes the livedata.

    private val saveTrigger = MutableLiveData<Boolean>()

    val saveStateLiveData = Transformations.switchMap(savetrigger) {
        val userValue = userModel.value
        return@switchMap if (it == null || userValue == null) {
            MutableLiveData().apply {
              value = null
            }
        else {
            repository.saveUser(userValue)
        }
    }

    init {
        userModel.value = UserModel()
    }

    fun saveUser() {
        saveTrigger.value = true
    }

    fun resetSaveTrigger() {
        saveTrigger.value = null
    }
}

然后在您的片段中:

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)

    userViewModel = ViewModelProviders.of(this, viewModelFactory).get(UserViewModel::class.java)
    binding.viewModel = userViewModel

    binding.btSubmit.setOnClickListener {
        userViewModel.saveUser()
    }

    userViewModel.data.observe(
            viewLifecycleOwner,
            Observer<Resource<Response<UserModel>>> {this.handleResponse(it)}
    )

    userViewModel.saveStateLiveData.observe(
        viewLifecycleOwner,
        Observer<Resource<Response<SuccessModel>>> {this.handleSaveResponse(it)}
    )
}

private fun handleResponse(response: Resource<Response<UserModel>>?) {
    when (response.estado) {
        State.ERROR -> {
            hideProgressBar()
        }
        State.LOADING -> {
            showProgressBar()
        }
        State.SUCCESS -> {
            hideProgressBar()
            // Display data
            viewModel.resetSaveTrigger()
        }
    }
}

private fun handleSaveResponse(response: Resource<Response<SuccessModel>>?) {
    when (response.estado) {
        State.ERROR -> {
            hideProgressBar()
        }
        State.LOADING -> {
            showProgressBar()
        }
        State.SUCCESS -> {
            hideProgressBar()
            // Call another fragment
        }
    }
}

这种方法可以重新观察实时数据,而无需生成其他数据。