詳解Android ViewCompat的作用
詳解Android ViewCompat的作用
ViewCompat類主要是用來提供兼容性的, 比如我最近看的比較的多的canScrollVertically方法, 在ViewCompat里面針對幾個版本有不同的實現(xiàn), 原理上還是根據(jù)版本判斷, 有時甚至還要判斷傳入?yún)?shù)的類型. 但是要注意的是, ViewCompat僅僅讓你調(diào)用不崩潰, 并不保證你調(diào)用的結(jié)果在不同版本的機器上一致.
關(guān)于如何優(yōu)雅的組織代碼, ViewCompat類的結(jié)構(gòu)非常適合我們參考.
ViewCompat里面定義了一個接口, 這個接口列出了所有它支持的方法
interface ViewCompatImpl { public boolean canScrollHorizontally(View v, int direction); public boolean canScrollVertically(View v, int direction); public int getOverScrollMode(View v); public void setOverScrollMode(View v, int mode); ...... }
ViewCompat類并非是在方法層面進行版本判斷然后調(diào)用不同的方法, 而是在類的層面上做的, 也就是說在調(diào)用方法時并沒有判斷版本的調(diào)用, 因為一臺手機的版本在開機到關(guān)機期間是不可能發(fā)生變化的, 所以只需要判斷一次, 而這次判斷放在了類的靜態(tài)初始化塊里.
static final ViewCompatImpl IMPL; static { final int version = android.os.Build.VERSION.SDK_INT; if (version >= 21) { IMPL = new LollipopViewCompatImpl(); } else if (version >= 19) { IMPL = new KitKatViewCompatImpl(); } else if (version >= 17) { IMPL = new JbMr1ViewCompatImpl(); } else if (version >= 16) { IMPL = new JBViewCompatImpl(); } else if (version >= 14) { IMPL = new ICSViewCompatImpl(); } else if (version >= 11) { IMPL = new HCViewCompatImpl(); } else if (version >= 9) { IMPL = new GBViewCompatImpl(); } else if (version >= 7) { IMPL = new EclairMr1ViewCompatImpl(); } else { IMPL = new BaseViewCompatImpl(); } }
這樣我們就得到了針對各個版本的不同實現(xiàn).
但是有些方法的實現(xiàn)在跨越幾個版本的時候是不變的, 有些方法又有可能每次都變, 如何實現(xiàn)高效的代碼復(fù)用呢? 那就是繼承+重寫.
比如BaseViewCompatImpl這個類是基類, 實現(xiàn)ViewCompatImpl接口, 把所有的方法都實現(xiàn)一次
static class BaseViewCompatImpl implements ViewCompatImpl { ...... public boolean canScrollHorizontally(View v, int direction) { return (v instanceof ScrollingView) && canScrollingViewScrollHorizontally((ScrollingView) v, direction); } public boolean canScrollVertically(View v, int direction) { return (v instanceof ScrollingView) && canScrollingViewScrollVertically((ScrollingView) v, direction); } ...... @Override public boolean isOpaque(View view) { final Drawable bg = view.getBackground(); if (bg != null) { return bg.getOpacity() == PixelFormat.OPAQUE; } return false; } ...... }
但是這些實現(xiàn)基本上都是空的, 或者無效的, 或者是一些workaround, 這也很正常, 因為確實不可能讓每個方法都做到兼容, 只能盡量讓他的版本支持多一點, 兼容性方法本來就有很多問題. 以上面這三個方法為例, 前兩個方法都是api 14出現(xiàn)的方法, 在14以下基本上等于是直接返回了false(這里低版本是僅對ScollingView提供了支持, ScollingView有三個基類, 其中一個是RecyclerView), google顯然沒有想到什么好的方法在低版本提供對這個方法的支持, 所以干脆就在api小于14時一直使用這個實現(xiàn), 而isOpaque則是類似workaround的方法, 在api 7時, isOpaque被正式添加到View類中, 所以在api 7我們可以直接調(diào)View的isOpaque, 那么應(yīng)該怎么寫代碼呢? 應(yīng)當(dāng)新建一個類, 繼承BaseViewCompatImpl, 重寫isOpaque方法, 也就是下面這樣:
static class EclairMr1ViewCompatImpl extends BaseViewCompatImpl { @Override public boolean isOpaque(View view) { return ViewCompatEclairMr1.isOpaque(view); } ...... }
而其他沒有更好兼容方案的方法我們都不管, 那么api 9如果某些方法又有了更好的實現(xiàn), 或者可以直接調(diào)用系統(tǒng)的api了, 就再新建一個類GBViewCompatImpl, 這個類需要繼承EclairMr1ViewCompatImpl.
同理, 我們在api 14對應(yīng)的類ICSViewCompatImpl中自然就會看到canScrollHorizontally和canScrollVertically的新的實現(xiàn), 而ICSViewCompatImpl必然繼承自HCViewCompatImpl.
就這樣慢慢的演化, 像串銅錢一樣, 每一個新的類對應(yīng)一個新的版本(版本之間不需要連續(xù)), 同時繼承自前一個版本的類, 在實現(xiàn)類的繼承樹上越接近葉子, 這個實現(xiàn)類的能力就越強.
最后看一下我們在代碼里面使用這個類時的調(diào)用代碼, 比如我要調(diào)用canScrollVertically方法, 那么我的代碼一定是ViewCompat. canScrollVertically(v, dy), 看看這個方法對應(yīng)的代碼
public static boolean canScrollHorizontally(View v, int direction) { return IMPL.canScrollHorizontally(v, direction); }
ViewCompat相當(dāng)于是一個中介, 它自己其實什么都不懂, 但是它認(rèn)識一個懂的人IMPL, 它將所有的調(diào)用都交給了IMPL, 而IMPL在ViewCompat這個類加載時就已經(jīng)根據(jù)當(dāng)前系統(tǒng)版本實例化了, 不需要再判斷版本了.
關(guān)于具體的使用請查看 官方文檔
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關(guān)文章
Android開發(fā)實現(xiàn)刪除聯(lián)系人通話記錄的方法
這篇文章主要介紹了Android開發(fā)實現(xiàn)刪除聯(lián)系人通話記錄的方法,較為詳細(xì)的分析了Android刪除通話記錄的原理、步驟與相關(guān)實現(xiàn)技巧,需要的朋友可以參考下2016-10-10Android使用Rotate3dAnimation實現(xiàn)3D旋轉(zhuǎn)動畫效果的實例代碼
利用Android的ApiDemos的Rotate3dAnimation實現(xiàn)了個圖片3D旋轉(zhuǎn)的動畫,圍繞Y軸進行旋轉(zhuǎn),還可以實現(xiàn)Z軸的縮放。點擊開始按鈕開始旋轉(zhuǎn),點擊結(jié)束按鈕停止旋轉(zhuǎn)。2018-05-05Android開發(fā)中使用sqlite實現(xiàn)新聞收藏和取消收藏的功能
本篇文章主要介紹了sqlite實現(xiàn)新聞收藏和取消收藏功能,主要涉及到oracle數(shù)據(jù)庫方面的內(nèi)容,對于Android開發(fā)sqlite實現(xiàn)收藏和取消功能感興趣的朋友可以參考下本文2016-11-11android里TextView加下劃線的幾種方法總結(jié)
下面小編就為大家?guī)硪黄猘ndroid里TextView加下劃線的幾種方法總結(jié)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-10-10Android開發(fā)手冊Button按鈕實現(xiàn)點擊音效
這篇文章主要為大家介紹了Android開發(fā)手冊Button按鈕實現(xiàn)點擊音效示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06Android樣式的開發(fā):layer-list實例詳解
本文主要介紹Android樣式開發(fā)layer-list,這里整理了詳細(xì)的資料,及簡單示例代碼有興趣的小伙伴可以參考下2016-09-09