1. 程式人生 > >Android App的三種架構模式MVC,MVP和MVVM

Android App的三種架構模式MVC,MVP和MVVM

http://www.2cto.com/kf/201506/405766.html

MVC使用總結
利用MVC設計模式,使得這個天氣預報小專案有了很好的可擴充套件和維護性,當需要改變UI顯示的時候,無需修改Contronller(控制器)Activity的程式碼和Model(模型)WeatherModel模型中的業務邏輯程式碼,很好的將業務邏輯和介面顯示分離。
在Android專案中,業務邏輯,資料處理等擔任了Model(模型)角色,XML介面顯示等擔任了View(檢視)角色,Activity擔任了Contronller(控制器)角色。contronller(控制器)是一箇中間橋樑的作用,通過介面通訊來協同 View(檢視)和Model(模型)工作,起到了兩者之間的通訊作用。
什麼時候適合使用MVC設計模式?當然一個小的專案且無需頻繁修改需求就不用MVC框架來設計了,那樣反而覺得程式碼過度設計,程式碼臃腫。一般在大的專案中,且業務邏輯處理複雜,頁面顯示比較多,需要模組化設計的專案使用MVC就有足夠的優勢了。
4.在MVC模式中我們發現,其實控制器Activity主要是起到解耦作用,將View檢視和Model模型分離,雖然Activity起到互動作用,但是找Activity中有很多關於檢視UI的顯示程式碼,因此View檢視和Activity控制器並不是完全分離的,也就是說一部分View檢視和Contronller控制器Activity是繫結在一個類中的。
MVC的優點:
(1)耦合性低。所謂耦合性就是模組程式碼之間的關聯程度。利用MVC框架使得View(檢視)層和Model(模型)層可以很好的分離,這樣就達到了解耦的目的,所以耦合性低,減少模組程式碼之間的相互影響。
(2)可擴充套件性好。由於耦合性低,新增需求,擴充套件程式碼就可以減少修改之前的程式碼,降低bug的出現率。
(3)模組職責劃分明確。主要劃分層M,V,C三個模組,利於程式碼的維護。

------------------------------------------------------------------------------------------

相信大家對MVC,MVP和MVVM都不陌生,作為三個最耳熟能詳的Android框架,它們的應用可以是非常廣泛的,但是對於一些新手來說,可能對於區分它們三個都有困難,更別說在實際的專案中應用了,有些時候想用MVP的,程式碼寫著寫著就變成了MVC,久而久之就對它們三個的選擇產生了恐懼感,如果你也是這樣的人群,那麼這篇文章可能會對你有很大的幫助,希望大家看完都會有收穫吧!

文章重點:

(1)瞭解並區分MVC,MVP,MVVM。

(2)知道這三種模式在Android中如何使用。

(3)走出data binding的誤區。

(4)瞭解MVP+data binding的開發模式。

本篇文章的demo我將會上傳到我的github上

水之積也不厚,則其負大舟也無力

正如莊子在逍遙遊中說的,如果水不夠深,那就沒有能夠擔負大船的力量 。所以在真正開始涉及具體的程式碼之前,我們要先對MVC,MVP和MVVM做一個初步的瞭解。如果各位同學對此已經有所瞭解了,可以選擇性跳過這一節。

MVC

MVC,Model View Controller,是軟體架構中最常見的一種框架,簡單來說就是通過controller的控制去操作model層的資料,並且返回給view層展示,具體見下圖

mvc

當用戶出發事件的時候,view層會發送指令到controller層,接著controller去通知model層更新資料,model層更新完資料以後直接顯示在view層上,這就是MVC的工作原理。

那具體到Android上是怎麼樣一個情況呢?

大家都知道一個Android工程有什麼對吧,有java的class檔案,有res資料夾,裡面是各種資源,還有類似manifest檔案等等。對於原生的Android專案來說,layout.xml裡面的xml檔案就對應於MVC的view層,裡面都是一些view的佈局程式碼,而各種java bean,還有一些類似repository類就對應於model層,至於controller層嘛,當然就是各種activity咯。大家可以試著套用我上面說的MVC的工作原理是理解。比如你的介面有一個按鈕,按下這個按鈕去網路上下載一個檔案,這個按鈕是view層的,是使用xml來寫的,而那些和網路連線相關的程式碼寫在其他類裡,比如你可以寫一個專門的networkHelper類,這個就是model層,那怎麼連線這兩層呢?是通過button.setOnClickListener()這個函式,這個函式就寫在了activity中,對應於controller層。是不是很清晰。

大家想過這樣會有什麼問題嗎?顯然是有的,不然為什麼會有MVP和MVVM的誕生呢,是吧。問題就在於xml作為view層,控制能力實在太弱了,你想去動態的改變一個頁面的背景,或者動態的隱藏/顯示一個按鈕,這些都沒辦法在xml中做,只能把程式碼寫在activity中,造成了activity既是controller層,又是view層的這樣一個窘境。大家回想一下自己寫的程式碼,如果是一個邏輯很複雜的頁面,activity或者fragment是不是動輒上千行呢?這樣不僅寫起來麻煩,維護起來更是噩夢。(當然看過Android原始碼的同學其實會發現上千行的程式碼不算啥,一個RecyclerView.class的程式碼都快上萬行了呢。。)

MVC還有一個重要的缺陷,大家看上面那幅圖,view層和model層是相互可知的,這意味著兩層之間存在耦合,耦合對於一個大型程式來說是非常致命的,因為這表示開發,測試,維護都需要花大量的精力。

正因為MVC有這樣那樣的缺點,所以才演化出了MVP和MVVM這兩種框架。

MVP

MVP作為MVC的演化,解決了MVC不少的缺點,對於Android來說,MVP的model層相對於MVC是一樣的,而activity和fragment不再是controller層,而是純粹的view層,所有關於使用者事件的轉發全部交由presenter層處理。下面還是讓我們看圖

mvp

從圖中就可以看出,最明顯的差別就是view層和model層不再相互可知,完全的解耦,取而代之的presenter層充當了橋樑的作用,用於操作view層發出的事件傳遞到presenter層中,presenter層去操作model層,並且將資料返回給view層,整個過程中view層和model層完全沒有聯絡。看到這裡大家可能會問,雖然view層和model層解耦了,但是view層和presenter層不是耦合在一起了嗎?其實不是的,對於view層和presenter層的通訊,我們是可以通過介面實現的,具體的意思就是說我們的activity,fragment可以去實現實現定義好的介面,而在對應的presenter中通過介面呼叫方法。不僅如此,我們還可以編寫測試用的View,模擬使用者的各種操作,從而實現對Presenter的測試。這就解決了MVC模式中測試,維護難的問題。

當然,其實最好的方式是使用fragment作為view層,而activity則是用於建立view層(fragment)和presenter層(presenter)的一個控制器。

MVVM

MVVM最早是由微軟提出的

mvvm

這裡要感謝泡在網上的日子,因為前面看到的三張圖我都是從它的部落格中摘取的,如果有人知道不允許這樣做的話請告訴我,我會從我的部落格中刪除的,謝謝。

從圖中看出,它和MVP的區別貌似不大,只不過是presenter層換成了viewmodel層,還有一點就是view層和viewmodel層是相互繫結的關係,這意味著當你更新viewmodel層的資料的時候,view層會相應的變動ui。

我們很難去說MVP和MVVM這兩個MVC的變種孰優孰劣,還是要具體情況具體分析。

紙上得來終覺淺,絕知此事要躬行

對於程式設計師來說,空談是最沒效率的一種方式,相信大家看了我上面對於三種模式的分析,或多或少都會有點雲裡霧裡,下面讓我們結合程式碼來看看。

讓我們試想一下下面這個情景,使用者點選一個按鈕A,獲取github上對應公司對應倉庫中貢獻排行第一的任的名字,然後我們還會有一個按鈕B,使用者點選按鈕B,介面上排行第一的那個人的名字就會換成自己的。

MVC

MVC實現是最簡單的。

首先看對應view層的xml檔案

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
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/container"
    android:orientation="vertical"
    tools:context=".ui.view.MainActivity"
    android:fitsSystemWindows="true">

    <Button
        android:text="get"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="get"/>

    <Button
        android:text="change"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="change"/>

    <TextView
        android:id="@+id/top_contributor"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:textSize="30sp"/>

</LinearLayout>

很簡單,兩個Button一個TextView

接著看對應controller層的activity

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
public class MainActivity extends AppCompatActivity {

    private ProcessDialog dialog;
    private Contributor contributor = new Contributor();

    private TextView topContributor;

    private Subscriber<Contributor> contributorSub = new Subscriber<Contributor>() {

        @Override
        public void onStart() {
            showProgress();
        }

        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {

        }

        @Override
        public void onNext(Contributor contributor) {
            MainActivity.this.contributor = contributor;

            topContributor.setText(contributor.login);

            dismissProgress();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        topContributor = (TextView)findViewById(R.id.top_contributor);
    }

    public void get(View view){
        getTopContributor("square", "retrofit");
    }

    public void change(View view){
        contributor.login = "zjutkz";

        topContributor.setText(contributor.login);
    }

    public void getTopContributor(String owner,String repo){
        GitHubApi.getContributors(owner, repo)
                .take(1)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.newThread())
                .map(new Func1<List<Contributor>, Contributor>() {

                    @Override
                    public Contributor call(List<Contributor> contributors) {
                        return contributors.get(0);
                    }
                })
                .subscribe(contributorSub);
    }

    public void showProgress(){
        if(dialog == null){
            dialog = new ProcessDialog(this);
        }

        dialog.showMessage("正在載入...");
    }

    public void dismissProgress(){
        if(dialog == null){
            dialog = new ProcessDialog(this);
        }

        dialog.dismiss();
    }
}

我們看一下get()方法中呼叫的getTopContributor方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void getTopContributor(String owner,String repo){
    GitHubApi.getContributors(owner, repo)
            .take(1)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.newThread())
            .map(new Func1<List<Contributor>, Contributor>() {

                @Override
                public Contributor call(List<Contributor> contributors) {
                    return contributors.get(0);
                }
            })
            .subscribe(contributorSub);
}

熟悉rxjava和retrofit的同學應該都明白這是啥意思,如果對這兩個開源庫不熟悉也沒事,可以參考給 Android 開發者的 RxJava 詳解用 Retrofit 2 簡化 HTTP 請求這兩篇文章。

對於這裡大家只要知道這段程式碼的意思就是去獲取github上owner公司中的repo倉庫裡貢獻排名第一的那個人。貢獻者是通過Contributor這個java bean儲存的。

1
2
3
4
5
6
7
8
9
10
public class Contributor {

    public String login;
    public int contributions;

    @Override
    public String toString() {
        return login + ", " + contributions;
    }
}

很簡單,login表示貢獻者的名字,contributor表示貢獻的次數。

然後通過rxjava的subscriber中的onNext()函式得到這個資料。

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
private Subscriber<Contributor> contributorSub = new Subscriber<Contributor>() {

    @Override
    public void onStart() {
        showProgress();
    }

    @Override
    public void onCompleted() {

    }

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onNext(Contributor contributor) {
        MainActivity.this.contributor = contributor;

        topContributor.setText(contributor.login);

        dismissProgress();
    }
};

至於另外那個change按鈕的工作大家應該都看得懂,這裡不重複了。

好了,我們來回顧一遍整個流程。

首先在xml中寫好佈局程式碼。

其次,activity作為一個controller,裡面的邏輯是監聽使用者點選按鈕並作出相應的操作。比如針對get按鈕,做的工作就是呼叫GithubApi的方法去獲取資料。

GithubApi,Contributor等類則表示MVC中的model層,裡面是資料和一些具體的邏輯操作。

說完了流程再來看看問題,還記得我們前面說的嗎,MVC在Android上的應用,一個具體的問題就是activity的責任過重,既是controller又是view。這裡是怎麼體現的呢?看了程式碼大家發現其中有一個progressDialog,在載入資料的時候顯示,載入完了以後取消,邏輯其實是view層的邏輯,但是這個我們沒辦法寫到xml裡面啊,包括TextView.setTextView(),這個也一樣。我們只能把這些邏輯寫到activity中,這就造成了activity的臃腫,這個例子可能還好,如果是一個複雜的頁面呢?大家自己想象一下。

MVP

通過具體的程式碼大家知道了MVC在Android上是如何工作的,也知道了它的缺點,那MVP是如何修正的呢?

這裡先向大家推薦github上的一個第三方庫,通過這個庫大家可以很輕鬆的實現MVP。好了,還是看程式碼吧。

首先還是xml

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
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/container"
    android:orientation="vertical"
    tools:context=".ui.view.MainActivity"
    android:fitsSystemWindows="true">

    <Button
        android:text="get"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="get"/>

    <Button
        android:text="change"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="change"/>

    <TextView
        android:id="@+id/top_contributor"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:textSize="30sp"/>

</LinearLayout>

這個和MVC是一樣的,畢竟介面的形式是一樣的嘛。

接下去,我們看一個介面。

1
2
3
4
5
6
7
8
            
           

相關推薦

Android App架構模式MVCMVPMVVM

http://www.2cto.com/kf/201506/405766.html MVC使用總結 利用MVC設計模式,使得這個天氣預報小專案有了很好的可擴充套件和維護性,當需要改變UI顯示的時候,無需修改Contronller(控制器)Activity的程式

Android UI層的框架模式-MVCMVPMVVM

MVC MVC全名是Model View Controller,是模型(model)-檢視(view)-控制器(controller)的縮寫。 呼叫關係 資料關係 View 接受使用者互動請求View 將請求轉交給ControllerController 操

Android App 的設計架構MVCMVPMVVM 的分析

MVC框架模式一樣,Model模型處理資料程式碼不變在Android的App開發中,很多人經常會頭疼於App的架構如何設計: 我的App需要應用這些設計架構嗎? MVC,MVP等架構講的是什麼?區別是什麼? 本文就來帶你分析一下這幾個架構的特性,優缺點,以及App架構設計中

設計模式-MVCMVP MVVM

複雜的軟體必須有清晰合理的架構,否則無法開發和維護。 MVC(Model-View-Controller)是最常見的軟體架構之一,業界有著廣泛應用。它本身很容易理解,但是要講清楚它與衍生的 MVP 和 MVVM 架構的區別就不容易了。 昨天晚上,我讀了《Scali

androidMVCMVPMVVM模式詳解析

我們都知道,android本身就採用了MVC模式,model層資料來源層我們就不說了,至於view層即通過xml來體現,而 controller層的角色一般是由activity來擔當的。雖然我們專案用到了MVP模式,但是現在人們並沒有總結出一種規範,所以MVP模式的寫法並不

教你認清MVCMVPMVVM模式

相信大家對MVC,MVP和MVVM都不陌生,作為三個最耳熟能詳的Android框架,它們的應用可以是非常廣泛的,但是對於一些新手來說,可能對於區分它們三個都有困難,更別說在實際的專案中應用了,有些時候想用MVP的,程式碼寫著寫著就變成了MVC,久而久之就對它們三

Android開發模式MVCMVPMVVM的簡單介紹與區別

相信大家對MVC,MVP和MVVM都不陌生,作為三個最耳熟能詳的Android框架,它們的應用可以是非常廣泛的,但是對於一些新手來說,可能對於區分它們三個都有困難,更別說在實際的專案中應用了,有些時候想用MVP的,程式碼寫著寫著就變成了MVC,久而久之就對它們三個的選擇產生了

架構MVCMVPMVVM簡介

1. 三層架構 三層架構就是將整個業務應用劃分為: UI層:介面層(User Interface layer) BLL層:業務邏輯層(Business Logic Layer) DAL層:資料訪問層(Data access layer) 區分層次的目的是為了

iOS架構模式MVCMVPMVVM(內附demo)

MVC MVC的實現思路是:使用者操作View,在Controller層完成業務邏輯處理,更新Model層,將資料顯示在View層。 在MVC中,每個層之間都有關聯,耦合比較緊,在大型專案中,維護起來比較費力。 View把控制權交給Controller層,

認清Android框架 MVCMVPMVVM

(2)知道這三種模式在Android中如何使用。 (3)走出data binding的誤區。 (4)瞭解MVP+data binding的開發模式。 本篇文章的demo我將會上傳到我的github上。 水之積也不厚,則其負大舟也無力 正如莊子在逍遙遊中說的,如果水不夠深,那就沒有能夠擔負大船的

MVCMVP MVVM

指令 hang mvc route text nts -i fonts ng- MVC,MVP 和 MVVM 的圖示 MVC(Model-View-Controller)是最常見的軟件架構之一,業界有著廣泛應用。它本身很容易理解,但是要講清楚,它與衍生的 MVP 和 MV

MVCMVP MVVM 的圖示

綁定 則無 作用 com 理解 兩種 區別 維護 保留 http://www.ruanyifeng.com/blog/2015/02/mvcmvp_mvvm.html 復雜的軟件必須有清晰合理的架構,否則無法開發和維護。 MVC(Model-View-Controlle

MVCMVP MVVM 的詳解

name one control ember 模式 hash 改名 主動性 主動 一、MVC MVC模式的意思是,軟件可以分成三個部分。 視圖(View):用戶界面。 控制器(Controller):業務邏輯 模型(Model):數據保存 各部分之間的通信方式如下

MVCMVP MVVM 的圖示區別

mage 否則 nbsp lan ng- 意思 scrip 業界 作用 作者: 阮一峰 日期: 2015年2月 1日 復雜的軟件必須有清晰合理的架構,否則無法開發和維護。 MVC(Model-View-Controller)是最常見的軟件架構之一,業界有著廣泛應用。它本身

MVCMVP MVVM 的區別

一、MVC MVC模式的意思是,軟體可以分成三個部分。 檢視(View):使用者介面。 控制器(Controller):業務邏輯 模型(Model):資料儲存   1.View 傳送指令到 Controller 2.Controller 完

MVCMVP MVVM(轉載)

1 什麼是MVC MVC的目的是為了把資料(Model)和檢視(View)分離開來,然後用控制器(Controller)作膠水來粘合M和V之間的關係。 這樣做的目的是為了實現注意點分離這樣一個更高層次的設計理念,也就是讓專業的物件做專業的事情,View就只負責檢視相關的東西,Mode

淺談MVCMVP MVVM 的區別

複雜的軟體必須有清晰合理的架構,否則無法開發和維護。 以下以Javascript客戶端頁面開發為例使用圖示簡單闡述三者的聯絡和區別。 需要注意的是,MVC開發模式備廣泛用於各種軟體開發中,包括網際網路的B/S模式的產品,而其他兩種模式大多數用在客戶端開發中,例如:Javascrtipt、WPF、Adn

Android App的設計架構MVC,MVP,MVVM架構經驗談

用戶 自己的 req html pla 觀察 持久化 重構 his 來源: Android App的設計架構:MVC,MVP,MVVM與架構經驗談 和MVC框架模式一樣,Model模型處理數據代碼不變在Android的App開發中,很多人經常會頭疼於App的架構如何設計:

Android中設計模式MVCMVPMVVM的簡單理解

設計模式VS框架框架是程式碼的重用,可擴充套件。舉幾個簡單的例子。Spring架構,Struts架構。設計模式是設計的重用,是一種抽象的設計方法。例如MVC,MVP,MVVM。下面,我們以android開發為例,簡單比較一下三種不同的設計模式。MVCMVC是指Modle,Vi

Android工廠模式簡析

簡單介紹三種工廠模式:簡單工廠模式,工廠方法模式,抽象工廠模式 1.簡單工廠模式 這是一個小工廠,什麼都由自己生產,別人要什麼就呼叫自己的相應工具去生產 具備三個特徵:具體工廠A,具體生產工具B,抽象生產物件C 就是 A呼叫工具B去生產C