我是android开发的新手,并且正在使用MVVM模式在android中实现登录功能。 我发现了LiveData的有趣功能:
通常,LiveData仅在数据更改时才向活动观察者提供更新。此行为的一个例外是,当观察者从非活动状态更改为活动状态时,他们也会收到更新。此外,如果观察者第二次从非活动状态更改为活动状态,则只有在该值自上次变为活动状态以来已发生更改时,它才会收到更新。
在我的程序中,当我回到片段时,它将立即触发观察功能。 例如,这会导致错误,例如,在observe函数中,我引用了视图的某些小部件,但是当我返回该片段后立即触发该小部件时,该小部件未初始化,因此会导致NullPointerException。如何避免这种情况?
我尝试用Transformation.distinctUntilChanged()包装实时数据,但是它不起作用...
这是我的视图模型的代码
public class LoginViewModel extends BaseViewModel<LoginRepository> {
private MutableLiveData<LoginEvent> loginEventMutableLiveData = new MutableLiveData<>();
private LiveData<RemoteResponse<UserInfo>> remoteResponseMutableLiveData =
Transformations.switchMap(loginEventMutableLiveData, repository::login);
private MutableLiveData<String> errMsgMutableLiveData = new MutableLiveData<>();
LoginViewModel(LoginRepository baseRepository) {
super(baseRepository);
}
public LiveData<RemoteResponse<UserInfo>> getRemoteResponseMutableLiveData() {
return remoteResponseMutableLiveData;
}
public MutableLiveData<String> getErrMsgMutableLiveData() {
return errMsgMutableLiveData;
}
public void login(LoginEvent loginEvent) {
if (Utils.isNullOrEmpty(loginEvent.userId)) {
errMsgMutableLiveData.setValue("Please enter a valid password!");
return;
}
if (Utils.isNullOrEmpty(loginEvent.password)) {
errMsgMutableLiveData.setValue("Please enter a valid password!");
return;
}
loginEventMutableLiveData.setValue(loginEvent);
}
}
这是我的观察功能:
viewModel.getRemoteResponseMutableLiveData().observe(getViewLifecycleOwner(), it -> {
if (it != null && it.status.equals("OK")) {
Utils.constructToast(getContext(), "Login success!").show();
Config.userId = it.response.userId;
Config.name = it.response.name;
navigationManager.navigateTo(new HomeListFragment());
} else {
Utils.constructToast(getContext(), it == null ? "Error !" : it.status).show();
}
});
在我的程序中,一旦登录成功,我就使用后退按钮返回登录片段,观察功能将立即触发,吐司显示“ Login Success”并立即进入homeListFragment ...
有什么建议吗?我很感激!谢谢!
-------版本-------
这是我的登录片段
public class LoginFragment extends BaseFragment<LoginViewModel, LoginRepository> {
private LoginFragmentBinding binding;
private NavigationManager navigationManager;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
binding = LoginFragmentBinding.inflate(inflater, container, false);
return binding.getRoot();
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
navigationManager = (NavigationManager) context;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
binding.btnLogin.setOnClickListener( v -> {
viewModel.login(new LoginEvent(binding.etUserIdLogin.getText().toString(),
Utils.md5Encryption(binding.etPasswordLogin.getText().toString()))); // faker user info
});
viewModel.getRemoteResponseMutableLiveData().observe(getViewLifecycleOwner(), it -> {
if (it != null && it.status.equals("OK")) {
Utils.constructToast(getContext(), "Login success!").show();
Config.userId = it.response.userId;
Config.name = it.response.name;
navigationManager.navigateTo(new HomeListFragment());
} else {
Utils.constructToast(getContext(), it == null ? "Error !" : it.status).show();
}
});
viewModel.getErrMsgMutableLiveData().observe(getViewLifecycleOwner(), it -> {
Utils.constructToast(getContext(), it).show();
});
}
@Override
protected LoginViewModel getViewModel() {
return new ViewModelProvider(requireActivity(), getFactory()).get(LoginViewModel.class);
}
@Override
protected ViewModelProvider.Factory getFactory() {
return new ViewModelProvider.Factory() {
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return (T) new LoginViewModel(getRepository());
}
};
}
@Override
protected LoginRepository getRepository() {
return new LoginRepository();
}
}
我的程序处于单一活动中,因此主要活动仅包含片段转换代码
public class MainActivity extends AppCompatActivity implements LocationListener,NavigationManager {
private DrawerLayout drawerLayout;
private FirebaseAnalytics firebaseAnalytics;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.ACCESS_FINE_LOCATION}, 1);
getLocation();
navigateTo(new OnBoardingSplashFragment());
}
@Override
public void navigateTo(Fragment fragment) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.first_fragment, fragment, null)
.addToBackStack(null)
.commit();
}
// .....
}