安卓LiveData - 观察者在配置更改后总是触发

13

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

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

以下是ViewModel、Repository和Activity类的代码:

ChangePasswordViewModel

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的值自上次服务器调用以来没有更新,那么如果没有对 LiveData 进行更改,为什么 .observe() 会触发?

3个回答

7
这是一种预期行为,你可以在文档中看到:

observe (LifecycleOwner owner, Observer observer) 将给定的观察者添加到给定所有者的生命周期内的观察者列表中。事件在主线程上分发。如果LiveData已经设置了数据,则将其传递给观察者。

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

3
除了上面的回答之外,重要的是要理解在哪些情况下使用ViewModel和LiveData观察器,只观察一次。本文介绍了这些情况,并展示了一种简单处理它们的方法:使用LiveData和事件进行工作

2
我已经使用了MutableSharedFlow代替MutableLiveData,并解决了与你相同的问题。
你可以尝试这样做:
    private val responseCode = MutableSharedFlow<Int>()
    ...
    fun passChangeCallback() {
        viewModelScope.launch {
        responseCode.emit(serverResponse)
    }

由于MutableSharedFlow在默认情况下不会重放已经发出的值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接