zoukankan      html  css  js  c++  java
  • 例子Architecting Android…The clean way?----代码分析

    Presention层:
     
    整个应用启动的时候,就执行依赖的初始化。编译项目之后,Dagger依赖框架使用ApplicationComponent生成一个DaggerApplicationCOmponent。
     
    1. 首先进行依赖的生成
    在Application中,调用initializeInjector()就会促使Dagger框架进行依赖生成。
     
    ApplicationComponent
    对其它Component提供Context,ThreadExecutor,PostExecutionThread,UserRepository依赖
    /**
    * A component whose lifetime is the life of the application.
    */
    @Singleton // Constraints this component to one-per-application or unscoped bindings.
    @Component(modules = ApplicationModule.class)
    public interface ApplicationComponent {
    void inject(BaseActivity baseActivity);

    //Exposed to sub-graphs.
    Context context();
    ThreadExecutor threadExecutor();
    PostExecutionThread postExecutionThread();
    UserRepository userRepository();
    }

    ApplicationModule
    /**
    * Dagger module that provides objects which will live during the application lifecycle.
    */
    @Module
    public class ApplicationModule {
    private final AndroidApplication application;

    public ApplicationModule(AndroidApplication application) {
    this.application = application;
    }

    @Provides @Singleton Context provideApplicationContext() {
    return this.application;
    }

    @Provides @Singleton Navigator provideNavigator() {
    return new Navigator();
    }

    @Provides @Singleton ThreadExecutor provideThreadExecutor(JobExecutor jobExecutor) {
    return jobExecutor;
    }

    @Provides @Singleton PostExecutionThread providePostExecutionThread(UIThread uiThread) {
    return uiThread;
    }

    @Provides @Singleton UserCache provideUserCache(UserCacheImpl userCache) {
    return userCache;
    }

    @Provides @Singleton UserRepository provideUserRepository(UserDataRepository userDataRepository) {
    return userDataRepository;
    }
    }
    在这个类中,提供了生成依赖的方法。
    需要参数的provide方法,参数也是通过Dagger依赖框架生成的。
    参数JobExecutor(data模块),UIThread(presentation模块),UserCacheImpl(data模块),UserDataRepository(data模块)生成的方式,是Dagger依赖框架调用相应类的构造方法实现的,而不是通过provide实现的。
    比如
    JobExecutor(data模块):
    public class JobExecutor implements ThreadExecutor {
      @Inject
      public JobExecutor() {
        this.workQueue = new LinkedBlockingQueue<>();
        this.threadFactory = new JobThreadFactory();
        this.threadPoolExecutor = new ThreadPoolExecutor(INITIAL_POOL_SIZE, MAX_POOL_SIZE,
            KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT, this.workQueue, this.threadFactory);
      }
    ...
    }
    属于data模块的:参数JobExecutor(data模块),UserCacheImpl(data模块),UserDataRepository(data模块)
     
    Application:
    /**
    * Android Main Application
    */
    public class AndroidApplication extends Application {

    private ApplicationComponent applicationComponent;

    @Override public void onCreate() {
    super.onCreate();
    this.initializeInjector();
    }

    private void initializeInjector() {
    this.applicationComponent = DaggerApplicationComponent.builder()
    .applicationModule(new ApplicationModule(this))
    .build();
    }

    public ApplicationComponent getApplicationComponent() {

    return this.applicationComponent;
    }
    }

    2.MainActivity实现
     
    使用ButterKnife对View对象进行注入,从而无需写findViewById。
     
    2.1继承BaseActivity,BaseActivity的实现
     
    A.
    声明了一个带有Inject注解的成员Navigator
    在onCreate方法中,将Navigator依赖注入到当前实例。
     
    B.
    提供三个protected方法,一个是用来添加fragment到当前界面的某个位置;两个是用来进行依赖注入的。
     
    2.2 MainActivity执行流程
    用户点击R.id.btn_LoadData Button,就会跳转到界面UserListActivity.
     
    3.UserListActivity实现
     
    A.
    界面加载,使用UserListFragment。
     
    B.
    在onCreate方法中,执行UserComponent包含的依赖初始化。
      private void initializeInjector() {
        this.userComponent = DaggerUserComponent.builder()
            .applicationComponent(getApplicationComponent())
            .activityModule(getActivityModule())
            .build();
      }
     
    UserComponent生成的依赖,被注入到UserListFragment,UserDetailsFragment。UserListFragment,UserDetailsFragment调用UserComponent实例的inject方法。
    UserComponent如下:
    可以注入到UserListFragment,UserDetailsFragment的依赖是GetUserListUseCase,GetUserDetailsUseCase。
    ,
    /**
    * A scope {@link com.fernandocejas.android10.sample.presentation.internal.di.PerActivity} component.
    * Injects user specific Fragments.
    */
    @PerActivity
    @Component(dependencies = ApplicationComponent.class, modules = {ActivityModule.class, UserModule.class})
    public interface UserComponent extends ActivityComponent {
    void inject(UserListFragment userListFragment);
    void inject(UserDetailsFragment userDetailsFragment);
    }

    /**
    * A base component upon which fragment's components may depend.
    * Activity-level components should extend this component.
    *
    * Subtypes of ActivityComponent should be decorated with annotation:
    * {@link com.fernandocejas.android10.sample.presentation.internal.di.PerActivity}
    */
    @PerActivity
    @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
    public interface ActivityComponent {
    //Exposed to sub-graphs.
    Activity activity();
    }
    /**
    * A module to wrap the Activity state and expose it to the graph.
    */
    @Module
    public class ActivityModule {
    private final Activity activity;

    public ActivityModule(Activity activity) {
    this.activity = activity;
    }

    /**
    * Expose the activity to dependents in the graph.
    */
    @Provides @PerActivity Activity activity() {
    return this.activity;
    }
    }
    /**
    * Dagger module that provides user related collaborators.
    */
    @Module
    public class UserModule {

    private int userId = -1;

    public UserModule() {}

    public UserModule(int userId) {
    this.userId = userId;
    }

    @Provides @PerActivity @Named("userList") UseCase provideGetUserListUseCase(
    GetUserListUseCase getUserListUseCase) {
    return getUserListUseCase;
    }

    @Provides @PerActivity @Named("userDetails") UseCase provideGetUserDetailsUseCase(
    UserRepository userRepository, ThreadExecutor threadExecutor,
    PostExecutionThread postExecutionThread) {
    return new GetUserDetailsUseCase(userId, userRepository, threadExecutor, postExecutionThread);
    }
    }
    4.UserListFragment的实现
     
    A.
    UserListFragment实现UserListView接口,用来表示View层。
    B.
    UserListFragment跟宿主Activity的通信,通过UserListFragment声明的接口UserListListener来实现。
    @Override public void onAttach(Activity activity) {
    super.onAttach(activity);
    if (activity instanceof UserListListener) {
    this.userListListener = (UserListListener) activity;
    }
    }
     
    C.
    当宿主Activity创建成功之后,回调方法:
    @Override public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    this.initialize();
    this.loadUserList();
    }
    在UserListFragment类中,使用Inject注解,声明了一个成员@Inject UserListPresenter userListPresenter;
    然后,调用UserComponent实例的方法inject,就可以将依赖userListPresenter注入到UserListFragment实例中。
    调用userListPresenter的方法setView,建立Presenter和View之间的关系。
    private void initialize() {
    this.getComponent(UserComponent.class).inject(this);
    this.userListPresenter.setView(this);
    }
    调用loadUserList方法,会加载所有用户数据。
    /**
    * Loads all users.
    */
    private void loadUserList() {
    this.userListPresenter.initialize();
    }
    界面的数据加载操作,都被封装在userListPresenter的initalize方法中。展示界面加载效果;执行获取数据操作;数据加载成功之后,显示对应的界面。这些都由userListPresenter来实现和控制。
     
    5.UserListPresenter
     
    A.
    调用构造方法,构造方法的参数,由Dagger注入。
    @Inject
    public UserListPresenter(@Named("userList") UseCase getUserListUserCase, UserModelDataMapper userModelDataMapper) {
    this.getUserListUseCase = getUserListUserCase;
    this.userModelDataMapper = userModelDataMapper;
    }
     
    B.
    提供initialize方法,供其它类调用。调用该方法,展示界面加载效果;获取所有用户数据。
    /**
    * Initializes the presenter by start retrieving the user list.
    */
    public void initialize() {
    this.loadUserList();
    }

    /**
    * Loads all users.
    */
    private void loadUserList() {
    this.hideViewRetry();
    this.showViewLoading();
    this.getUserList();
    }
    private void getUserList() {
    this.getUserListUseCase.execute(this); //这里使用到了domain层上的类,domain层提供用例类。一个用例类表示一个表示一个业务,在这里表示获取用户列表。

    }

    6.UserListPresenter和UseCase的协作
     
     
    UserListPresenter和UseCase的协作,使用
     
    The RxJava Android Module 框架
     
     
    1.UserListPresenter属于Presention层,它依赖domain层和data层。
     
    2.UseCase是domain层,它的实例是GetUserListUseCase,这个是由Presention层中的依赖定义包指定的,如下:
    com.fernandocejas.android10.sample.presentation.internal.di.modules.UserModule:
     
      @Provides @PerActivity @Named("userList") UseCase provideGetUserListUseCase(
          GetUserListUseCase getUserListUseCase) {
        return getUserListUseCase;
      }
     
    -----
    所以,GetUserListUseCase是必须是可注入的,要在其构造函数中添加@Inject注解。
     
    3.UserListPresenter和GetUserListUseCase,UserListPresenter是一个订阅者;这个订阅者订阅的流是CloudUserDataStore实例的方法getUseEntityList()产出来之后,经过映射的流,
    该流是长这个样子的:
     
      @Override public Observable<List<User>> getUsers() {
        //we always get all users from the cloud
        final UserDataStore userDataStore = this.userDataStoreFactory.createCloudDataStore();
        return userDataStore.getUserEntityList().map(userListEntityMapper);
      }
     
     
    总结牵涉到的类及所在的层:
     
    presentation层:UserListPresenter。
    domain层: GetUseerListUseCase,UseCase
    data层:UserDataRepository,CloudUserDataStore,UserDataStoreFactory
     
    presentation层依赖domain层和data层。
     
     
    7.整个项目使用到的框架技术
     
    1.Dagger依赖生成,定义依赖的生成规则。
    2.RxAndroid 响应式编程范式的应用,用事件流的方式来处理异步事件。
    3.okHttp,网络请求应用到该框架。
     
    8.整个项目阅读下来,可以学习到的东西
     
     
    1.使用依赖注入,一个实例包含其它实例,在获取其它实例的使用,使用依赖注入,不将其它实例的生成方式暴露出去。这样,使用者只关注使用,无需关注怎样实例化,其它实例实例化的过程对使用者隐藏掉。
     
    2.分层,分模块,这个要针对功能的含义来划分,根据关注点来划分。
    presentation层,我们只关注界面展示,我们在这一层里面,我们只需要关注界面展示方面的代码,我们只放界面展示代码在这一层上,还有依赖生成的代码。在这层,我们重点只关注界面代码,还有依赖生成的规则。
     
    domain层,领域层,用例层,从这个模块中包的命名就可以知道,它表示抽象程度高的业务,与系统平台无关的业务。在这个应用中,有两个业务,一个是获取用户列表,一个是获取用户的详细信息。
    在这一层,存放业务的实现代码。
    data层,数据获取,数据存储的实现代码放在这一层。
     
    层之间的依赖规则:
    presention层------>domain层-------获取数据---->data层
     

    参考资料:http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/
  • 相关阅读:
    linux 程序无缘无故推出 没有core文件 broken pipe Resource temporarily unavailable
    inline元素、block元素、inline-block元素
    转:Linux环境变量设置方法总结 PATH、LD_LIBRARY_PATH
    转: 深入理解信号槽机制
    【模式识别与机器学习】——PART2 机器学习——统计学习基础——Regularized Linear Regression
    【模式识别与机器学习】——PART2 机器学习——统计学习基础——2.Bias variance tradeoff
    关于GPU你必须知道的基本知识
    【计算机算法设计与分析】——5.5 0/1背包问题
    【模式识别与机器学习】——5.2 形式语言理论和句法模式识别
    【模式识别与机器学习】——句法模式识别5.1集合论中的关系运算
  • 原文地址:https://www.cnblogs.com/ttylinux/p/4541107.html
Copyright © 2011-2022 走看看