Android实践 — ikan项目(三)

/ 0评 / 1

  本篇简述下项目的domain层,domain层在项目中担负的职责是处理presentation层下发的数据存取过程。因为data层仅是对数据存取并不包含对数据进一步处理工作,所以对数据处理应是项目的业务逻辑层职责。
  在domain层,不关心数据的来源,只需定义Repository接口然后data层实现该接口实现即可,先看项目中FeedRepository的定义:

interface FeedRepository {

fun getHomeFeeds(feedParamProvider: FeedParamProvider): Observable<List<FeedEntity>>
    // xxx
}

FeedRepository在data层的实现FeedDataRepository如下:

@Singleton
class FeedDataRepository @Inject constructor(private var feedDataStoreFactory: FeedDataStoreFactory)
    : FeedRepository {

    override fun getHomeFeeds(feedParamProvider: FeedParamProvider) = feedDataStoreFactory
            .createCloudDataStore()
            .getHomeFeeds(feedParamProvider)
    // xxx
}

在data层需要确定数据具体来源,这里是通过DataStoreFactory创建相应的DataStore实例,继而通过DataStore实例获取数据。FeedDataStoreFactory提供创建CloudFeedDataStore和LocalFeedDataStore实例的方法,看下实现代码:

@Singleton
class FeedDataStoreFactory @Inject internal constructor(private val apiConnector: Connector,
                                                        private val tokenInterceptor: TokenInterceptor,
                                                        private val feedCache: FeedCache) {

    fun createCloudDataStore(): FeedDataStore = CloudFeedDataStore(apiConnector, tokenInterceptor, feedCache)

    fun createLocalDataStore(): FeedDataStore = LocalFeedDataStore(feedCache)
}

在domain层通过repository接口和data层建立连接,但是创建连接的过程并不包含具体业务逻辑。基于职责从data层获取的数据并不一定等于presentation需要的数据,比如首页的视频列表,产品的需求是用户屏蔽的视频不做显示,需要在domain层就需要将屏蔽的视频过滤掉。其次为了与domain层与presentation层进行交互,项目在domain层为每个Repository创建对应的管理类,比如FeedRepositoryManager,具体代码如下:

@Singleton
class FeedRepositoryManager @Inject constructor(threadExecutor: ThreadExecutor,
                                                postExecutionThread: PostExecutionThread,
                                                private var feedDataRepository: FeedDataRepository) :
        BaseRepositoryManager(threadExecutor, postExecutionThread) {

    fun executeGetHomeFeeds(feedParamProvider: FeedParamProvider, subscriber: Observer<PagerEntity<List<FeedEntity>>>) {
        feedDataRepository.getHomeFeeds(feedParamProvider)
                .subscribeOn(Schedulers.from(threadExecutor))
                .observeOn(postExecutionThread.scheduler)
                .subscribe(subscriber)
    }

    // xxx
}

如你所见,executeGetHomeFeeds是间接通过FeedRepository获取数据比较好理解,然后subscribeOn限定订阅的线程,observeOn限定观察的线程,两者分别依赖threadExecutor和postExecutionThread对象,对此稍作讲解,先看下代码:

@Singleton
class DefaultExecutor @Inject constructor() : ThreadExecutor {

    private val workQueue: BlockingQueue<Runnable>
    private val threadPoolExecutor: ThreadPoolExecutor
    private val threadFactory: ThreadFactory

    init {
        workQueue = LinkedBlockingQueue()
        threadFactory = DefaultThreadFactory()
        threadPoolExecutor = ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE,
                KEEP_ALIVE_TIME.toLong(), KEEP_ALIVE_TIME_UNIT, this.workQueue, this.threadFactory)
    }

    override fun execute(runnable: Runnable) {
        threadPoolExecutor.execute(runnable)
    }

    private class DefaultThreadFactory : ThreadFactory {

        private var counter = 0

        override fun newThread(runnable: Runnable): Thread {
            return Thread(runnable, THREAD_NAME + counter++)
        }

        companion object {

            private const val THREAD_NAME = "android_thread_"
        }
    }

    companion object {

        private const val CORE_POOL_SIZE = 5
        private const val MAX_POOL_SIZE = 20
        private const val KEEP_ALIVE_TIME = 10

        private val KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS
    }
}

简述下该类的实现:首先初始化BlockingQueue对象,其负责生产的线程不断的制造新对象并插入到阻塞队列中,直到达到这个队列的上限值。队列达到上限值之后生产线程将会被阻塞,直到消费的线程对这个队列进行消费。初始化ThreadFactory对象,其负责创建线程对象。之后ThreadPoolExecutor通过BlockingQueue对象、ThreadFactory对象、设定核心线程数、设定线程池所能容纳的最大线程数、设定非核心线程的闲置超时时间、设定keepAliveTime的单位共同创建一个线程池。其实就是一个线程池的配置过程 0.0

PostExecutionThread实现类UIThread的代码如下:

@Singleton
class UIThread @Inject constructor() : PostExecutionThread {

    override val scheduler: Scheduler
        get() = AndroidSchedulers.mainThread()
}

UIThread比较容易理解,直接使用AndroidSchedulers.mainThread(),不再赘述。控制流向和数据流向入下图所示:

最后,再次明确下domain层职责是衔接data层以获取源数据,同时通过RepositoryManager向presentation层提供所需要的数据。

发表评论

电子邮件地址不会被公开。 必填项已用*标注