Android 实时数据 - 观察配置更改后始终触发



我目前正在重构我的代码,以包含由android.arch库提供的带有LiveData的ViewModel。我有一个简单的活动,它将密码更改请求发送到服务器并根据HTTP响应代码进行操作。

为此,我创建了扩展数据 ViewModel 的类和一个用于调用服务器的存储库类。我的 ViewModel 类有一个 MutableLiveData 字段,我使用 .observe(...) 方法从我的活动中订阅了该字段。问题是 .observe(...) 中的代码在配置更改(即屏幕旋转)后一直触发,我不知道为什么。

以下是相应的视图模型、存储库和活动类的代码:

更改密码视图模型

public class ChangePasswordViewModel extends ViewModel{
private MutableLiveData<Integer> responseCode;
private PasswordChangeRepository passwordChangeRepository;
public ChangePasswordViewModel() {
responseCode = new MutableLiveData<>();
passwordChangeRepository = new PasswordChangeRepositoryImpl();
}
public MutableLiveData<Integer> responseCodeLiveData() {
return responseCode;
}
public void sendChangePasswordRequest(String newPassword){
passwordChangeRepository.changePassword(newPassword,     passChangeCallback());
}
// Callback that fires after server sends a response
private Callback passChangeCallback(){
...
responseCode.postValue(serverResponse)
...
}

密码更改存储库

public class PasswordChangeRepositoryImpl {
public void changePassword(String newPassword, Callback<Void> callback){
//Sending new password to server and processing response in callback
ServerCalls.changePassword(newPassword, callback);
}
}

活动

public class ChangePasswordActivity extends AppCompatActivity{
...
private void init(){
//Getting appropriate view model
passwordViewModel = ViewModelProviders.of(this).get(ChangePasswordViewModel.class);
// Starting to observe LiveData
passwordViewModel.getResponseCode().observe(this, responseCode -> {
Log.info("Server response is " + responseCode);
});
//Sending new password to server
buttonPassChange.setOnClickListener(view ->
passwordViewModel.sendChangePasswordRequest("newPass")
);
}
...
}

问题是,在我第一次使用 sendChangePasswordRequest(...) 向服务器发送请求后,观察活动中的代码

passwordViewModel.getResponseCode().observe(this, responseCode -> {
Log.info("Server response is " + responseCode);
});

每次旋转屏幕后都会触发。为什么会这样?自上次服务器调用以来,MutableLiveData responseCode 的值尚未更新,那么如果实时数据没有更改,为什么 .observe() 会触发呢?

这是预期的行为,如您在文档中看到的那样:

观察(生命周期所有者所有者, 观察者观察者)在给定所有者的生命周期内将给定观察者添加到观察者列表中。事件是 在主线程上调度。如果 LiveData 已经有数据集,则 将交付给观察员。

如果你想观察视图状态的变化,那么你应该创建并观察视图状态而不是网络请求,谷歌已经为这种情况提供了一个示例。

除了上面的答案之外,了解使用 ViewModel 和 LiveData 观察器只观察一次的场景也很重要,本文解释了它们并展示了一种轻松处理它的方法: 使用 LiveData 和事件

我使用了MutableSharedFlow而不是MutableLiveData,并解决了与您相同的问题。

你可以试试这个:

private val responseCode = MutableSharedFlow<Int>()
...
fun passChangeCallback() {
viewModelScope.launch {
responseCode.emit(serverResponse)
}

因为 MutableSharedFlow 不会重播 defalut 已经发出的值。

最新更新