久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

淺談 Android 編程思想和架構(gòu)

 jnstyle 2016-03-21

我主要是想講一講自己對(duì)于 接口,、模塊化、MVP 的一些心得,。

有這么一個(gè)場(chǎng)景,,兩個(gè)不同的頁(yè)面,包含了看起來一模一樣的界面內(nèi)容(或者稱 frame/UI),,這種場(chǎng)景可能很常見,,有時(shí)看到會(huì)說:“哈哈,我可以設(shè)計(jì)個(gè)復(fù)用,!” 但是遇到一個(gè)問題是,,這兩個(gè)頁(yè)面需要分別去請(qǐng)求不同的服務(wù)端 API,返回下來的數(shù)據(jù)結(jié)構(gòu)也不一樣(姑且不說去和服務(wù)端開發(fā)協(xié)商),,這樣就會(huì)導(dǎo)致具體的 view holder 或者適配器在綁定數(shù)據(jù)的時(shí)候無法復(fù)用,,為何說無法復(fù)用或難以復(fù)用呢?舉個(gè)例子,,比如傳進(jìn)適配器的 list item 數(shù)據(jù)內(nèi)容不一樣,,你總不能把 item 再拆了,分好幾個(gè) list 傳進(jìn)去吧,?面向具體編程情況下,,適配器得到不同的 items,得對(duì) item 抽取內(nèi)容綁定到 UI,,難免要寫很多重復(fù)的代碼,。

這時(shí)候我們可以采取面向抽象編程,既然不同的數(shù)據(jù)對(duì)應(yīng)一樣的 UI,,如果它們都實(shí)現(xiàn)了一樣的接口,,這個(gè)接口的設(shè)計(jì)取決于 UI 需要哪些數(shù)據(jù)塊,然后不同的 Item model 去實(shí)現(xiàn)這個(gè)接口提供數(shù)據(jù)即可,,這時(shí)適配器只要持有這個(gè)接口類型的 item 即可,,通俗地舉個(gè)例子說,比如數(shù)據(jù)模型1和2都實(shí)現(xiàn)了 IPost 接口,,那么適配器就只要持有 List 數(shù)據(jù)即可,,List<數(shù)據(jù)模型1> 和 List<數(shù)據(jù)模型2> 都可以視作“一樣的鴨子”傳遞給這個(gè)適配器。這樣把數(shù)據(jù)模型的數(shù)據(jù)塊抽取放到了數(shù)據(jù)模型本身實(shí)現(xiàn),,不僅不用寫很多重復(fù)的分發(fā)代碼,,而且適配器本身都能復(fù)用了;當(dāng)接口需要新的方法,,也能驅(qū)動(dòng)著實(shí)現(xiàn)者們?nèi)?shí)現(xiàn),。

這就是抽象編程或者接口的好處,接口可以讓不同的模型通過同樣的方法提供內(nèi)容,,這樣它們就可以一定程度上視為同類,,就像有句話說的,如果一個(gè)動(dòng)物走起來像鴨子,,叫起來也像鴨子,,我們就可以把它當(dāng)作是鴨子

另外,,同樣地,,對(duì)于有相同可復(fù)用的 UI 這個(gè)場(chǎng)景,我們可以更進(jìn)一步去做,,即把 View Holder 化為一個(gè)自定義 ViewGroup,,或者包裹之。這樣做的好處是,,更多邏輯不同的地方也都能更好地去復(fù)用,,而且對(duì)于 Adapter,你不需要再糾結(jié) Item UI 的內(nèi)容點(diǎn)擊事件,,是要回調(diào)到 Adapter 外還是在Adapter 內(nèi)直接綁定數(shù)據(jù)響應(yīng),。前者處理方式會(huì)導(dǎo)致 Adapter 得暴露很多接口,傳遞很多數(shù)據(jù),,經(jīng)常要從數(shù)據(jù)集合中重新根據(jù)位置取綁定的數(shù)據(jù),,等等。后者,,則會(huì)導(dǎo)致 Adapter 變得臃腫,,處理過多不應(yīng)該屬于它的業(yè)務(wù),而且同樣存在著數(shù)據(jù)重復(fù)綁定問題,。

這時(shí)候如果把 View Holder 化為一個(gè)自定義 ViewGroup,,那么交互數(shù)據(jù)的時(shí)候就可以進(jìn)行UI數(shù)據(jù)綁定和響應(yīng)數(shù)據(jù)綁定,而監(jiān)聽器建議是在初始化的時(shí)候就進(jìn)行設(shè)置,,避免 View 被復(fù)用的時(shí)候,,重新設(shè)置數(shù)據(jù)的同時(shí)重復(fù) new 出無謂的監(jiān)聽器對(duì)象。

其中,,交互給 ViewGroup 這個(gè)對(duì)象的數(shù)據(jù)模型也是要使用接口模型,,比如同樣接收 IPost 接口對(duì)象作為數(shù)據(jù),這樣凡是實(shí)現(xiàn)了同樣的提供數(shù)據(jù)接口的類,,都能傳入這個(gè) ViewGroup 中供其使用,。這里提供一個(gè)我的常用寫法,,使用 ViewGroup 關(guān)聯(lián)一個(gè) item 布局:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class PostView extends LinearLayout implements View.OnClickListener {
    private TextView mSummary;
    private ImageView mAvatar;
    private TextView mUsername;
    private TextView mCreateAt;
    protected IPost mData;
    public PostView(Context context) {
        this(context, null);
    }
    public PostView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public PostView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        inflate(context, R.layout.view_post, this);
    }
    @Override protected void onFinishInflate() {
        super.onFinishInflate();
        mAvatar = (ImageView) findViewById(R.id.avatar);
        mUsername = (TextView) findViewById(R.id.username);
        mCreateAt = (TextView) findViewById(R.id.create_at);
        mSummary = (TextView) findViewById(R.id.summary);
        setOnClickListener(this);
    }
    public void setPost(IPost data) {
        mData = data;
        Glides.loadCircleImage(getContext(), data.getAvatar(), mAvatar);
        mUsername.setText(data.getUsername());
        mCreateAt.setText(data.getCreatedAtFromNow());
        mSummary.setText(data.getSummary());
    }
     
    @Override public void onClick(View v) {
        Intent intent = StreamActivity.newIntent(getContext(),
                mData.getAvatar(), mData.getUsername(), mData.getUserId(),
                mData.isCurrentUser());
        getContext().startActivity(intent);
    }
}

解釋了接口的一些實(shí)際使用場(chǎng)景之后,我們接下來就很好談 MVP 架構(gòu)了,,因?yàn)榭赡芎芏嗳藭?huì)在使用 MVP 的時(shí)候產(chǎn)生困惱,,為什么要搞那么多接口再實(shí)現(xiàn),何不直接調(diào)用具體對(duì)象的方法,?現(xiàn)在可能有點(diǎn)清楚了,。

今年 Android 開發(fā)的技術(shù)趨勢(shì),我覺得一是 RxJava 會(huì)繼續(xù)被更多人接受進(jìn)而開始使用,,二是谷歌花了不少心思的 Data Binding 很可能會(huì)迎來正式版,,data binding 是實(shí)現(xiàn) MVVM 架構(gòu)的重要組成部分,介于它還不夠完善而且目前還無法提供雙向綁定,,目前很多人包括俺都還只能停留在個(gè)人項(xiàng)目玩一玩的階段,,所以我也是比較青睞于 MVP 架構(gòu)。

MVP 逐漸流行起來了,,必然是有一些好處,,不然誰會(huì)去管這么一個(gè)新興東西。首先就是它會(huì)更加易于測(cè)試,,Android 平臺(tái)默認(rèn)的應(yīng)用架構(gòu)導(dǎo)致單元測(cè)試變得異常的困難,,和 SDK 糾纏在一起的代碼,使你無法改變要測(cè)試單元的預(yù)備狀態(tài),,無法進(jìn)行單元測(cè)試的準(zhǔn)備步驟,,而且很多情況,你無法獲得測(cè)試內(nèi)容的結(jié)果或者狀態(tài),,也就無法完成斷言內(nèi)容,。而使用 MVP 的好處就是能夠更易于做測(cè)試,同時(shí)也能夠有更好的復(fù)用性和松耦合性,。

MVP 即 Model – Presenter – View,,各部分之間的通訊,都是雙向的,,Presenter 持有 View 和 Model 的抽象引用,,作為中間人,處理業(yè)務(wù)邏輯,,Model 角色用于調(diào)取數(shù)據(jù),,而 View 則用于展現(xiàn)和控制 UI,它們都由中間人 P 調(diào)度,。抽象的好處前面說了,,如果 M 或 V 有改變,只要換一個(gè)實(shí)現(xiàn)者就好了,,對(duì)于 P,,可以繼續(xù)把它們當(dāng)成提供一樣的可調(diào)用方法對(duì)象,。

對(duì)于包的結(jié)構(gòu),如果項(xiàng)目比較小,,可以把不同的 Presenter 置于同一個(gè) package 下,,而如果頁(yè)面數(shù)很多項(xiàng)目模塊很多,則可以每一個(gè)模塊分一套 MVP packages,。

現(xiàn)在我們只要在 Activity 或 Fragment 中的生命周期簡(jiǎn)單做一些 UI 組件初始化等布置,,然后一些業(yè)務(wù)邏輯工作就請(qǐng)求 Presenter 去完成,,Presenter 內(nèi)部持有 View 和 Model,,Activity 是 View(MVP 中的 View) 的實(shí)現(xiàn),于是 Presenter 調(diào)用 Model 去請(qǐng)求得到數(shù)據(jù)庫(kù)或網(wǎng)絡(luò)數(shù)據(jù),,完成之后再調(diào)用 View 改變 UI 的方法,,或者把數(shù)據(jù)交給 View 去展現(xiàn)。如此,,每個(gè)角色的代碼都會(huì)變得很簡(jiǎn)潔,、明確。而且,,將業(yè)務(wù)邏輯放到 Presenter 中去,,可以避免當(dāng) Activity 退出而后臺(tái)線程仍然引用著 Activity,致使資源無法被系統(tǒng)回收從而引起內(nèi)存泄露,。

對(duì)于屏幕旋轉(zhuǎn) Activity 重建和內(nèi)存泄漏等問題,,MVP 能夠更好地處理。當(dāng) Activity 銷毀的之前,,可以把 Presenter 中的引用去除,,因此不會(huì)在切換屏幕的時(shí)候發(fā)生內(nèi)存泄漏,而且沒必要去 unsubscribe 請(qǐng)求,。具體推薦大家看看這篇文章:使用 MVP 和后臺(tái)任務(wù),。

對(duì)于 Presenter 的設(shè)計(jì),或者說具體應(yīng)該把哪些內(nèi)容放到 Presenter 中,,是一個(gè)關(guān)鍵,。Model 并不是必須有的,如果使用 RxJava 和 Retrofit,,可以很清晰地獲取數(shù)據(jù)庫(kù)內(nèi)容和網(wǎng)絡(luò)數(shù)據(jù),,則可以把 Model 的工作納入到 Presenter 中。如果帶有 Model,,則 Presenter 要實(shí)現(xiàn) Model 的回調(diào),,在回調(diào)中把數(shù)據(jù)傳給 View 或響應(yīng)。所以 Presenter 必須得有 View 的引用,,但可以不用 Model.

一個(gè) Activity 可以有多個(gè) Presenter,,要用到什么業(yè)務(wù)就加入什么 Presenter,,并且實(shí)現(xiàn)這個(gè) Presenter 所需要的 View 接口即可,這就是簡(jiǎn)單的復(fù)用邏輯,。

最后,,介紹一種我的重構(gòu)技巧。對(duì)于原本不是 MVP 的項(xiàng)目,,結(jié)合 Android Studio 進(jìn)行重構(gòu)也很容易,,AS 有個(gè)好用的功能快捷鍵是 option + enter,可以用來自動(dòng)解決錯(cuò)誤,,利用它,,我們可以很方便的把原本都寫到 Activity 中的業(yè)務(wù)抽出,并且不用手動(dòng)去創(chuàng)建各種接口中的方法和實(shí)現(xiàn)方法,,步驟大概是這樣的:

首先建一個(gè)業(yè)務(wù)的 Presenter 和一個(gè) View 接口,,Presenter 中加入 View 接口變量,并寫個(gè)構(gòu)造方法用于 View 初始化,。而 View 接口,,只要先放空即可。然后回到 Activity,,implements View 接口,,初始化 Presenter,并把自己交給 Presenter,,找到原本業(yè)務(wù)邏輯的地方,,把相關(guān)代碼剪切,然后輸入比如 mPresenter.loadData(),,這時(shí)候,,Presenter 中并沒有 loadData 這個(gè)方法,你只要對(duì)著錯(cuò)誤按一下 option + enter 就可以出來 “自動(dòng)在 Presenter 中創(chuàng)建這個(gè)方法” 的選項(xiàng),,然后自動(dòng)創(chuàng)建了之后,,再跳過去,粘貼剛才的代碼,,并且在回調(diào)的時(shí)候,,調(diào)用 view.hideProgressBar() 方法,同樣的,,hideProgressBar 這個(gè)方法在 View 接口中并沒有,,于是 option + enter 自動(dòng)在 View 接口中創(chuàng)建這個(gè)方法。這時(shí)候 Activity 就會(huì)報(bào)錯(cuò),,提示你必須實(shí)現(xiàn) hideProgressBar 這個(gè)方法,,然后你再對(duì)著 Activity 按 option + enter 自動(dòng)生成需要實(shí)現(xiàn)的方法的框體,從而進(jìn)行實(shí)現(xiàn)。這樣就完成了整個(gè)循環(huán)驅(qū)動(dòng)重構(gòu),,是一條 step by step 很簡(jiǎn)單的套路,。


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多