返回上一个片段时如何避免LiveData触发观察器

时间:2020-04-27 05:24:46

标签: android mvvm observable android-lifecycle android-livedata

我是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();
    }

   // .....
}

0 个答案:

没有答案