观察()方法被调用两次,如何防止它?



observe方法被调用两次,第一次使用变量的最后一个值,然后使用更新后的值。对我来说,这是一个大问题,因为我需要在不同的情况下展示Toast,我不知道如何解决这个问题。例如,如果我用正确的凭据调用函数,它会显示Toast ("Login effettuato"),但是如果我尝试用错误的凭据登录,它会首先显示Toast ("Login effettuato"),然后显示Toast (" error ")。请帮帮我。

public class LoginFragment extends Fragment {
private LoginViewModel loginViewModel;
private FragmentLoginBinding binding;
public static final String SHARED_PREFS = "CREDENTIAL";
public static final String key = "accessToken";
private ExecutorService threadPool;
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
threadPool = Executors.newFixedThreadPool(5);
loginViewModel = new ViewModelProvider(this).get(LoginViewModel.class);
binding = FragmentLoginBinding.inflate(inflater, container, false);
View root = binding.getRoot();
ImageView backgroundLoginImg = binding.backgroundLoginImg;
Glide.with(getContext()).load(R.drawable.wood).into(backgroundLoginImg);
EditText email = binding.emailText;
EditText password = binding.editTextPassword;
Button login = binding.loginButton;
login.setOnClickListener(view -> {
if (!email.getText().toString().equals("") && !password.getText().toString().equals("")) {
loginViewModel.login(email.getText().toString(), password.getText().toString())
.observe(getViewLifecycleOwner(), accessToken -> {
if (accessToken != null) {
threadPool.execute(() -> {
SharedPreferences sharedPreferences = LoginFragment.this.getActivity()
.getSharedPreferences(SHARED_PREFS, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(key, accessToken.getAccessToken());
editor.apply();
});
Toast.makeText(LoginFragment.this.getContext(), "Login effettuato",
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(LoginFragment.this.getContext(), "Errore", Toast.LENGTH_SHORT)
.show();
}
});
email.getText().clear();
password.getText().clear();
} else {
Toast.makeText(getContext(), "Compilare tutti i campi", Toast.LENGTH_SHORT).show();
}
});
return root;
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}
public class LoginViewModel extends ViewModel {
private final Repository repository;
public LoginViewModel() {
repository = new Repository();
}
public MutableLiveData<AccessToken> login(String email, String password) {
return repository.onLoginClick(email, password);
}
}
public class Repository {
public static MutableLiveData<AccessToken> accessToken;
private ExecutorService threadPool;
public Repository() {
accessToken = new MutableLiveData();
threadPool = Executors.newFixedThreadPool(8);
}
public MutableLiveData<AccessToken> onLoginClick(String email, String password) {
threadPool.execute(() -> {
accessToken.postValue(null);
UtenteLogin utenteLogin = new UtenteLogin(email, password);
Call<AccessToken> call = RetrofitClient.getInstance().getMyApi().login(utenteLogin);
call.enqueue(new Callback<AccessToken>() {
@Override
public void onResponse(Call<AccessToken> call, Response<AccessToken> response) {
if (response.code() == 201) {
if (response.body() != null) {
accessToken.postValue(response.body());
}
} else {
}
}
@Override
public void onFailure(Call<AccessToken> call, Throwable t) {
Log.println(Log.INFO, "Login", "Login fallito");
}
});
});
return accessToken;
}
}

不要在setOnClickListener{…}

把你的调用观察和逻辑在setOnClickListener之外,但保持它在onCreateView或在onCreateView中只调用一次的单独函数。

LiveData保留最后一个值,并在观察者开始观察时更新它们。这是一个很好的特性,如果你的视图被销毁并重新创建数据仍然在那里并且视图用那个数据重新加载,所以它并不意味着在每个动作上都被观察到。只需要在onCreateView中开始观察一次。

观察者不会在一次更新后死亡,它会一直存在,直到你给它的生命周期结束,在这种情况下是Fragment的viewLifecycle,并且可以处理重复更新。所以,你不应该在setOnClickListener中设置观察者因为那会在每次点击发生时创建额外的观察者这会导致像这样的bug。