Android MVVM 搭建:封裝Activity

根據(jù)Android 基于Databinding 的入門級 MVVM 模式搭建
我們成功的搭建了MVVM中的View,Databinding,ViewModel之間的關(guān)系僧凰,同時我們也加入了專門負責處理網(wǎng)絡(luò)請求和相關(guān)數(shù)據(jù)請求的model模塊(presenter包,為了防止出現(xiàn)混淆框弛,我們在此處將presenter更改為model命名方式)箫攀,但這只不過是最原始版的MVVM雛形庄蹋,用起來并沒有方便多少壶愤,現(xiàn)在我們對他們進行進一步封裝领曼。

1.建立一個大致的目錄:

mvvm初始目錄

1.application包用于放置基礎(chǔ)Application抹剩,用于后續(xù)我們放置可能涉及到的基礎(chǔ)組件初始化司抱;
2.activity包放置基礎(chǔ)BaseDBActivity封裝以及可能會用到的特殊需求的基礎(chǔ)Activity;
3.base包用于放置BaseActivity,BaseFragment諸如此類的基礎(chǔ)類,方便我們根據(jù)業(yè)務(wù)需要做統(tǒng)一封裝的入口铐炫;
4.fragment包放置基礎(chǔ)BaseDBFragment封裝以及可能會用到的特殊需求的基礎(chǔ)Fragment;
5.model包用于放置model層基礎(chǔ)封裝類,如BaseModel垒手;
6.vm包用于放置vm層基礎(chǔ)封裝類,如BaseVM;

2.封裝BaseDBActivty:

我們原始的Activity要將Databinding跟VM串聯(lián)起來倒信,我們是在Activity內(nèi)操作的科贬,代碼如下:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
        MainVM mainVM = new ViewModelProvider(this).get(MainVM.class);
        binding.setViewModel(mainVM);
    }
}

那么此處我們需要把每個View和VM綁定的細節(jié)封裝到BaseDBActivity內(nèi),以后我們就不用再每次都寫這么兩句代碼了鳖悠,封裝以后代碼如下:

public abstract class BaseBDActivity extends BaseActivity {

    protected ViewDataBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        bindLayout();
    }

    protected void bindLayout(){
        binding = DataBindingUtil.setContentView(this, getLayoutId());
        //MainVM mainVM = new ViewModelProvider(this).get(MainVM.class);
        //binding.setViewModel(mainVM);
    }

    public abstract int getLayoutId();

}

這里我們可以看到榜掌,經(jīng)過簡單的封裝,我們現(xiàn)在MainActivity已經(jīng)變成了:

public class MainActivity extends BaseBDActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public int getLayoutId() {
        return R.layout.activity_main;
    }
}

但此時我們無法獲取具體的Databinding用于調(diào)用binding.setViewModel(new MainVM());這一步數(shù)據(jù)綁定乘综,我們注意到DataBindingUtil.setContentView返回的是一個泛型<T extends ViewDataBinding>憎账,也就是說我們其實可以拿到具體的Databinding引用類型:ActivityMainBinding,從而我們可以手動完成數(shù)據(jù)綁定卡辰,于是我們可以進一步優(yōu)化BaseBDActivity:

public abstract class BaseBDActivity<T extends ViewDataBinding> extends BaseActivity {

    protected T binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        bindLayout();
    }

    protected void bindLayout(){
        binding = DataBindingUtil.setContentView(this, getLayoutId());
        //MainVM mainVM = new ViewModelProvider(this).get(MainVM.class);
        //binding.setViewModel(mainVM);
    }

    public abstract int getLayoutId();

}

現(xiàn)在我們現(xiàn)在MainActivity已經(jīng)變成了:

public class MainActivity extends BaseBDActivity<ActivityMainBinding> {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MainVM mainVM = new ViewModelProvider(this).get(MainVM.class);
        binding.setViewModel(mainVM);
    }

    @Override
    public int getLayoutId() {
        return R.layout.activity_main;
    }
}

接下來胞皱,我們需要將binding.setViewModel這一步優(yōu)化掉,通過強行設(shè)定Layout的ViewModel命名為viewModel九妈,我們可以通過ViewDatabinding.setVariable(int variableId, @Nullable Object value)方法規(guī)避掉binding.setViewModel(mainVM)這種無法通用的問題反砌,也就是在Layout布局文件中,我們對ViewModel的引入是寫死的:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <!--此處綁定viewModel(封裝的原因我們這里固定命名為:viewModel)-->
        <variable
            name="viewModel"
            type="com.jf.mvvm_1.work.vm.MainVM" />
    </data>
</layout>

而我們可以通過傳入Class<?> clz 也可以直接封裝new ViewModelProvider(this).get(MainVM.class)這一步允蚣,最終變?yōu)椋?/p>

public abstract class BaseBDActivity<T extends ViewDataBinding> extends BaseActivity {

    protected T binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        bindLayout();
    }

    protected void bindLayout(){
        bindLayout(getViewModelClass());
    }

    protected void bindLayout(Class<? extends ViewModel> clzVM){
        bindLayout(new ViewModelProvider(this).get(clzVM));
    }

    protected <X extends ViewModel> void bindLayout(X vm){
        binding = DataBindingUtil.setContentView(this, getLayoutId());
        binding.setLifecycleOwner(this);
        binding.setVariable(BR.viewModel,vm);
    }

    public abstract int getLayoutId();

    protected abstract Class<? extends ViewModel> getViewModelClass();

}

而此時我們的MainActivity的代碼簡化為:

public class MainActivity extends BaseBDActivity<ActivityMainBinding> {

    @Override
    public int getLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected Class<? extends ViewModel> getViewModelClass() {
        return MainVM.class;
    }
}

然后我們注意到通過反射機制獲取泛型的類類型:((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()可以獲取泛型的Class類型于颖,我們可以進一步封裝為泛型指定類型:

public abstract class BaseBDActivity<T extends ViewDataBinding,X extends ViewModel> extends BaseActivity {

    protected T binding;
    protected X viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        bindLayout();
    }

    protected void bindLayout(){
        bindLayout(getViewModelClass());
    }

    protected void bindLayout(Class<X> clzVM){
        bindLayout(new ViewModelProvider(this).get(clzVM));
    }

    protected void bindLayout(X vm){
        viewModel = vm;
        binding = DataBindingUtil.setContentView(this, getLayoutId());
        binding.setLifecycleOwner(this);
        binding.setVariable(BR.viewModel,vm);
    }

    public abstract int getLayoutId();

    //protected abstract Class<? extends ViewModel> getViewModelClass();

    public Class<X> getViewModelClass() {
        Class<X> xClass = (Class<X>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
        return xClass;
    }

}

最終我們的MainActivity的代碼簡化為:

public class MainActivity extends BaseBDActivity<ActivityMainBinding,MainVM> {

    @Override
    public int getLayoutId() {
        return R.layout.activity_main;
    }

}

源碼地址:https://github.com/jackyflame/MvvmSimple

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市嚷兔,隨后出現(xiàn)的幾起案子森渐,更是在濱河造成了極大的恐慌,老刑警劉巖冒晰,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件同衣,死亡現(xiàn)場離奇詭異,居然都是意外死亡壶运,警方通過查閱死者的電腦和手機耐齐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蒋情,“玉大人埠况,你說我怎么就攤上這事】醚ⅲ” “怎么了辕翰?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長狈谊。 經(jīng)常有香客問我喜命,道長沟沙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任壁榕,我火速辦了婚禮矛紫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘牌里。我一直安慰自己颊咬,他們只是感情好,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布牡辽。 她就那樣靜靜地躺著贪染,像睡著了一般。 火紅的嫁衣襯著肌膚如雪催享。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天哟绊,我揣著相機與錄音因妙,去河邊找鬼。 笑死票髓,一個胖子當著我的面吹牛攀涵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播洽沟,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼以故,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了裆操?” 一聲冷哼從身側(cè)響起怒详,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎踪区,沒想到半個月后昆烁,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡缎岗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年静尼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片传泊。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡鼠渺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出眷细,到底是詐尸還是另有隱情拦盹,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布薪鹦,位于F島的核電站掌敬,受9級特大地震影響惯豆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜奔害,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一楷兽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧华临,春花似錦芯杀、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至扶供,卻和暖如春筛圆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背椿浓。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工太援, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人扳碍。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓提岔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親笋敞。 傳聞我的和親對象是個殘疾皇子碱蒙,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354

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