class OneAct : BaseAct(), MovieView, TrainView
kotlin 可以多继承接口,但不能多继承类,和 Java 一样
override fun injectDependencies() {
movieRepository = ComponentsHolder.movieComponent.getRepository()
trainRepository = ComponentsHolder.trainComponent.getRepository()
}基类里写了依赖注入的方法。
为什么不用 "inject" 方法?
因为无论 Movie 还是 Train 组件都无法提供完整的依赖,inject 必须提供所有。
inject 和这种最早的 get 方式没有高低之分。
@Inject lateinit var movieRepository: MovieRepository
private val moviePresenter by lazy { MoviePresenter(this, movieRepository) }
@Inject lateinit var trainRepository: TrainRepository
private val trainPresenter by lazy { TrainPresenter(this, trainRepository) }
MVP 的 M 和 P, V 是 OneAct 本身
因为我觉得把 Activity 这种有生命周期的东西作为依赖不太好,就用这种写法了。
override fun init() {
// init recyclerView
with(recyclerView) {
layoutManager = LinearLayoutManager(this@OneAct)
adapter = movieAdapter
}
// movie interaction
moviePresenter.onViewCreated()
// train interaction
trainPresenter.onViewCreated()
}MVP 里面一个隐藏的概念就是 interaction ,交互是一切的开端,事件驱动的源头。 override fun onDestroy() {
super.onDestroy()
moviePresenter.onViewDestroyed()
trainPresenter.onViewDestroyed()
}
销毁也可以看做交互,去释放数据库资源,网络资源,取消请求等等。
abstract class BasePresenter : Presenter {
protected val subscriptions = CompositeDisposable()
// 生命周期结束时 dispose
override fun onViewDestroyed(){
subscriptions.dispose()
}
}
class TrainPresenter(private var view: TrainView, private var repository: TrainRepository) : BasePresenter() {
override fun onViewCreated() {
subscriptions += loadTrains()
}
private val name = "G4"
private fun loadTrains() = repository.get(name).subscribe { view.render(it) }
}如果用了 rxjava,那就是 dispose。class TrainRepositoryImpl(private val api: TrainApi) : TrainRepository {
override fun get(name: String): Observable<TrainInfo> {
return api.get(BuildConfig.APP_KEY, name)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map { it.result.train_info }
}
}class MovieRepositoryImpl(private val box: Box<Movie>) : MovieRepository {
override fun get(): Observable<List<Movie>> = RxQuery.observable(box.query().build())
}无论是数据库还是网络,都被抽象成近乎一致的处理方式。object ComponentsHolder {
private lateinit var app: App
fun init(app: App) {
ComponentsHolder.app = app
}
private val appComponent by lazy {
DaggerAppComponent.builder()
.networkModule(NetworkModule())
.boxModule(BoxModule(app))
.build()
}
val movieComponent by lazy {
appComponent.getMovieComponent()
}
val trainComponent by lazy {
appComponent.getTrainComponent()
}
}依赖注入器的持有者,koltin 有多种实现单列的方式。
@Module
class NetworkModule {
@AppScope
@Provides
fun okHttpClient(): OkHttpClient = OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
// .addInterceptor(makeHeadersInterceptor())
.build()
private val trainBaseUrl = "http://apis.juhe.cn/train/"
@AppScope
@Provides
@Named(value = "train")
fun retrofit(client: OkHttpClient): Retrofit = Retrofit.Builder()
.baseUrl(trainBaseUrl)
.client(client)
.addConverterFactory(GsonConverterFactory.create(Gson()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
}网络模块提供了 train retrofit
@Module
class TrainModule {
@TrainScope
@Provides
fun api(@Named(value = "train") retrofit: Retrofit): TrainApi = retrofit.create(TrainApi::class.java)
@TrainScope
@Provides
fun repository(api: TrainApi): TrainRepository = TrainRepositoryImpl(api)
}train模块从 parent 组件 app 组件获取了 train retrofit,分离和继承得到了很好的实现。@Module
class MovieModule {
@MovieScope
@Provides
fun box(boxStore: BoxStore): Box<Movie> = boxStore.boxFor(Movie::class.java)
@MovieScope
@Provides
fun repository(box: Box<Movie>): MovieRepository = MovieRepositoryImpl(box)
}
类似的
最后贴下效果图,很美。
本文介绍了一个使用Kotlin实现的MVP架构应用案例,详细解释了如何通过依赖注入管理组件间的交互,包括电影和火车数据的加载过程。文章还探讨了不同依赖注入方式的选择,并展示了如何利用RxJava进行异步数据处理。
3528

被折叠的 条评论
为什么被折叠?



