First refactor to use dagger on presentation layer.

This commit is contained in:
Fernando Cejas
2015-03-01 20:50:53 +01:00
parent f81fcf855d
commit d80a9d78f6
12 changed files with 169 additions and 103 deletions

View File

@ -6,14 +6,18 @@ package com.fernandocejas.android10.sample.data.cache.serializer;
import com.fernandocejas.android10.sample.data.entity.UserEntity;
import com.google.gson.Gson;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* Class user as Serializer/Deserializer for user entities.
*/
@Singleton
public class JsonSerializer {
private final Gson gson = new Gson();
@Inject
public JsonSerializer() {
//empty
}

View File

@ -9,13 +9,17 @@ import com.fernandocejas.android10.sample.domain.User;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* Mapper class used to transform {@link UserEntity} (in the data layer) to {@link User} in the
* domain layer.
*/
@Singleton
public class UserEntityDataMapper {
@Inject
public UserEntityDataMapper() {
//empty
}

View File

@ -9,6 +9,7 @@ import com.fernandocejas.android10.sample.data.cache.UserCache;
import com.fernandocejas.android10.sample.data.entity.mapper.UserEntityJsonMapper;
import com.fernandocejas.android10.sample.data.net.RestApi;
import com.fernandocejas.android10.sample.data.net.RestApiImpl;
import javax.inject.Inject;
/**
* Factory that creates different implementations of {@link UserDataStore}.
@ -18,6 +19,7 @@ public class UserDataStoreFactory {
private final Context context;
private final UserCache userCache;
@Inject
public UserDataStoreFactory(Context context, UserCache userCache) {
if (context == null || userCache == null) {
throw new IllegalArgumentException("Constructor parameters cannot be null!!!");

View File

@ -9,6 +9,8 @@ import com.fernandocejas.android10.sample.presentation.internal.di.components.Ap
import com.fernandocejas.android10.sample.presentation.internal.di.components.Dagger_ApplicationComponent;
import com.fernandocejas.android10.sample.presentation.internal.di.modules.ApplicationModule;
import com.fernandocejas.android10.sample.presentation.view.activity.BaseActivity;
import com.fernandocejas.android10.sample.presentation.view.fragment.UserDetailsFragment;
import com.fernandocejas.android10.sample.presentation.view.fragment.UserListFragment;
/**
* Android Main Application
@ -32,4 +34,12 @@ public class AndroidApplication extends Application {
public void inject(BaseActivity baseActivity) {
this.applicationComponent.inject(baseActivity);
}
public void inject(UserListFragment userListFragment) {
this.applicationComponent.inject(userListFragment);
}
public void inject(UserDetailsFragment userDetailsFragment) {
this.applicationComponent.inject(userDetailsFragment);
}
}

View File

@ -7,13 +7,18 @@ package com.fernandocejas.android10.sample.presentation.internal.di.components;
import com.fernandocejas.android10.sample.presentation.AndroidApplication;
import com.fernandocejas.android10.sample.presentation.internal.di.modules.ActivityModule;
import com.fernandocejas.android10.sample.presentation.internal.di.modules.ApplicationModule;
import com.fernandocejas.android10.sample.presentation.internal.di.modules.UserModule;
import com.fernandocejas.android10.sample.presentation.view.activity.BaseActivity;
import com.fernandocejas.android10.sample.presentation.view.fragment.UserDetailsFragment;
import com.fernandocejas.android10.sample.presentation.view.fragment.UserListFragment;
import dagger.Component;
import javax.inject.Singleton;
@Singleton
@Component(modules = {ApplicationModule.class, ActivityModule.class})
@Component(modules = {ApplicationModule.class, ActivityModule.class, UserModule.class})
public interface ApplicationComponent {
void inject(AndroidApplication androidApplication);
void inject(BaseActivity activity);
void inject(UserListFragment userListFragment);
void inject(UserDetailsFragment userDetailsFragment);
}

View File

@ -0,0 +1,91 @@
/**
* Copyright (C) 2015 android10.org. All rights reserved.
* @author Fernando Cejas (the android10 coder)
*/
package com.fernandocejas.android10.sample.presentation.internal.di.modules;
import android.content.Context;
import com.fernandocejas.android10.sample.data.cache.FileManager;
import com.fernandocejas.android10.sample.data.cache.UserCache;
import com.fernandocejas.android10.sample.data.cache.UserCacheImpl;
import com.fernandocejas.android10.sample.data.cache.serializer.JsonSerializer;
import com.fernandocejas.android10.sample.data.entity.mapper.UserEntityDataMapper;
import com.fernandocejas.android10.sample.data.executor.JobExecutor;
import com.fernandocejas.android10.sample.data.repository.UserDataRepository;
import com.fernandocejas.android10.sample.data.repository.datasource.UserDataStoreFactory;
import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
import com.fernandocejas.android10.sample.domain.interactor.GetUserDetailsUseCase;
import com.fernandocejas.android10.sample.domain.interactor.GetUserDetailsUseCaseImpl;
import com.fernandocejas.android10.sample.domain.interactor.GetUserListUseCase;
import com.fernandocejas.android10.sample.domain.interactor.GetUserListUseCaseImpl;
import com.fernandocejas.android10.sample.domain.repository.UserRepository;
import com.fernandocejas.android10.sample.presentation.UIThread;
import com.fernandocejas.android10.sample.presentation.mapper.UserModelDataMapper;
import com.fernandocejas.android10.sample.presentation.presenter.UserDetailsPresenter;
import com.fernandocejas.android10.sample.presentation.presenter.UserListPresenter;
import dagger.Module;
import dagger.Provides;
@Module
public class UserModule {
@Provides ThreadExecutor provideThreadExecutor() {
return JobExecutor.getInstance();
}
@Provides PostExecutionThread providePostExecutionThread() {
return UIThread.getInstance();
}
@Provides JsonSerializer provideJsonSerializer() {
return new JsonSerializer();
}
@Provides FileManager provideFileManager() {
return FileManager.getInstance();
}
@Provides UserCache provideUserCache(Context context, JsonSerializer jsonSerializer,
FileManager fileManager, ThreadExecutor threadExecutor) {
return UserCacheImpl.getInstance(context, jsonSerializer, fileManager, threadExecutor);
}
@Provides UserDataStoreFactory provideUserDataStoreFactory(Context context, UserCache userCache) {
return new UserDataStoreFactory(context, userCache);
}
@Provides UserEntityDataMapper provideUserEntityDataMapper() {
return new UserEntityDataMapper();
}
@Provides UserRepository provideUserRepository(UserDataStoreFactory userDataStoreFactory,
UserEntityDataMapper userEntityDataMapper) {
return UserDataRepository.getInstance(userDataStoreFactory, userEntityDataMapper);
}
@Provides GetUserListUseCase provideGetUserListUseCase(UserRepository userRepository,
ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) {
return new GetUserListUseCaseImpl(userRepository, threadExecutor, postExecutionThread);
}
@Provides UserModelDataMapper provideUserModelDataMapper() {
return new UserModelDataMapper();
}
@Provides UserListPresenter provideUserListPresenter(GetUserListUseCase userListUseCase,
UserModelDataMapper userModelDataMapper) {
return new UserListPresenter(userListUseCase, userModelDataMapper);
}
@Provides GetUserDetailsUseCase provideGetUserDetailsUseCase(UserRepository userRepository,
ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) {
return new GetUserDetailsUseCaseImpl(userRepository,
threadExecutor, postExecutionThread);
}
@Provides UserDetailsPresenter provideUserDetailsPresenter(GetUserDetailsUseCase getUserDetailsUseCase,
UserModelDataMapper userModelDataMapper) {
return new UserDetailsPresenter(getUserDetailsUseCase, userModelDataMapper);
}
}

View File

@ -9,13 +9,17 @@ import com.fernandocejas.android10.sample.presentation.model.UserModel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* Mapper class used to transform {@link User} (in the domain layer) to {@link UserModel} in the
* presentation layer.
*/
@Singleton
public class UserModelDataMapper {
@Inject
public UserModelDataMapper() {
//empty
}

View File

@ -4,6 +4,7 @@
*/
package com.fernandocejas.android10.sample.presentation.presenter;
import android.support.annotation.NonNull;
import com.fernandocejas.android10.sample.domain.User;
import com.fernandocejas.android10.sample.domain.exception.ErrorBundle;
import com.fernandocejas.android10.sample.domain.interactor.GetUserDetailsUseCase;
@ -21,20 +22,21 @@ public class UserDetailsPresenter implements Presenter {
/** id used to retrieve user details */
private int userId;
private final UserDetailsView viewDetailsView;
private UserDetailsView viewDetailsView;
private final GetUserDetailsUseCase getUserDetailsUseCase;
private final UserModelDataMapper userModelDataMapper;
public UserDetailsPresenter(UserDetailsView userDetailsView,
GetUserDetailsUseCase getUserDetailsUseCase, UserModelDataMapper userModelDataMapper) {
if (userDetailsView == null || getUserDetailsUseCase == null || userModelDataMapper == null) {
throw new IllegalArgumentException("Constructor parameters cannot be null!!!");
}
this.viewDetailsView = userDetailsView;
public UserDetailsPresenter(GetUserDetailsUseCase getUserDetailsUseCase,
UserModelDataMapper userModelDataMapper) {
this.getUserDetailsUseCase = getUserDetailsUseCase;
this.userModelDataMapper = userModelDataMapper;
}
public void setView(@NonNull UserDetailsView view) {
this.viewDetailsView = view;
}
@Override public void resume() {}
@Override public void pause() {}

View File

@ -4,6 +4,7 @@
*/
package com.fernandocejas.android10.sample.presentation.presenter;
import android.support.annotation.NonNull;
import com.fernandocejas.android10.sample.domain.User;
import com.fernandocejas.android10.sample.domain.exception.ErrorBundle;
import com.fernandocejas.android10.sample.domain.interactor.GetUserListUseCase;
@ -12,27 +13,32 @@ import com.fernandocejas.android10.sample.presentation.mapper.UserModelDataMappe
import com.fernandocejas.android10.sample.presentation.model.UserModel;
import com.fernandocejas.android10.sample.presentation.view.UserListView;
import java.util.Collection;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* {@link Presenter} that controls communication between views and models of the presentation
* layer.
*/
@Singleton
public class UserListPresenter implements Presenter {
private final UserListView viewListView;
private UserListView viewListView;
private final GetUserListUseCase getUserListUseCase;
private final UserModelDataMapper userModelDataMapper;
public UserListPresenter(UserListView userListView, GetUserListUseCase getUserListUserCase,
@Inject
public UserListPresenter(GetUserListUseCase getUserListUserCase,
UserModelDataMapper userModelDataMapper) {
if (userListView == null || getUserListUserCase == null || userModelDataMapper == null) {
throw new IllegalArgumentException("Constructor parameters cannot be null!!!");
}
this.viewListView = userListView;
this.getUserListUseCase = getUserListUserCase;
this.userModelDataMapper = userModelDataMapper;
}
public void setView(@NonNull UserListView view) {
this.viewListView = view;
}
@Override public void resume() {}
@Override public void pause() {}

View File

@ -7,6 +7,7 @@ package com.fernandocejas.android10.sample.presentation.view.fragment;
import android.app.Fragment;
import android.os.Bundle;
import android.widget.Toast;
import com.fernandocejas.android10.sample.presentation.AndroidApplication;
/**
* Base {@link android.app.Fragment} class for every fragment in this application.
@ -16,15 +17,8 @@ public abstract class BaseFragment extends Fragment {
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
initializePresenter();
}
/**
* Initializes the {@link com.fernandocejas.android10.sample.presentation.presenter.Presenter}
* for this fragment in a MVP pattern used to architect the application presentation layer.
*/
abstract void initializePresenter();
/**
* Shows a {@link android.widget.Toast} message.
*
@ -33,4 +27,13 @@ public abstract class BaseFragment extends Fragment {
protected void showToastMessage(String message) {
Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
}
/**
* Get the Android Main Application.
*
* @return singleton {@link com.fernandocejas.android10.sample.presentation.AndroidApplication}
*/
protected AndroidApplication getApplication() {
return (AndroidApplication)getActivity().getApplication();
}
}

View File

@ -15,26 +15,12 @@ import android.widget.TextView;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.OnClick;
import com.fernandocejas.android10.sample.data.cache.FileManager;
import com.fernandocejas.android10.sample.data.cache.UserCache;
import com.fernandocejas.android10.sample.data.cache.UserCacheImpl;
import com.fernandocejas.android10.sample.data.cache.serializer.JsonSerializer;
import com.fernandocejas.android10.sample.data.entity.mapper.UserEntityDataMapper;
import com.fernandocejas.android10.sample.data.executor.JobExecutor;
import com.fernandocejas.android10.sample.data.repository.UserDataRepository;
import com.fernandocejas.android10.sample.data.repository.datasource.UserDataStoreFactory;
import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
import com.fernandocejas.android10.sample.domain.interactor.GetUserDetailsUseCase;
import com.fernandocejas.android10.sample.domain.interactor.GetUserDetailsUseCaseImpl;
import com.fernandocejas.android10.sample.domain.repository.UserRepository;
import com.fernandocejas.android10.sample.presentation.R;
import com.fernandocejas.android10.sample.presentation.UIThread;
import com.fernandocejas.android10.sample.presentation.mapper.UserModelDataMapper;
import com.fernandocejas.android10.sample.presentation.model.UserModel;
import com.fernandocejas.android10.sample.presentation.presenter.UserDetailsPresenter;
import com.fernandocejas.android10.sample.presentation.view.UserDetailsView;
import com.fernandocejas.android10.sample.presentation.view.component.AutoLoadImageView;
import javax.inject.Inject;
/**
* Fragment that shows details of a certain user.
@ -44,7 +30,8 @@ public class UserDetailsFragment extends BaseFragment implements UserDetailsView
private static final String ARGUMENT_KEY_USER_ID = "org.android10.ARGUMENT_USER_ID";
private int userId;
private UserDetailsPresenter userDetailsPresenter;
@Inject UserDetailsPresenter userDetailsPresenter;
@InjectView(R.id.iv_cover) AutoLoadImageView iv_cover;
@InjectView(R.id.tv_fullname) TextView tv_fullname;
@ -69,6 +56,7 @@ public class UserDetailsFragment extends BaseFragment implements UserDetailsView
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.getApplication().inject(this);
this.initialize();
}
@ -96,28 +84,9 @@ public class UserDetailsFragment extends BaseFragment implements UserDetailsView
this.userDetailsPresenter.pause();
}
@Override void initializePresenter() {
// All these dependency initialization could have been avoided using a
// dependency injection framework. But in this case are used this way for
// LEARNING EXAMPLE PURPOSE.
ThreadExecutor threadExecutor = JobExecutor.getInstance();
PostExecutionThread postExecutionThread = UIThread.getInstance();
JsonSerializer userCacheSerializer = new JsonSerializer();
UserCache userCache = UserCacheImpl.getInstance(getActivity(), userCacheSerializer,
FileManager.getInstance(), threadExecutor);
UserDataStoreFactory userDataStoreFactory =
new UserDataStoreFactory(this.getContext(), userCache);
UserEntityDataMapper userEntityDataMapper = new UserEntityDataMapper();
UserRepository userRepository = UserDataRepository.getInstance(userDataStoreFactory,
userEntityDataMapper);
GetUserDetailsUseCase getUserDetailsUseCase = new GetUserDetailsUseCaseImpl(userRepository,
threadExecutor, postExecutionThread);
UserModelDataMapper userModelDataMapper = new UserModelDataMapper();
this.userDetailsPresenter =
new UserDetailsPresenter(this, getUserDetailsUseCase, userModelDataMapper);
private void initialize() {
this.userDetailsPresenter.setView(this);
this.userId = getArguments().getInt(ARGUMENT_KEY_USER_ID);
}
@Override public void renderUser(UserModel user) {
@ -156,13 +125,6 @@ public class UserDetailsFragment extends BaseFragment implements UserDetailsView
return getActivity().getApplicationContext();
}
/**
* Initializes fragment's private members.
*/
private void initialize() {
this.userId = getArguments().getInt(ARGUMENT_KEY_USER_ID);
}
/**
* Loads all users.
*/

View File

@ -16,28 +16,14 @@ import android.widget.RelativeLayout;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.OnClick;
import com.fernandocejas.android10.sample.data.cache.FileManager;
import com.fernandocejas.android10.sample.data.cache.UserCache;
import com.fernandocejas.android10.sample.data.cache.UserCacheImpl;
import com.fernandocejas.android10.sample.data.cache.serializer.JsonSerializer;
import com.fernandocejas.android10.sample.data.entity.mapper.UserEntityDataMapper;
import com.fernandocejas.android10.sample.data.executor.JobExecutor;
import com.fernandocejas.android10.sample.data.repository.UserDataRepository;
import com.fernandocejas.android10.sample.data.repository.datasource.UserDataStoreFactory;
import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
import com.fernandocejas.android10.sample.domain.interactor.GetUserListUseCase;
import com.fernandocejas.android10.sample.domain.interactor.GetUserListUseCaseImpl;
import com.fernandocejas.android10.sample.domain.repository.UserRepository;
import com.fernandocejas.android10.sample.presentation.R;
import com.fernandocejas.android10.sample.presentation.UIThread;
import com.fernandocejas.android10.sample.presentation.mapper.UserModelDataMapper;
import com.fernandocejas.android10.sample.presentation.model.UserModel;
import com.fernandocejas.android10.sample.presentation.presenter.UserListPresenter;
import com.fernandocejas.android10.sample.presentation.view.UserListView;
import com.fernandocejas.android10.sample.presentation.view.adapter.UsersAdapter;
import com.fernandocejas.android10.sample.presentation.view.adapter.UsersLayoutManager;
import java.util.Collection;
import javax.inject.Inject;
/**
* Fragment that shows a list of Users.
@ -51,7 +37,7 @@ public class UserListFragment extends BaseFragment implements UserListView {
void onUserClicked(final UserModel userModel);
}
private UserListPresenter userListPresenter;
@Inject UserListPresenter userListPresenter;
@InjectView(R.id.rv_users) RecyclerView rv_users;
@InjectView(R.id.rl_progress) RelativeLayout rl_progress;
@ -72,6 +58,12 @@ public class UserListFragment extends BaseFragment implements UserListView {
}
}
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.getApplication().inject(this);
this.initialize();
}
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
@ -97,27 +89,8 @@ public class UserListFragment extends BaseFragment implements UserListView {
this.userListPresenter.pause();
}
@Override protected void initializePresenter() {
// All these dependency initialization could have been avoided using a
// dependency injection framework. But in this case are used this way for
// LEARNING EXAMPLE PURPOSE.
ThreadExecutor threadExecutor = JobExecutor.getInstance();
PostExecutionThread postExecutionThread = UIThread.getInstance();
JsonSerializer userCacheSerializer = new JsonSerializer();
UserCache userCache = UserCacheImpl.getInstance(getActivity(), userCacheSerializer,
FileManager.getInstance(), threadExecutor);
UserDataStoreFactory userDataStoreFactory =
new UserDataStoreFactory(this.getContext(), userCache);
UserEntityDataMapper userEntityDataMapper = new UserEntityDataMapper();
UserRepository userRepository = UserDataRepository.getInstance(userDataStoreFactory,
userEntityDataMapper);
GetUserListUseCase getUserListUseCase = new GetUserListUseCaseImpl(userRepository,
threadExecutor, postExecutionThread);
UserModelDataMapper userModelDataMapper = new UserModelDataMapper();
this.userListPresenter = new UserListPresenter(this, getUserListUseCase, userModelDataMapper);
private void initialize() {
this.userListPresenter.setView(this);
}
private void setupUI() {