记录

本文介绍了一个使用Kotlin实现的MVP架构应用案例,详细解释了如何通过依赖注入管理组件间的交互,包括电影和火车数据的加载过程。文章还探讨了不同依赖注入方式的选择,并展示了如何利用RxJava进行异步数据处理。
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)

}
类似的


最后贴下效果图,很美。









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值