手把手教你搭建android模塊化項(xiàng)目框架(十三)——優(yōu)雅的處理渠道與rom差異

你是否厭倦了這種寫法?

when{
    isXiaomi()->xxxx
    isVivo()->xxxxx
    is.......
}

亦或是這樣的代碼?

    if(isXiaomi){
        xxxxx
    }else if(isVivo){
        xxxxxxx
    }else if....

那么今天,我將帶你實(shí)現(xiàn)不一樣的渠道、rom差異。

廢話不多,先看效果~

我們這里隨便舉個例子,不同平臺打印不同的log,可以看到,在華為手機(jī)上打印出了current is Huawei,而在三星手機(jī)上打印出了Samsung,創(chuàng)建簡單易懂,無需處理繁雜的條件判斷~

//自動創(chuàng)建代理類
private val logProxy by lazy {
    getPlatformProxy<ILogPlatformAction>()
}

fun setup(){
    logProxy.log()
}

打印結(jié)果: 
華為-> current is Huawei
三星-> current is Samsung

那么接下來,我們進(jìn)入編碼教程環(huán)節(jié)吧~

前幾天我們在# 手把手教你搭建android模塊化項(xiàng)目框架(九)小試牛刀——優(yōu)雅的登錄方案中簡單介紹過SPI,今天我拋磚引玉,繼續(xù)使用SPI、autoservice實(shí)現(xiàn)差異化代理這里我以不同rom為例,渠道區(qū)分同理,一看就懂~

首先我們在core_tool模塊中創(chuàng)建統(tǒng)一平臺區(qū)分接口~

所有功能實(shí)現(xiàn)要基于此接口

interface IPlatformAction

然后創(chuàng)建功能區(qū)分接口,這里我們以打印log為例

interface ILogPlatformAction : IPlatformAction {
    fun log()
}

之后創(chuàng)建實(shí)現(xiàn)類,這里我們只區(qū)分華為、三星手機(jī),筆者手里就只有這兩個品牌的手機(jī)

增強(qiáng)健壯性,我們創(chuàng)建一個默認(rèn)的實(shí)現(xiàn)類,避免某些型號沒有實(shí)現(xiàn)類時(shí)出現(xiàn)問題
@AutoService(ILogPlatformAction::class)
open class DefaultLogAction : ILogPlatformAction {
    override fun log() {
        Log.v("ssssss", "current is Default")
    }
}

我們的平臺實(shí)現(xiàn)類基于default實(shí)現(xiàn)即可,例如我們接口功能中有10個方法,只有兩個平臺需要區(qū)分時(shí),可以簡化很多代碼
@AutoService(ILogPlatformAction::class)
class SamsungLogAction : DefaultLogAction() {
    override fun log() {
        Log.v("ssssss", "current is Samsung")

    }
}

@AutoService(ILogPlatformAction::class)
class HuaweiLogAction : DefaultLogAction() {
    override fun log() {
        Log.v("ssssss", "current is Huawei")
    }
}

然后我們怎么區(qū)分各個平臺差異呢?

我們知道,SPI代理創(chuàng)建對象是根據(jù)接口查找實(shí)現(xiàn)類,這里我們?yōu)榱撕喕褂茫瑢懸粋€擴(kuò)展方法協(xié)助查詢實(shí)現(xiàn)類即可~

這里我們偷下懶,直接使用類名字做區(qū)分,例如華為的實(shí)現(xiàn)類我們一定帶上huawei,三星的同理,但是要注意,如此寫法一定要確保我們的實(shí)現(xiàn)類名稱不被混淆!!

如果不想使用類名區(qū)分或者團(tuán)隊(duì)人員經(jīng)常變動的情況下,這里我推薦在IPlatformAction類中添加platName,并且在每個rom的實(shí)現(xiàn)類中寫入名稱,以便ServiceLoader獲取實(shí)現(xiàn)類時(shí)判斷使用

代碼如下

inline fun <reified T> getPlatformProxy(): T {
    val implList = ServiceLoader.load(T::class.java).toList()
    return runCatching {
        implList.find {
            這里的RuntimeUtil.platName可以自己獲取一下,判斷rom的代碼還是要有的,不過僅僅使用一次即可,下面我會給出參考代碼
            it?.getSimpleNameLowerCase()?.contains(RuntimeUtil.platName) == true
            如果使用platName方式
            //it?.platName == RuntimeUtil.platName
        } as T
    }.getOrElse {
        implList.find {
            如果沒有找到實(shí)現(xiàn)類,
            it?.getSimpleNameLowerCase()?.contains(RuntimeUtil.PLATFORM_DEFAULT) == true
            如果使用platName方式
            //it?.platName == RuntimeUtil.PLATFORM_DEFAULT
        } as T
    }
}

然后是RuntimeUtil的參考代碼

這個參考代碼,包括git上的,一定不要拿來直接用,我都是亂寫的判斷條件,不一定準(zhǔn)確判斷各個rom的差異
object RuntimeUtil {
    private const val PLATFORM_XIAOMI = "xiaomi"
    private const val PLATFORM_HUAWEI = "huawei"
    private const val PLATFORM_VIVO = "vivo"
    private const val PLATFORM_OPPO = "oppo"
    private const val PLATFORM_SAMSUNG = "samsung"
    const val PLATFORM_DEFAULT = "default"

    private val manufacturer by lazy { Build.MANUFACTURER.lowercase() }

    val platName by lazy {
        when {
            isMIUI() -> PLATFORM_XIAOMI
            isSamsung() -> PLATFORM_SAMSUNG
            isVivo() -> PLATFORM_VIVO
            isOppo() -> PLATFORM_OPPO
            isHuawei() -> PLATFORM_HUAWEI
            else -> PLATFORM_DEFAULT
        }
    }
}

如此我們便達(dá)到了文章開頭的使用方式

下面我們總結(jié)一下實(shí)現(xiàn)方式

  1. 創(chuàng)建IPlatformAction接口,可以處理統(tǒng)一事務(wù)或處理混淆不想使用類名時(shí)添加platformname字段區(qū)分查詢實(shí)現(xiàn)類
  2. 創(chuàng)建各個差異功能的接口,繼承至IPlatformAction接口,例如ILogPlatformAction
  3. 創(chuàng)建各個rom差異化實(shí)現(xiàn)類,繼承ILogPlatformAction
  4. 創(chuàng)建getPlatformProxy()擴(kuò)展方法,達(dá)到自動創(chuàng)建動態(tài)代理的效果

完成以上4步,即可達(dá)到文章開頭的效果啦~

完整項(xiàng)目地址:傳送門

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容