安卓 MVVM 仓库和视图模型问题

huangapple go评论66阅读模式
英文:

Android MVVM Repository and ViewModel Question

问题

我刚刚开始使用MVVM模式当我尝试进行登录时遇到了一些问题以下是我的代码

**1. 登录服务**

```java
public interface LoginService {
    @FormUrlEncoded
    @POST("user/login")
    Call<JsonObject> validateLogin(@Field("phoneNum") String phoneNum, @Field("password") String password);
}

2. 仓库(Repository)

public class LoginRepository {
    private static final String TAG = "LoginRepository";
    private static LoginRepository instance;

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

    public MutableLiveData<JsonObject> getLoginMessage(String phoneNum, String password) {
        final MutableLiveData<JsonObject> message = new MutableLiveData<>();
        LoginService service = RetrofitClass.getLoginService();
        Call<JsonObject> call = service.validateLogin(phoneNum, password);
        call.enqueue(new Callback<JsonObject>() {
            @Override
            public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
                if (response.isSuccessful()) {
                    JsonObject info = response.body();
                    message.setValue(info);
                }
            }

            @Override
            public void onFailure(Call<JsonObject> call, Throwable t) {
                Log.d(TAG, "fail!");
                message.setValue(null);
            }
        });
        return message;
    }
}

3. 视图模型(ViewModel)

方法 queryRepo 用于使用手机号和密码请求登录服务。当用户点击登录按钮时会使用该方法。

public class LoginViewModel extends ViewModel {
    private static final String TAG = "UserProfileViewModel";

    private LoginRepository mLoginRepository;

    private MutableLiveData<JsonObject> message = new MutableLiveData<>();

    public void queryRepo(String phoneNum, String password) {
        this.message = mLoginRepository.getLoginMessage(phoneNum, password);
    }

    public LiveData<JsonObject> getMessage() {
        return message;
    }
}

4. 活动(Activity)
登录

public class LoginActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = "LoginActivity";

    private TextView mForgetPswTv, mRegisterTv;
    private EditText mPhoneEdt, mPasswordEdt;
    private QMUIRoundButton mLoginBtn;
    private ProgressBar mProgressBar;

    private LoginViewModel mLoginViewModel;

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

        getSupportActionBar().hide();
        setContentView(R.layout.activity_login);
        initView();
        bindOperation();
        mLoginViewModel = new ViewModelProvider(this).get(LoginViewModel.class);
        mLoginViewModel.getMessage().observe(this, new Observer<JsonObject>() {
            @Override
            public void onChanged(JsonObject jsonObject) {
                if (jsonObject != null) {
                    mProgressBar.setVisibility(View.GONE);
                    mPasswordEdt.setText(jsonObject.toString());
                } else Log.d(TAG, "null");
            }
        });
    }

    private void initView() {
        mProgressBar = (ProgressBar) findViewById(R.id.progress_circular_movie_article);
        mForgetPswTv = findViewById(R.id.forget_psw_tv);
        mRegisterTv = findViewById(R.id.register_tv);
        mLoginBtn = findViewById(R.id.login_btn);
        mPhoneEdt = findViewById(R.id.phone_edt);
        mPasswordEdt = findViewById(R.id.password_edt);
    }

    private void bindOperation() {
        mForgetPswTv.setOnClickListener(LoginActivity.this);
        mRegisterTv.setOnClickListener(LoginActivity.this);
        mLoginBtn.setOnClickListener(v -> {
            mLoginViewModel.queryRepo(mPhoneEdt.getText().toString(), mPasswordEdt.getText().toString());
        });
    }
}

我认为代码写得很清楚,但我真的不知道为什么它不起作用。当我点击登录按钮时,this.message.getValue() 会变成 null。我是否遗漏了重要的内容?实际上,如果我不初始化 message,第一次调用 queryRepo 是有效的,但一旦 message 被赋值,如果我再次调用 queryRepomessage.getValue() 就会变成 null。


<details>
<summary>英文:</summary>
I have just start my MVVM pattern. And when I do the login, I have some problems. Here is my code.
**1. login service**
```java
public interface LoginService {
@FormUrlEncoded
@POST(&quot;user/login&quot;)
Call&lt;JsonObject&gt; validateLogin(@Field(&quot;phoneNum&quot;) String phoneNum, @Field(&quot;password&quot;) String password);
}

2. Repository

public class LoginRepository {
    private static final String TAG = &quot;LoginRepository&quot;;
    private static LoginRepository instance;

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

    public MutableLiveData&lt;JsonObject&gt; getLoginMessage(String phoneNum, String password) {
        final MutableLiveData&lt;JsonObject&gt; message = new MutableLiveData&lt;&gt;();
        LoginService service = RetrofitClass.getLoginService();
        Call&lt;JsonObject&gt; call = service.validateLogin(phoneNum, password);
        call.enqueue(new Callback&lt;JsonObject&gt;() {
            @Override
            public void onResponse(Call&lt;JsonObject&gt; call, Response&lt;JsonObject&gt; response) {
                if (response.isSuccessful()) {
                    JsonObject info = response.body();
                    message.setValue(info);
                }
            }

            @Override
            public void onFailure(Call&lt;JsonObject&gt; call, Throwable t) {
                Log.d(TAG, &quot;fail!&quot;);
                message.setValue(null);
            }
        });
        return message;
    }
}

3. viewmodel

the method queryRepo is to request login service using phoneNum and password. And it will be used when user click the login button.

public class LoginViewModel extends ViewModel {
    private static final String TAG = &quot;UserProfileViewModel&quot;;

    private LoginRepository mLoginRepository;

    private MutableLiveData&lt;JsonObject&gt; message = new MutableLiveData&lt;&gt;();

    public void queryRepo(String phoneNum, String password) {
        this.message = mLoginRepository.getLoginMessage(phoneNum, password);
    }

    public LiveData&lt;JsonObject&gt; getMessage() {
        return message;
    }
}

4. Activity
login

public class LoginActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = &quot;LoginActivity&quot;;

    private TextView mForgetPswTv, mRegisterTv;
    private EditText mPhoneEdt, mPasswordEdt;
    private QMUIRoundButton mLoginBtn;
    private ProgressBar mProgressBar;

    private LoginViewModel mLoginViewModel;

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

        getSupportActionBar().hide();
        setContentView(R.layout.activity_login);
        initView();
        bindOperation();
        mLoginViewModel = new ViewModelProvider(this).get(LoginViewModel.class);
        mLoginViewModel.getMessage().observe(this, new Observer&lt;JsonObject&gt;() {
            @Override
            public void onChanged(JsonObject jsonObject) {
                if (jsonObject != null) {
                    mProgressBar.setVisibility(View.GONE);
                    mPasswordEdt.setText(jsonObject.toString());
                } else Log.d(TAG, &quot;null&quot;);
            }
        });


    }


    private void initView() {
        mProgressBar = (ProgressBar) findViewById(R.id.progress_circular_movie_article);
        mForgetPswTv = findViewById(R.id.forget_psw_tv);//忘记密码
        mRegisterTv = findViewById(R.id.register_tv);//立即注册
        mLoginBtn = findViewById(R.id.login_btn);
        mPhoneEdt = findViewById(R.id.phone_edt);
        mPasswordEdt = findViewById(R.id.password_edt);
    }


    private void bindOperation() {
        mForgetPswTv.setOnClickListener(LoginActivity.this);
        mRegisterTv.setOnClickListener(LoginActivity.this);
        mLoginBtn.setOnClickListener(v -&gt; {
            mLoginViewModel.queryRepo(mPhoneEdt.getText().toString(), mPasswordEdt.getText().toString());
        });
    }


}

I think it's clear, but I really don't know why it doesn't work, When I touch the login button, this.message.getValue() will change to null. is there something important that I missed?
actually, if I don't initialize the message, the first time I call queryRepo is fine, but once the message is assigned a value, if I call queryRepo again, message.getValue() will be null.

答案1

得分: 1

我终于成功了,就像下面这样。

mLoginBtn.setOnClickListener(v -> {
    mLoginViewModel.queryRepo(mPhoneEdt.getText().toString(), mPasswordEdt.getText().toString());
    mLoginViewModel.getMessage().observe(this, new Observer<JsonObject>() {
        @Override
        public void onChanged(JsonObject jsonObject) {
            if (jsonObject != null) {
                mProgressBar.setVisibility(View.GONE);
                mPasswordEdt.setText(jsonObject.toString());
            } else Log.d(TAG, "null");
        }
    });
});

再次感谢大家!

英文:

I finally made it, just as below.

mLoginBtn.setOnClickListener(v -&gt; {
    mLoginViewModel.queryRepo(mPhoneEdt.getText().toString(), mPasswordEdt.getText().toString());
    mLoginViewModel.getMessage().observe(this, new Observer&lt;JsonObject&gt;() {
            @Override
            public void onChanged(JsonObject jsonObject) {
                if (jsonObject != null) {
                    mProgressBar.setVisibility(View.GONE);
                    mPasswordEdt.setText(jsonObject.toString());
                } else Log.d(TAG, &quot;null&quot;);
            }
        });
});

Thanks for everybody again!

答案2

得分: 0

尝试在按钮的点击监听器中观察实时数据,就像这样,并进行检查:

mLoginBtn.setOnClickListener(v -> {
    mLoginViewModel.queryRepo(mPhoneEdt.getText().toString(), mPasswordEdt.getText().toString());

    mLoginViewModel.getMessage().observe(this, new Observer<JsonObject>() {
        @Override
        public void onChanged(JsonObject jsonObject) {
            if (jsonObject != null) {
                mProgressBar.setVisibility(View.GONE);
                mPasswordEdt.setText(jsonObject.toString());
            } else Log.d(TAG, "null");
        }
    });
});
英文:

Try to Observe live data into Button OnClickListener, Like this, and check

 mLoginBtn.setOnClickListener(v -&gt; {
mLoginViewModel.queryRepo(mPhoneEdt.getText().toString(), mPasswordEdt.getText().toString());
mLoginViewModel.getMessage().observe(this, new Observer&lt;JsonObject&gt;() {
@Override
public void onChanged(JsonObject jsonObject) {
if (jsonObject != null) {
mProgressBar.setVisibility(View.GONE);
mPasswordEdt.setText(jsonObject.toString());
} else Log.d(TAG, &quot;null&quot;);
}
});
});

huangapple
  • 本文由 发表于 2020年8月18日 09:22:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/63460589.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定