代码改变世界

一个App架构例子分析--UI层使用MVP模式;各层之间使用Otto实现通信

2015-05-17 10:42  ttylinux  阅读(1033)  评论(0编辑  收藏  举报

一、这个App整体的架构划分:

 

分为四大模块:
 
1.app模块
2.common模块
3.domain模块
4.model模块
 
 
app模块的依赖:
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile project(':domain')
...
}
它依赖domain,领域层模块。在app模块中,应用了MVP模式,把一个activity中的View和Presenter划分掉。
 
domain模块的依赖:
dependencies {
    compile project (':common')
    compile project (':model')
...
}
它依赖model模块。领域逻辑代码放在这个模块;需要获取数据,获取数据的实现代码则放在module模块;它依赖common,通用的功能,整个应用共用的代码,放在common模块中。
 
 
model模块的依赖:
dependencies {
    compile project(':common')
....
}
这个模块只依赖common模块。model模块提供数据获取,修改功能。
 
common模块的依赖:
dependencies {
    compile 'com.squareup:otto:1.3.5'
    compile 'com.google.dagger:dagger:2.0'
    compile 'org.glassfish:javax.annotation:10.0-b28'
}
它不依赖domain,app,model模块。它使用第三方类库,来给其它模块提供功能。使用Dagger依赖注入框架,进行依赖注入;使用otto类库,来实现总线方式的通信。
 
二、整个执行流程简要分析
 
app模块:
MoviesActivity,MoviesPresenter。
 
domain模块:
ConfigurationUsecase, GetMoviesUsecaseController。
 
module模块:
RestMovieSource。
 
模块之间的通信,协作使用Bus总线来实现。比如,module模块,接受了数据查询的请求,查询完毕之后,它就通过总线post出去;然后,app模块或者domain模块,使用总线订阅了某个事件,那么订阅该事件的方法就会被回调。
 
 
三、依赖注入框架,注入流程
 
1.依赖注入流程
在MoviesActivity中,声明了一个带有注解@Inject的成员,@Inject MoviesPresenter mMoviesPresenter。这就表明当前类需要注入一个依赖mMoviesPresenter。
 
2.在MoviesActivity中,执行方法initializeDependencyInjector():
private void initializeDependencyInjector() {

MoviesApp app = (MoviesApp) getApplication();

DaggerBasicMoviesUsecasesComponent.builder()
     .appComponent(app.getAppComponent())
     .basicMoviesUsecasesModule(new BasicMoviesUsecasesModule())
     .build().inject(this);
}

package com.hackvg.android.di.components;

import com.hackvg.android.di.modules.BasicMoviesUsecasesModule;
import com.hackvg.android.di.scopes.PerActivity;
import com.hackvg.android.views.activities.MoviesActivity;

import dagger.Component;

@PerActivity
@Component(dependencies = AppComponent.class, modules = BasicMoviesUsecasesModule.class)
public interface BasicMoviesUsecasesComponent {

void inject (MoviesActivity moviesActivity);
}

}

 

initializeDependencyInjector()方法,会生成所有相关的依赖,根据一个对象图生成依赖。编译该项目,Dagger会为BasicMoviesUsecasesComponent生成一个类DaggerBasicMoviesUsecasesComponent。在创建了Component实例后,传入需要的外部参数,AppComponent.class,BasicMoviesUsecasesModule.class,然后,再调用其中的inject方法就可以了。
 
@PerActivity注解表明该Component的存在的范围与当前Activity一致。
 
Dagger生成Component中的依赖的流程:
1.BasicMoviesUsecasesModule,描述了依赖 ConfigurationUsecase, ConfigurationUsecase的生成

package com.hackvg.android.di.modules;

import com.hackvg.domain.ConfigurationUsecase;
import com.hackvg.domain.ConfigurationUsecaseController;
import com.hackvg.domain.GetMoviesUsecase;
import com.hackvg.domain.GetMoviesUsecaseController;
import com.hackvg.model.rest.RestMovieSource;
import com.squareup.otto.Bus;

import dagger.Module;
import dagger.Provides;

@Module
public class BasicMoviesUsecasesModule {

@Provides ConfigurationUsecase provideConfigurationUsecase (Bus bus, RestMovieSource moviesSource) {
     return new ConfigurationUsecaseController(moviesSource, bus);
}

@Provides GetMoviesUsecase provideMoviesUsecase (Bus bus, RestMovieSource movieSource) {
      return new GetMoviesUsecaseController(movieSource, bus);
}
}

2.生成上述两个依赖,需要提供参数Bus, RestMovieSource,那么,根据Dagger规定,这两个参数也要执行依赖注入。这两个依赖由AppComponent.Class来提供:
该AppComponent实例是单例的,它提供了两个依赖的生成Bus, RestMovieSource。
 
AppComponent:

package com.hackvg.android.di.components;


import com.hackvg.android.di.modules.ApplicationModule;
import com.hackvg.android.di.modules.DomainModule;
import com.hackvg.model.rest.RestMovieSource;
import com.squareup.otto.Bus;

import javax.inject.Singleton;

import dagger.Component;

@Singleton
@Component(modules = {
ApplicationModule.class,
DomainModule.class,
})

public interface AppComponent {

Bus bus();
RestMovieSource restMovieSource();
}

DomainModule:描述了依赖Bus,RestMoviesSource的生成。

package com.hackvg.android.di.modules;

import com.hackvg.model.rest.RestMovieSource;
import com.squareup.otto.Bus;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

@Module
public class DomainModule {

@Provides @Singleton Bus provideBus () {
return new Bus();
}

@Provides @Singleton RestMovieSource provideDataSource (Bus bus) { return new RestMovieSource(bus); }

}

 
参考资料:
https://github.com/saulmm/Material-Movies