Skip to content

Can I use this architecture in real project? #55

Closed
@sitexa

Description

@sitexa

This is not an issue.
It's really a clearly defined architecture. A lot of technologies are introduced into the architecture, I 've never used them before, Dagger, RxAndroid, Butternife, etc.
But I am little confused by the fine defined UseCases, for example , GetUserList, GetUserDetails for user usecases. If I want to do user search, I must define SearchUser usecase, I want to do CRUD for many many Objects, I need to write hands of usecases separately.
And, I'm not sure how to pass parameters to the usecases. For example, GetUserDetails, pass the userId by constructor in UserModule. How can I pass a search critera to SearchUser UseCase? A Map? Or a Model? Is there another way instead of constructor?

Thank you very much for any suggestion.

Activity

spirosoik

spirosoik commented on Oct 8, 2015

@spirosoik

Of course you can but you must use a few tools to make your life easier.

johnwatsondev

johnwatsondev commented on Oct 8, 2015

@johnwatsondev

@sitexa I have solved this problem. Here is a NOT elegant enough solution.

No callback function. Just pass your criteria through Varargs.

LoginPresenter.java

  private void performLogin(String userId, String pwd){
    Map<String, String> fields = new HashMap<>();
    fields.put("userId", userId);
    fields.put("pwd", pwd);

    userLoginCase.execute(new LoginSubscriber(), fields);
  }

UseCase.java

  protected abstract Observable buildUseCaseObservable (Object...param);

  public void execute(Subscriber useCaseSubscriber, Object...param){
    subscription = buildUseCaseObservable(param)
        .subscribeOn(Schedulers.from(threadExecutor))
        .observeOn(postExecutionThread.getScheduler())
        .lift(new OperatorSynchronousUnsubscribe())
        .subscribe(useCaseSubscriber);
  }

UserLoginCase.java

public class UserLoginCase extends UseCase {

  private final UserRepository userRepository;

  @Inject
  public UserLoginCase(UserRepository userRepository,
      ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) {
    super(threadExecutor, postExecutionThread);
    this.userRepository = userRepository;
  }

  @Override protected Observable buildUseCaseObservable(Object...param) {
    return this.userRepository.userLogin((Map<String, String>) param[0]);
  }
}

UserRepository.java

public interface UserRepository {
  Observable<User> userLogin(final Map<String, String> fields);
}

UserDataRepository.java

@Singleton public class UserDataRepository implements UserRepository {

  private final UserDataStoreFactory userDataStoreFactory;
  private final UserEntityDataMapper dataMapper;

  @Inject public UserDataRepository(UserDataStoreFactory dataStoreFactory,
      UserEntityDataMapper userEntityDataMapper) {
    this.userDataStoreFactory = dataStoreFactory;
    this.dataMapper = userEntityDataMapper;
  }

  @Override public Observable<User> userLogin(Map<String, String> fields) {
    final UserDataStore userDataStore = this.userDataStoreFactory.createCloudDataStore();
    return userDataStore.userLogin(fields).map(entity -> this.dataMapper.transform(entity));
  }
}

UserDataStore.java

public interface UserDataStore {
  Observable<UserEntity> userLogin(@NonNull final Map<String, String> fields);
}

CloudUserDataStore.java

public class CloudUserDataStore implements UserDataStore {
  private final RestApi restApi;

  public CloudUserDataStore(RestApi restApi) {
    this.restApi = restApi;
  }

  @Override public Observable<UserEntity> userLogin(@NonNull Map<String, String> fields) {
    return restApi.userLogin(fields);
  }
}

RestApi.java

public interface RestApi {
  Observable<UserEntity> userLogin(final Map<String, String> fields);
}

RestApi.java

public class RestApiImpl implements RestApi {
  private static RetrofitAPI RETROFIT_CLIENT;

  @Override public Observable<UserEntity> userLogin(final Map<String, String> fields) {
    return RETROFIT_CLIENT.userLogin(fields).timeout(REQUEST_TIMEOUT, TimeUnit.SECONDS);
  }
}

Please @me if you have any issue. Thanks.

sitexa

sitexa commented on Oct 9, 2015

@sitexa
Author

Thank you very much, @johnwatsondev .
It is a good approach I'd like to follow, but I don't know how to write the 'OperatorSynchronousUnsubscribe' class, would you please give that to me ?

Thanks.

sitexa

sitexa commented on Oct 9, 2015

@sitexa
Author

@spirosoik , I am glad to have your words.
But my life is not easy if you don't tell me what those tools are and what they can do work for me.

Thank you.

spirosoik

spirosoik commented on Oct 9, 2015

@spirosoik

@sitexa on of this example you will see that the data layer uses files. You can use ORMLite for database. Also for the API you can use Retrofit in order to get back Observables as a response.

johnwatsondev

johnwatsondev commented on Oct 9, 2015

@johnwatsondev

@sitexa It a approach that prevent memory leak. But it has a weakness as konmik said below.
qq20151009-0 2x
Reference:
ReactiveX/RxJava#3148
OperatorSynchronousUnsubscribe

There is a more elegant solution for preventing memory leak in Android. (Recommend)
https://github.com/trello/RxLifecycle

spirosoik

spirosoik commented on Oct 9, 2015

@spirosoik

@johnwatsondev cool thanks for the info.

sitexa

sitexa commented on Oct 9, 2015

@sitexa
Author

@johnwatsondev , it seems too difficult for me to get the point from the posts you referred. I need do some research on that topic.

sitexa

sitexa commented on Oct 9, 2015

@sitexa
Author

@spirosoik , thank you for your reply.
I do use OkHttp/Retrofit in the network layer under the data layer. My point is should I write many many usecases separately for each object, like CRUD.

johnwatsondev

johnwatsondev commented on Oct 10, 2015

@johnwatsondev

@sitexa I have used this architecture in real project.

As you said I have write some UseCase to do business stuff at the beginning. Eg:UserLoginCase,UserRegisterCase,UserSendVerifyCodeCase,UserForgetPasswordCase etc.

But i found they are belong to User Module.
So i created a UseCaseList which extends UseCase. Here is the SNAPSHOT:

public abstract class UseCaseList extends UseCase {

  //protected Subscription subscription1 = Subscriptions.empty();
  //protected Subscription subscription2 = Subscriptions.empty();
  //protected Subscription subscription3 = Subscriptions.empty();
  //protected Subscription subscription4 = Subscriptions.empty();

  protected Subscription subscription1;
  protected Subscription subscription2;
  protected Subscription subscription3;
  protected Subscription subscription4;

  protected CompositeSubscription mCompositeSubscription = new CompositeSubscription();

  protected UseCaseList(ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) {
    super(threadExecutor, postExecutionThread);
  }

  protected abstract Observable buildUseCaseObservable1(Object... param);
  protected abstract Observable buildUseCaseObservable2(Object... param);
  protected abstract Observable buildUseCaseObservable3(Object... param);
  protected abstract Observable buildUseCaseObservable4(Object... param);

  @Override public void execute(Subscriber useCaseSubscriber, Object... param) {
    super.execute(useCaseSubscriber, param);
    mCompositeSubscription.add(subscription);
  }

  public void execute1(Subscriber UseCaseSubscriber, Object... param) {
    subscription1 = buildUseCaseObservable1(param).subscribeOn(Schedulers.from(threadExecutor))
        .observeOn(postExecutionThread.getScheduler())
        .lift(new OperatorSynchronousUnsubscribe())
        .subscribe(UseCaseSubscriber);
    mCompositeSubscription.add(subscription1);
  }

  public void execute2(Subscriber UseCaseSubscriber, Object... param) {
    subscription2 = buildUseCaseObservable2(param).subscribeOn(Schedulers.from(threadExecutor))
        .observeOn(postExecutionThread.getScheduler())
        .lift(new OperatorSynchronousUnsubscribe())
        .subscribe(UseCaseSubscriber);
    mCompositeSubscription.add(subscription2);
  }

  public void execute3(Subscriber UseCaseSubscriber, Object... param) {
    subscription3 = buildUseCaseObservable3(param).subscribeOn(Schedulers.from(threadExecutor))
        .observeOn(postExecutionThread.getScheduler())
        .lift(new OperatorSynchronousUnsubscribe())
        .subscribe(UseCaseSubscriber);
    mCompositeSubscription.add(subscription3);
  }

  public void execute4(Subscriber UseCaseSubscriber, Object... param) {
    subscription4 = buildUseCaseObservable4(param).subscribeOn(Schedulers.from(threadExecutor))
        .observeOn(postExecutionThread.getScheduler())
        .lift(new OperatorSynchronousUnsubscribe())
        .subscribe(UseCaseSubscriber);
    mCompositeSubscription.add(subscription4);
  }

  @Override public void unsubscribe() {
    //super.unsubscribe();
    if (mCompositeSubscription.hasSubscriptions()) {
      mCompositeSubscription.unsubscribe();
    }
  }
}

Then My UserUseCaseList can extend UseCaseList and override buildUseCaseObservable method.

We can package some similar UseCase or in same Business Module together in my opinion. My code is just a simple idea.

I have realized that code is not elegant. It can be replace with Queue or other Data Structure. Maybe you could give me some refactor suggestion.

You can argue with me by email or QQ (503548433).

Thanks in advance!

sitexa

sitexa commented on Oct 10, 2015

@sitexa
Author

@johnwatsondev , added your QQ.

alexandru-calinoiu

alexandru-calinoiu commented on Oct 12, 2015

@alexandru-calinoiu

@johnwatsondev what is QQ?

johnwatsondev

johnwatsondev commented on Oct 13, 2015

@johnwatsondev

@alexandru-calinoiu Sorry about that.
QQ is a chinese IM software.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @alexandru-calinoiu@spirosoik@sitexa@johnwatsondev

        Issue actions

          Can I use this architecture in real project? · Issue #55 · android10/Android-CleanArchitecture