从MVP迁移到MVVM,并尝试从网络教程中学习。
一些教程指出ViewModel类不应对Activity或View(android.view.View)类有任何引用。
但是在一些教程中,我已经看到Views用于ViewModel类和Activity中,以使用ViewModel启动其他Activity。 For example:
import android.arch.lifecycle.ViewModel;
import android.support.annotation.NonNull;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import com.journaldev.androidmvvmbasics.interfaces.LoginResultCallback;
import com.journaldev.androidmvvmbasics.model.User;
public class LoginViewModel extends ViewModel {
private User user;
private LoginResultCallback mDataListener;
LoginViewModel(@NonNull final LoginResultCallback loginDataListener) {
mDataListener = loginDataListener;
user = new User("", "");
}
public TextWatcher getEmailTextWatcher() {
return new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
user.setEmail(editable.toString());
}
};
}
public TextWatcher getPasswordTextWatcher() {
return new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
user.setPassword(editable.toString());
}
};
}
public void onLoginClicked(@NonNull final View view) {
checkDataValidity();
}
private void checkDataValidity() {
if (user.isInputDataValid())
mDataListener.onSuccess("Login was successful");
else {
mDataListener.onError("Email or Password not valid");
}
}
}
Another one和View.OnClickListener
public class PostViewModel extends BaseObservable {
private Context context;
private Post post;
private Boolean isUserPosts;
public PostViewModel(Context context, Post post, boolean isUserPosts) {
this.context = context;
this.post = post;
this.isUserPosts = isUserPosts;
}
public String getPostScore() {
return String.valueOf(post.score) + context.getString(R.string.story_points);
}
public String getPostTitle() {
return post.title;
}
public Spannable getPostAuthor() {
String author = context.getString(R.string.text_post_author, post.by);
SpannableString content = new SpannableString(author);
int index = author.indexOf(post.by);
if (!isUserPosts) content.setSpan(new UnderlineSpan(), index, post.by.length() + index, 0);
return content;
}
public int getCommentsVisibility() {
return post.postType == Post.PostType.STORY && post.kids == null ? View.GONE : View.VISIBLE;
}
public View.OnClickListener onClickPost() {
return new View.OnClickListener() {
@Override
public void onClick(View v) {
Post.PostType postType = post.postType;
if (postType == Post.PostType.JOB || postType == Post.PostType.STORY) {
launchStoryActivity();
} else if (postType == Post.PostType.ASK) {
launchCommentsActivity();
}
}
};
}
public View.OnClickListener onClickAuthor() {
return new View.OnClickListener() {
@Override
public void onClick(View v) {
context.startActivity(UserActivity.getStartIntent(context, post.by));
}
};
}
public View.OnClickListener onClickComments() {
return new View.OnClickListener() {
@Override
public void onClick(View v) {
launchCommentsActivity();
}
};
}
private void launchStoryActivity() {
context.startActivity(ViewStoryActivity.getStartIntent(context, post));
}
private void launchCommentsActivity() {
context.startActivity(CommentsActivity.getStartIntent(context, post));
}
}
Another one和活动参考
public class UserProfileViewModel {
/* ------------------------------ Constructor */
private Activity activity;
/* ------------------------------ Constructor */
UserProfileViewModel(@NonNull Activity activity) {
this.activity = activity;
}
/* ------------------------------ Main method */
/**
* On profile image clicked
*
* @param userName name of user
*/
public void onProfileImageClicked(@NonNull String userName) {
Bundle bundle = new Bundle();
bundle.putString("USERNAME", userName);
Intent intent = new Intent(activity, UserDetailActivity.class);
intent.putExtras(bundle);
activity.startActivity(intent);
}
/**
* @param editable editable
* @param userProfileModel the model of user profile
*/
public void userNameTextChange(@NonNull Editable editable,
@NonNull UserProfileModel userProfileModel) {
userProfileModel.setUserName(editable.toString());
Log.e("ViewModel", userProfileModel.getUserName());
}
}
ViewModel类包含Android和View类是否可以, 这样对单元测试不好吗?
自定义视图模型类应扩展哪个类? ViewModel
或
BaseObservable/Observable
?
答案 0 :(得分:2)
警告:ViewModel绝不能引用视图,生命周期或任何可能包含对活动上下文的引用的类。
这是因为ViewModel
保留了配置更改。假设您有一项活动,并且旋转设备。该活动被杀死,并创建了一个新实例。如果将视图放在视图模型中,那么该活动将不会被垃圾回收,因为这些视图持有对先前活动的引用。同样,视图本身将被重新创建,但是您将旧视图保留在viewmodel中。基本上,不要在视图模型中放置任何视图,上下文,活动。
如果您想使用展示带有存储库模式的MVVM的简单示例,则可以在gitlab上查看我的示例存储库:https://gitlab.com/rafid059/music-api-test
Google也提供了一个很好的示例:https://github.com/googlesamples/android-sunflower/