MVVM - 很难理解如何在 Clean Architecture 中创建域层
MVVM - Having a hard time understanding how to create the Domain layer in Clean Architecture
我正在尝试学习 MVVM 以使我的应用程序的架构更加简洁。但是我很难掌握如何为我的应用程序创建“域”层。
目前我的项目结构是这样的:
我的View
是activity。我的 ViewModel
有一个 activity 可以调用的 public 方法。一旦调用 ViewModel 中的方法,它就会调用我的 Repository
class 中的方法,该方法执行网络调用,然后 returns 将数据返回给 ViewModel。然后,我更新 ViewModel 中的 LiveData
,以便更新 Activity 的 UI。
这是我对如何向结构添加 Domain
层感到困惑的地方。我已经阅读了很多关于域层的 Whosebug 答案和博客,它们大多都告诉您从 ViewModel
中删除所有业务逻辑并制作一个纯 Java/Kotlin class.
所以不用
View --> ViewModel --> Repository
我会从 ViewModel
与 Domain
class 通信,而 Domain
class 会与 Repository
通信?
View --> ViewModel --> Domain --> Repository
我正在使用 RxJava
从我的 ViewModel
呼叫 Repository
class。
@HiltViewModel
public class PostViewModel extends ViewModel {
private static final String TAG = "PostViewModel";
private final List<Post> listPosts = new ArrayList<>();
private final MutableLiveData<List<Post>> getPostsLiveData = new MutableLiveData<>();
private final MutableLiveData<Boolean> centerProgressLiveData = new MutableLiveData<>();
private final MainRepository repository;
@Inject
public PostViewModel(MainRepository repository) {
this.repository = repository;
getSubredditPosts();
}
public void getSubredditPosts() {
repository.getSubredditPosts()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Response>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
centerProgressLiveData.setValue(true);
}
@Override
public void onNext(@NonNull Response response) {
Log.d(TAG, "onNext: Query called");
centerProgressLiveData.setValue(false);
listPosts.clear();
listPosts.addAll(response.getData().getChildren());
getPostsLiveData.setValue(listPosts);
}
@Override
public void onError(@NonNull Throwable e) {
Log.e(TAG, "onError: getPosts", e);
centerProgressLiveData.setValue(false);
}
@Override
public void onComplete() {
}
});
}
public class MainRepository {
private final MainService service;
@Inject
public MainRepository(MainService service) {
this.service = service;
}
public Observable<Response> getSubredditPosts() {
return service.getSubredditPosts();
}
}
有人可以给我举个例子说明我该怎么做吗?我在这里迷路了
我在尝试找出域层时遇到了困难。
最常见的例子是用例。
您的视图模型不会直接与存储库通信。正如你所说,你需要viewmodel》domain》repository
您可能会认为用例是对每个存储库方法的抽象。
假设您有一个 Movies Repository,您可以在其中为电影列表调用一个方法,为电影详细信息调用另一个方法,为相关电影调用第三个方法。
每个方法都有一个用例。
它的目的是什么?
假设您有一个与 Detail Viewmodel 通信的 DetailActivity。您的视图模型不需要知道所有存储库(在详细信息屏幕上调用电影列表方法的目的是什么?)。因此,您的 DetailViewModel 所知道的只是“Detail Usecase”(调用存储库中的 Detail 方法)。
Google几小时前更新了架构文档,快来看看吧!
https://android-developers.googleblog.com/2021/12/rebuilding-our-guide-to-app-architecture.html?m=1&s=09
PS:用例不是特殊的 android class,您不需要固有任何行为(如片段、activity、视图模型...)这是一个正常的 class 将接收存储库作为参数。
你会得到类似的东西:
视图模型:
function createPost(post Post){
createUseCase.create(post)
}
用例
function createPost(post Post): Response {
return repository.create(post)
}
我花了很多时间尝试通过阅读大量博客和 Whosebug 答案来学习如何使用 RxJava
添加域层,但是所有这些都缺少响应的转换api 调用您想要在屏幕上显示的内容(例如,如果后端 return 是用户名 dave123
而您想要显示 by dave123
)。
我终于想通了,秘诀是在 UseCase
class 中使用 RxJava .map()
运算符。我还决定将 RxJava 调用保留在我的 ViewModel
.
中
所以在我的 Repository
class 中,我有一个调用 Api 和 return 类型 Single<Response>
的方法。这是 Api return 的原始 json 数据。
public class MainRepository {
private final MainService service;
private final PostDao postDao;
@Inject
public MainRepository(MainService service, PostDao postDao) {
this.service = service;
this.postDao = postDao;
}
public Single<Response> getResponse() {
return service.getSubredditPosts();
}
}
在我的 GetPostsUseCase
class 中,我从 MainRepository
调用 getResponse()
方法并通过对其执行业务逻辑来更改 Response
(我想在 UI 上显示的内容。在这种情况下,我将 String
“by”添加到用户名)
我遇到很多麻烦的秘密或部分 understanding/figuring 是如何转换 Single<>
中的类型。我使用 .map()
运算符更改 return 类型并将 Response
过滤为 List<Post>
public class GetPostsUseCase {
private final MainRepository mainRepository;
@Inject
public GetPostsUseCase(MainRepository mainRepository) {
this.mainRepository = mainRepository;
}
public Single<List<Post>> getSubredditPosts(){
return mainRepository.getResponse().map(response ->
getPostsFromResponse(response.getData().getChildren())
);
}
private List<Post> getPostsFromResponse(List<Child> listChildren) {
List<Post> listPosts = new ArrayList<>();
for (Child child : listChildren) {
Post post = child.getPost();
post.setCreatedBy("by " + post.getUsername());
listPosts.add(post);
}
return listPosts;
}
}
这就是我的 ViewModel
的样子
public class PostViewModel extends ViewModel {
private static final String TAG = "PostViewModel";
private final List<Post> listPosts = new ArrayList<>();
private final MutableLiveData<List<Post>> getPostsLiveData = new MutableLiveData<>();
private final MutableLiveData<Boolean> centerProgressLiveData = new MutableLiveData<>();
private final GetPostsUseCase getPostsUseCase;
@Inject
public PostViewModel(GetPostsUseCase getPostsUseCase) {
this.getPostsUseCase = getPostsUseCase;
getSubredditPosts();
}
public void getSubredditPosts() {
getPostsUseCase.getSubredditPosts()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<List<Post>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
centerProgressLiveData.setValue(true);
}
@Override
public void onSuccess(@NonNull List<Post> list) {
Log.d(TAG, "onNext: Query called");
centerProgressLiveData.setValue(false);
listPosts.clear();
listPosts.addAll(list);
getPostsLiveData.setValue(listPosts);
}
@Override
public void onError(@NonNull Throwable e) {
centerProgressLiveData.setValue(false);
}
});
}
我找不到任何包含此类示例的博文或答案。希望这对正在努力学习如何使用 MVVM、Hilt、RXJava 和域层实现干净架构的任何人有所帮助。
如果我确实做错了什么或认为架构不干净,请告诉我。
我正在尝试学习 MVVM 以使我的应用程序的架构更加简洁。但是我很难掌握如何为我的应用程序创建“域”层。
目前我的项目结构是这样的:
我的View
是activity。我的 ViewModel
有一个 activity 可以调用的 public 方法。一旦调用 ViewModel 中的方法,它就会调用我的 Repository
class 中的方法,该方法执行网络调用,然后 returns 将数据返回给 ViewModel。然后,我更新 ViewModel 中的 LiveData
,以便更新 Activity 的 UI。
这是我对如何向结构添加 Domain
层感到困惑的地方。我已经阅读了很多关于域层的 Whosebug 答案和博客,它们大多都告诉您从 ViewModel
中删除所有业务逻辑并制作一个纯 Java/Kotlin class.
所以不用
View --> ViewModel --> Repository
我会从 ViewModel
与 Domain
class 通信,而 Domain
class 会与 Repository
通信?
View --> ViewModel --> Domain --> Repository
我正在使用 RxJava
从我的 ViewModel
呼叫 Repository
class。
@HiltViewModel
public class PostViewModel extends ViewModel {
private static final String TAG = "PostViewModel";
private final List<Post> listPosts = new ArrayList<>();
private final MutableLiveData<List<Post>> getPostsLiveData = new MutableLiveData<>();
private final MutableLiveData<Boolean> centerProgressLiveData = new MutableLiveData<>();
private final MainRepository repository;
@Inject
public PostViewModel(MainRepository repository) {
this.repository = repository;
getSubredditPosts();
}
public void getSubredditPosts() {
repository.getSubredditPosts()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Response>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
centerProgressLiveData.setValue(true);
}
@Override
public void onNext(@NonNull Response response) {
Log.d(TAG, "onNext: Query called");
centerProgressLiveData.setValue(false);
listPosts.clear();
listPosts.addAll(response.getData().getChildren());
getPostsLiveData.setValue(listPosts);
}
@Override
public void onError(@NonNull Throwable e) {
Log.e(TAG, "onError: getPosts", e);
centerProgressLiveData.setValue(false);
}
@Override
public void onComplete() {
}
});
}
public class MainRepository {
private final MainService service;
@Inject
public MainRepository(MainService service) {
this.service = service;
}
public Observable<Response> getSubredditPosts() {
return service.getSubredditPosts();
}
}
有人可以给我举个例子说明我该怎么做吗?我在这里迷路了
我在尝试找出域层时遇到了困难。 最常见的例子是用例。
您的视图模型不会直接与存储库通信。正如你所说,你需要viewmodel》domain》repository
您可能会认为用例是对每个存储库方法的抽象。
假设您有一个 Movies Repository,您可以在其中为电影列表调用一个方法,为电影详细信息调用另一个方法,为相关电影调用第三个方法。
每个方法都有一个用例。
它的目的是什么?
假设您有一个与 Detail Viewmodel 通信的 DetailActivity。您的视图模型不需要知道所有存储库(在详细信息屏幕上调用电影列表方法的目的是什么?)。因此,您的 DetailViewModel 所知道的只是“Detail Usecase”(调用存储库中的 Detail 方法)。
Google几小时前更新了架构文档,快来看看吧! https://android-developers.googleblog.com/2021/12/rebuilding-our-guide-to-app-architecture.html?m=1&s=09
PS:用例不是特殊的 android class,您不需要固有任何行为(如片段、activity、视图模型...)这是一个正常的 class 将接收存储库作为参数。
你会得到类似的东西:
视图模型:
function createPost(post Post){
createUseCase.create(post)
}
用例
function createPost(post Post): Response {
return repository.create(post)
}
我花了很多时间尝试通过阅读大量博客和 Whosebug 答案来学习如何使用 RxJava
添加域层,但是所有这些都缺少响应的转换api 调用您想要在屏幕上显示的内容(例如,如果后端 return 是用户名 dave123
而您想要显示 by dave123
)。
我终于想通了,秘诀是在 UseCase
class 中使用 RxJava .map()
运算符。我还决定将 RxJava 调用保留在我的 ViewModel
.
所以在我的 Repository
class 中,我有一个调用 Api 和 return 类型 Single<Response>
的方法。这是 Api return 的原始 json 数据。
public class MainRepository {
private final MainService service;
private final PostDao postDao;
@Inject
public MainRepository(MainService service, PostDao postDao) {
this.service = service;
this.postDao = postDao;
}
public Single<Response> getResponse() {
return service.getSubredditPosts();
}
}
在我的 GetPostsUseCase
class 中,我从 MainRepository
调用 getResponse()
方法并通过对其执行业务逻辑来更改 Response
(我想在 UI 上显示的内容。在这种情况下,我将 String
“by”添加到用户名)
我遇到很多麻烦的秘密或部分 understanding/figuring 是如何转换 Single<>
中的类型。我使用 .map()
运算符更改 return 类型并将 Response
过滤为 List<Post>
public class GetPostsUseCase {
private final MainRepository mainRepository;
@Inject
public GetPostsUseCase(MainRepository mainRepository) {
this.mainRepository = mainRepository;
}
public Single<List<Post>> getSubredditPosts(){
return mainRepository.getResponse().map(response ->
getPostsFromResponse(response.getData().getChildren())
);
}
private List<Post> getPostsFromResponse(List<Child> listChildren) {
List<Post> listPosts = new ArrayList<>();
for (Child child : listChildren) {
Post post = child.getPost();
post.setCreatedBy("by " + post.getUsername());
listPosts.add(post);
}
return listPosts;
}
}
这就是我的 ViewModel
的样子
public class PostViewModel extends ViewModel {
private static final String TAG = "PostViewModel";
private final List<Post> listPosts = new ArrayList<>();
private final MutableLiveData<List<Post>> getPostsLiveData = new MutableLiveData<>();
private final MutableLiveData<Boolean> centerProgressLiveData = new MutableLiveData<>();
private final GetPostsUseCase getPostsUseCase;
@Inject
public PostViewModel(GetPostsUseCase getPostsUseCase) {
this.getPostsUseCase = getPostsUseCase;
getSubredditPosts();
}
public void getSubredditPosts() {
getPostsUseCase.getSubredditPosts()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<List<Post>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
centerProgressLiveData.setValue(true);
}
@Override
public void onSuccess(@NonNull List<Post> list) {
Log.d(TAG, "onNext: Query called");
centerProgressLiveData.setValue(false);
listPosts.clear();
listPosts.addAll(list);
getPostsLiveData.setValue(listPosts);
}
@Override
public void onError(@NonNull Throwable e) {
centerProgressLiveData.setValue(false);
}
});
}
我找不到任何包含此类示例的博文或答案。希望这对正在努力学习如何使用 MVVM、Hilt、RXJava 和域层实现干净架构的任何人有所帮助。
如果我确实做错了什么或认为架构不干净,请告诉我。