重新加载片段后触发 LiveData 观察器

LiveData observer triggered after reloading fragment

我的 MainAcivity 托管 2 个片段,登录并注册。我在 LoginFragment 上有一个 LiveData 观察器,它观察用户登录实时数据,之后如果用户通过身份验证 MainMenuActivity 意图将启动。在主菜单上有注销按钮,可以启动 MainActivity 并加载 LoginFragment。

但是问题来了,加载片段后 LoginFragment 上的观察者立即触发,直接再次启动 MainMenuActivity 意图。

我的登录片段:

public class LoginFragment extends Fragment {
    public static LoginFragment newInstance(){
        return new LoginFragment();
    }

    private LoginViewModel mLoginViewModel;
    private LiveData<UserModelJSONPlaceholder> mUserModelLiveData;

    private static final String TAG = "FragLogin";
    private Button mBtnLogin;
    private EditText mTxtUsername, mTxtPass;
    private TextView mTxtRegister;
    private CheckBox mCheckBoxRemember;
    private TextView mTxtInvalid;
    private Callbacks mCallbacks = null;
    private ProgressBar mProgressBar;
    private UserApiInterface mAPIInterface;
    private SharedPreferences mSharedPreferences;
    private SharedPreferences.Editor mPreferencesEditor;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_login,container,false);

        mBtnLogin = view.findViewById(R.id.btnLogin_login);
        mTxtUsername = view.findViewById(R.id.txtUsername);
        mTxtPass = view.findViewById(R.id.txtPass);
        mCheckBoxRemember = view.findViewById(R.id.checkBoxRememberMe);
        mTxtRegister = view.findViewById(R.id.txtRegister_login);
        mProgressBar = view.findViewById(R.id.progressBar);
        mTxtInvalid = view.findViewById(R.id.txtInvalid);

        mProgressBar.setVisibility(View.GONE);
        mTxtInvalid.setVisibility(View.GONE);

        mAPIInterface = APIClient.getClient().create(UserApiInterface.class);
        mSharedPreferences = getContext().getSharedPreferences("login",Context.MODE_PRIVATE);
        mPreferencesEditor = mSharedPreferences.edit();
        setListener();

        return view;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mLoginViewModel = new ViewModelProvider(this).get(LoginViewModel.class);

        mUserModelLiveData = mLoginViewModel.getUserModelLiveData();

        //observer would be triggered right after loading fragment after logout
        mUserModelLiveData.observe(this, new Observer<UserModelJSONPlaceholder>() {
            @Override
            public void onChanged(UserModelJSONPlaceholder userModel) {

                Log.d(TAG, "onChanged: Observer: "+userModel.getResponse());
                mProgressBar.setVisibility(View.GONE);
                String loginAuth = userModel.getResponse();

                if(loginAuth.equals("OK")){
                    mPreferencesEditor.putString("name",userModel.getUserModel().getName());
                    mCallbacks.login_goMainMenu(userModel.getUserModel().getName());
                }else{
                    mTxtInvalid.setVisibility(View.VISIBLE);
                }
            }
        });
    }

    private void doLogin(){
        mProgressBar.setVisibility(View.VISIBLE);
        final String username = mTxtUsername.getText().toString().trim();
        final String password = mTxtPass.getText().toString().trim();
        mLoginViewModel.authLogin(username,password);
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mCallbacks = (Callbacks) context;
    }

    private void setListener(){
        mBtnLogin.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                doLogin();
            }
        });
        mTxtRegister.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mCallbacks.login_goRegister();
            }
        });
        mCheckBoxRemember.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if(buttonView.isChecked()){
                    mPreferencesEditor.putBoolean("rememberMe", true).apply();
                    Log.d(TAG, "onCheckedChanged: Checked");
                }else{
                    mPreferencesEditor.putBoolean("rememberMe", false).apply();
                    Log.d(TAG, "onCheckedChanged: Unchecked");
                }
            }
        });
    }

    public interface Callbacks{
        void login_goMainMenu(String name);
        void login_goRegister();
    }
}

我的 MainMenuActivity:

public class MainMenuActivity extends AppCompatActivity {
    private static final String ARG_NAME = "arg_name";

    private Button mBtnEnterQ,mBtnCreateQ;
    private TextView mTxtName;
    private Toolbar mToolbar;
    private SharedPreferences mSharedPreferences;
    private SharedPreferences.Editor mEditor;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_menu);

        mBtnEnterQ = findViewById(R.id.btnEnterQ);
        mBtnCreateQ = findViewById(R.id.btnCreateQ);
        mTxtName = findViewById(R.id.txtUsername);
        mToolbar = findViewById(R.id.toolbar);
        mSharedPreferences = getSharedPreferences("login",MODE_PRIVATE);
        mEditor = mSharedPreferences.edit();

        setSupportActionBar(mToolbar);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.toolbar_menu,menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case R.id.itemLogout:
                doLogout();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    private void doLogout(){
        mEditor.remove("rememberMe");
        mEditor.apply();
        Intent i = new Intent(this, MainActivity.class);
        startActivity(i);
        finish();
    }
}

这是我的 ViewModel 和 LoginFragment 的 Repo:

public class LoginViewModel extends ViewModel {
    private static final String TAG = "LoginVM";
    private UserRepository mUserRepository;
    LiveData<UserModelJSONPlaceholder> mUserModelLiveData;


    public LoginViewModel() {
        mUserRepository = UserRepository.getInstance();
    }

    public void authLogin(String username, String password){
       mUserRepository.authLogin(username,password);
    }

    public LiveData<UserModelJSONPlaceholder> getUserModelLiveData() {
        return mUserRepository.getUserModelLiveData();
    }
}

public class UserRepository {
    private static UserRepository instance;

    private static final String TAG = "RepoUser";
    private UserApiInterface mUserApiInterface;
    MutableLiveData<UserModelJSONPlaceholder> userModelLiveData;

    public static UserRepository getInstance(){
        if(instance==null){
            instance=new UserRepository();
        }
        return instance;
    }

    private UserRepository(){
        mUserApiInterface = APIClient.getClient().create(UserApiInterface.class);
        Log.d(TAG, "UserRepository: repoInit");
    }

    public void authLogin(String username, String password){
        Log.d(TAG, "authLogin: REQUEST INIT");
        Log.d(TAG, "authLogin: SERVER: "+ CONFIG.SERVER);
        mUserApiInterface.getUser(username,password).enqueue(new Callback<UserModelJSONPlaceholder>() {
            @Override
            public void onResponse(Call<UserModelJSONPlaceholder> call, Response<UserModelJSONPlaceholder> response) {
                if(response.isSuccessful()){
                    UserModelJSONPlaceholder r = response.body();
                    userModelLiveData.postValue(response.body());
                }else{
                    Log.d(TAG, "onResponse: FAILED. "+response.errorBody());
                }
            }

            @Override
            public void onFailure(Call<UserModelJSONPlaceholder> call, Throwable t) {
                Log.d(TAG, "onFailure: "+t.getMessage());
            }
        });
    }

    public LiveData<UserModelJSONPlaceholder> getUserModelLiveData() {
        if(userModelLiveData == null)
            userModelLiveData = new MutableLiveData<>();

        return userModelLiveData;
    }
}

你的问题是你让 UserRepository 是 Singleton 实例并始终保持 userModelLiveData 的值 修复它的简单方法将方法更改为此

public LiveData<UserModelJSONPlaceholder> getUserModelLiveData() {
        userModelLiveData = new MutableLiveData<>();
        return userModelLiveData;
}