MVP之Android官方MVP架構(gòu)學(xué)習(xí)—Model層

一逛揩、Model層結(jié)構(gòu)

Model層類(lèi)位于data包下,組織結(jié)構(gòu)如圖:


model.jpg

二麸俘、Model層分析

1. 實(shí)體類(lèi)

Tasks作為實(shí)體類(lèi)辩稽,定義的屬性和方法,具體可以查看代碼

2. 接口

TasksDataSource定義了Model的回調(diào)接口和方法

public interface TasksDataSource {

    interface LoadTasksCallback {

        void onTasksLoaded(List<Task> tasks);

        void onDataNotAvailable();
    }

    interface GetTaskCallback {

        void onTaskLoaded(Task task);

        void onDataNotAvailable();
    }

    void getTasks(@NonNull LoadTasksCallback callback);

    void getTask(@NonNull String taskId, @NonNull GetTaskCallback callback);

    void saveTask(@NonNull Task task);

    void completeTask(@NonNull Task task);

    void completeTask(@NonNull String taskId);

    void activateTask(@NonNull Task task);

    void activateTask(@NonNull String taskId);

    void clearCompletedTasks();

    void refreshTasks();

    void deleteAllTasks();

    void deleteTask(@NonNull String taskId);
}

3.實(shí)現(xiàn)類(lèi)

3.1 TasksLocalDataSource

TasksLocalDataSource是TasksDataSource的本地?cái)?shù)據(jù)源實(shí)現(xiàn)類(lèi)从媚,用于從本地?cái)?shù)據(jù)庫(kù)獲取數(shù)據(jù)逞泄,采用單例模式,并且有兩個(gè)幫助類(lèi)TasksDbHelper和TasksPersistenceContract用于從操作數(shù)據(jù)庫(kù)

3.1 TasksRemoteDataSource

TasksRemoteDataSource是TasksDataSource的遠(yuǎn)程數(shù)據(jù)源實(shí)現(xiàn)類(lèi)拜效,用于從服務(wù)端獲取數(shù)據(jù)(demo里只是模仿從服務(wù)端獲扰缰凇),采用單例模式

3.1 TasksRepository

Repository也是TasksDataSource的實(shí)現(xiàn)類(lèi)紧憾,其中持有兩個(gè)兩個(gè)TasksDataSource對(duì)象到千,一般為一個(gè)TasksLocalDataSource對(duì)象和一個(gè)TasksRemoteDataSource對(duì)象,用于統(tǒng)一管理獲取數(shù)據(jù)的方式赴穗,采用單例模式

public class TasksRepository implements TasksDataSource {

    private static TasksRepository INSTANCE = null;

    // 遠(yuǎn)程數(shù)據(jù)源對(duì)象
    private final TasksDataSource mTasksRemoteDataSource;

    // 本地?cái)?shù)據(jù)源對(duì)象
    private final TasksDataSource mTasksLocalDataSource;

    // 存放緩存數(shù)據(jù)
    Map<String, Task> mCachedTasks;

    // 緩存數(shù)據(jù)是否可用
    boolean mCacheIsDirty = false;

    // 構(gòu)造方法
    private TasksRepository(@NonNull TasksDataSource tasksRemoteDataSource,
                            @NonNull TasksDataSource tasksLocalDataSource) {
        mTasksRemoteDataSource = checkNotNull(tasksRemoteDataSource);
        mTasksLocalDataSource = checkNotNull(tasksLocalDataSource);
    }

    // 獲取TasksRepository實(shí)例憔四,采用單例模式
    public static TasksRepository getInstance(TasksDataSource tasksRemoteDataSource,
                                              TasksDataSource tasksLocalDataSource) {
        if (INSTANCE == null) {
            INSTANCE = new TasksRepository(tasksRemoteDataSource, tasksLocalDataSource);
        }
        return INSTANCE;
    }

    public static void destroyInstance() {
        INSTANCE = null;
    }

    // 獲取數(shù)據(jù)
    @Override
    public void getTasks(@NonNull final LoadTasksCallback callback) {
        checkNotNull(callback);

        // 如果緩存可用,則立即返回內(nèi)存中的數(shù)據(jù)
        if (mCachedTasks != null && !mCacheIsDirty) {
            callback.onTasksLoaded(new ArrayList<>(mCachedTasks.values()));
            return;
        }

        if (mCacheIsDirty) {
            // 如果緩存數(shù)據(jù)已經(jīng)不可用般眉,則從服務(wù)端更新數(shù)據(jù)
            getTasksFromRemoteDataSource(callback);
        } else {
            // 從數(shù)據(jù)庫(kù)獲取數(shù)據(jù)了赵,如果沒(méi)有,則從服務(wù)端獲取
            mTasksLocalDataSource.getTasks(new LoadTasksCallback() {
                @Override
                public void onTasksLoaded(List<Task> tasks) {
                    refreshCache(tasks);
                    callback.onTasksLoaded(new ArrayList<>(mCachedTasks.values()));
                }

                @Override
                public void onDataNotAvailable() {
                    getTasksFromRemoteDataSource(callback);
                }
            });
        }
    }

    // 從服務(wù)端獲取數(shù)據(jù)
    private void getTasksFromRemoteDataSource(@NonNull final LoadTasksCallback callback) {
        mTasksRemoteDataSource.getTasks(new LoadTasksCallback() {
            @Override
            public void onTasksLoaded(List<Task> tasks) {
                refreshCache(tasks);
                refreshLocalDataSource(tasks);
                callback.onTasksLoaded(new ArrayList<>(mCachedTasks.values()));
            }

            @Override
            public void onDataNotAvailable() {
                callback.onDataNotAvailable();
            }
        });
    }
}

可以看到煤篙,在實(shí)例化TasksRepository時(shí)需要傳入兩個(gè)TasksDataSource對(duì)象斟览;在獲取數(shù)據(jù)時(shí)先從緩存中獲取,如果緩存中沒(méi)有辑奈,則從數(shù)據(jù)庫(kù)獲取,數(shù)據(jù)庫(kù)沒(méi)有已烤,再?gòu)姆?wù)端獲取鸠窗,若為強(qiáng)制刷新,則直接從服務(wù)端獲取胯究。

三稍计、Model使用

1.TasksDataSource的實(shí)例化

在MVP中,Presenter對(duì)象持有Model對(duì)象裕循,如:

public class AddEditTaskPresenter implements AddEditTaskContract.Presenter,
        TasksDataSource.GetTaskCallback {

    // TasksDataSource對(duì)象
    @NonNull
    private final TasksDataSource mTasksRepository;

    // 實(shí)例化時(shí)傳入TasksDataSource對(duì)象
    public AddEditTaskPresenter(@Nullable String taskId, @NonNull TasksDataSource tasksRepository,
            @NonNull AddEditTaskContract.View addTaskView) {
        mTaskId = taskId;
        mTasksRepository = checkNotNull(tasksRepository);
        mAddTaskView = checkNotNull(addTaskView);

        mAddTaskView.setPresenter(this);
    }
}

Presenter在實(shí)例化是需要傳入TasksDataSource對(duì)象臣嚣,Presenter是在Activity中完成實(shí)例化的

public class AddEditTaskActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.addtask_act);

        ...

        // 實(shí)例化Presenter,傳入TasksDataSource對(duì)象
        new AddEditTaskPresenter(
                taskId,
                Injection.provideTasksRepository(getApplicationContext()),
                addEditTaskFragment);
    }
}

可以看到TasksDataSource對(duì)象是由Injection類(lèi)的provideTasksRepository方法生成

2.Gradle動(dòng)態(tài)配置

在main/java目中并沒(méi)有Injection類(lèi)剥哑,通過(guò)查看app/build.gradle文件可以知道硅则,項(xiàng)目有兩個(gè)生產(chǎn)版本:mock和prod,如下:

productFlavors {
        mock {
            applicationIdSuffix = ".mock"
        }
        prod {

        }
    }

在項(xiàng)目的目錄結(jié)構(gòu)中也有對(duì)應(yīng)的src/mock和src/prod兩個(gè)目錄目錄

source_directories.jpg

在mock和prod中?分別有一個(gè)Injection類(lèi)株婴,這里利用了gradle中的productFlavor創(chuàng)建了多個(gè)版本怎虫,其中每個(gè)版本都可以在工程src目錄下建立與main同級(jí)的文件夾,文件夾名字就是ProductFlavor的名字,可以在其中創(chuàng)建java目錄并添加相應(yīng)的java文件大审,不用的版本可以有相同名字不同實(shí)現(xiàn)的類(lèi)蘸际,具體可查看Android Plugin for Gradle
prod目錄下的Injection

public class Injection {

    public static TasksRepository provideTasksRepository(@NonNull Context context) {
        checkNotNull(context);
        return TasksRepository.getInstance(TasksRemoteDataSource.getInstance(),
                TasksLocalDataSource.getInstance(context));
    }
}

mock目錄下的Injection

public class Injection {

    public static TasksRepository provideTasksRepository(@NonNull Context context) {
        checkNotNull(context);
        return TasksRepository.getInstance(FakeTasksRemoteDataSource.getInstance(),
                TasksLocalDataSource.getInstance(context));
    }
}

可以看到:

  • prod的Injection創(chuàng)建TasksRepository實(shí)例時(shí)傳入的是TasksRemoteDataSource實(shí)例和TasksLocalDataSource實(shí)例

  • mock的Injection創(chuàng)建TasksRepository實(shí)例時(shí)傳入的是FakeTasksRemoteDataSource實(shí)例和TasksLocalDataSource實(shí)例徒扶,其中FakeTasksRemoteDataSource是在mock目錄下創(chuàng)建的TasksDataSource的實(shí)現(xiàn)類(lèi)粮彤。

通過(guò)這種方式可以實(shí)現(xiàn)不同版本注入不同的TasksDataSource實(shí)現(xiàn)類(lèi)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末姜骡,一起剝皮案震驚了整個(gè)濱河市导坟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌溶浴,老刑警劉巖乍迄,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異士败,居然都是意外死亡闯两,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)谅将,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)漾狼,“玉大人,你說(shuō)我怎么就攤上這事饥臂⊙吩辏” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵隅熙,是天一觀的道長(zhǎng)稽煤。 經(jīng)常有香客問(wèn)我,道長(zhǎng)囚戚,這世上最難降的妖魔是什么酵熙? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮驰坊,結(jié)果婚禮上匾二,老公的妹妹穿的比我還像新娘。我一直安慰自己拳芙,他們只是感情好察藐,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著舟扎,像睡著了一般分飞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上浆竭,一...
    開(kāi)封第一講書(shū)人閱讀 49,821評(píng)論 1 290
  • 那天浸须,我揣著相機(jī)與錄音惨寿,去河邊找鬼。 笑死删窒,一個(gè)胖子當(dāng)著我的面吹牛裂垦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播肌索,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蕉拢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了诚亚?” 一聲冷哼從身側(cè)響起晕换,我...
    開(kāi)封第一講書(shū)人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎站宗,沒(méi)想到半個(gè)月后闸准,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡梢灭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年夷家,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片敏释。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡库快,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出钥顽,到底是詐尸還是另有隱情义屏,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布蜂大,位于F島的核電站闽铐,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏奶浦。R本人自食惡果不足惜阳啥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望财喳。 院中可真熱鬧,春花似錦斩狱、人聲如沸耳高。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)泌枪。三九已至,卻和暖如春秕岛,著一層夾襖步出監(jiān)牢的瞬間碌燕,已是汗流浹背误证。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留修壕,地道東北人愈捅。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像慈鸠,于是被迫代替她去往敵國(guó)和親蓝谨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理青团,服務(wù)發(fā)現(xiàn)譬巫,斷路器,智...
    卡卡羅2017閱讀 134,633評(píng)論 18 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,781評(píng)論 25 707
  • 靜寂咕缎,靜寄,靜極 遠(yuǎn)心 一百個(gè)聲部咸作,一個(gè)節(jié)律呼吸 子夜兩點(diǎn) 田盤(pán)山的林木果間 一片轟鳴的靜寂 穿行在林中 扇動(dòng)的翅...
    遠(yuǎn)心篤行閱讀 228評(píng)論 0 0
  • 六豐商城提示:情人節(jié)過(guò)了记罚,我還是要送你一個(gè)大紅花墅诡。此紅花非彼紅花,而是其名就為紅花桐智。紅花在我國(guó)歷史悠久末早,主要...
    nongyedianshang閱讀 346評(píng)論 0 0
  • 人7135-潔-同桌瓊咪 臨摹—貓貓兔4 (原圖來(lái)自“-LANKI-”的微博配圖)
    半影時(shí)光閱讀 182評(píng)論 0 0