android databinding之include

因爲前段時間瞭解到了google推出的數據綁定框架databinding,就使用它實現了一個簡單的android的mvvm架構思想的demo。java

使用過程之中很happy,按照其使用方式,框架會自動生成佈局文件對應的XXXBinding類文件。不再用findViewById了,也不再用使用註解框架在Activity或者Fragment中寫大量的控件屬性了,哇,整個世界都清淨了。。。。這感受太爽了。。。android

結果遇到問題了,也不知道怎麼解決。。。。幸虧有google老師帶咱們學習。數組

前面都是廢話,下面就詳細分析我遇到的問題吧!架構

使用一個Activity + 對應的佈局文件舉例:app

DemoActivity:框架

public class DemoActivity extends BaseActivity<DemoVM, ActivityDemoBinding> {

    @Bind(R.id.linkTv)
    TextView linkTv;

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

    @Override
    protected void initBinding() {
        setBinding(DataBindingUtil.<ActivityDemoBinding>setContentView(this, R.layout.activity_demo));
        binding.setVm(getViewModel());
    }

    @Override
    protected void initModel() {
    }

    @Override
    public void initViewModel() {
        setViewModel(new DemoVM(this));
    }

    private void initWidget() {
        linkTv.setText(Html.fromHtml(getResources().getString(R.string.url)));
        linkTv.setMovementMethod(LinkMovementMethod.getInstance());
    }

    @Override
    protected boolean hasBackButton() {
        return false;
    }

    @Override
    protected int getToolbarTitle() {
        return R.string.title_activity_demo;
    }

    activity_demo.xml(include了一個佈局文件):mvvm

<?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:bind="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <import type="com.zdj.presentation.modules.demo.vms.DemoVM" />

        <variable
            name="vm"
            type="DemoVM" />
    </data>

    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:context="com.zdj.presentation.modules.demo.views.DemoActivity">

        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay"
            app:elevation="0dp">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:popupTheme="@style/AppTheme.PopupOverlay" />

        </android.support.design.widget.AppBarLayout>

        <include
            layout="@layout/content_demo"
            bind:vm="@{vm}" />

    </android.support.design.widget.CoordinatorLayout>
</layout>

    content_demo.xml:ide

<?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:bind="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data parent="@">
        <import type="com.zdj.presentation.modules.demo.vms.DemoVM"/>
        <variable
            name="vm"
            type="DemoVM"/>
    </data>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:context="com.zdj.presentation.modules.demo.views.DemoActivity"
        tools:showIn="@layout/activity_demo">

        <TextView
            android:id="@+id/linkTv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"/>

        <Button
            android:id="@+id/btn_LoadData"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/btn_text_load_data"
            bind:onClickListener="@{vm.onClickLoadData}" />
    </LinearLayout>
</layout>

    由Activity的initWidget方法可見,若要使用content_demo中的TextView控件,還須要註解框架或者經過findViewById方法也行,找到指定的控件,而後對其處理。這樣其實就是生成了兩個控件實例在操做佈局文件     中的控件了,可見的一個實例在Activity中,那麼另外一個呢?它在content_demo.xml生成的ContentDemoBinding類中,而activity_demo.xml生成的對應的數據綁定類ActivityDemoBinding含有ContentDemoBinding一個類型的私有的屬性,而偏偏的想要操做的view是ContentDemoBinding的一個屬性,activity是訪問不到的。函數

    有沒有什麼辦法徹底使用databinding框架自動給咱們生成的各個實例呢?這樣好處至少有兩個:1 不用使用findViewById 或者第三方註解框架  2 避免生成前面提到的兩個控件實例對象佈局

    下面介紹方法,其實很簡單,針對activity_demo.xml作一點點的改變便可:

<?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:bind="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <import type="com.zdj.presentation.modules.demo.vms.DemoVM" />

        <variable
            name="vm"
            type="DemoVM" />
    </data>

    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:context="com.zdj.presentation.modules.demo.views.DemoActivity">

        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay"
            app:elevation="0dp">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:popupTheme="@style/AppTheme.PopupOverlay" />

        </android.support.design.widget.AppBarLayout>
        <!--    須要改變的地方:加上 android:id="@+id/views" 便可   -->
        <include
            layout="@layout/content_demo"
            android:id="@+id/views"
            bind:vm="@{vm}" />

    </android.support.design.widget.CoordinatorLayout>
</layout>

    佈局文件修改以後,代碼的變化,這裏只貼了initWidget方法了,由於除了去除對BufferKnife的依賴之外(能夠刪除控件屬性了),改變的只有這裏:

private void initWidget() {
     // 終於能夠在Activity中直接訪問include的控件了,這個簡單的問題困擾了我好長時間。。。。
    binding.views.linkTv.setText(Html.fromHtml(getResources().getString(R.string.url)));
    binding.views.linkTv.setMovementMethod(LinkMovementMethod.getInstance());
}

    究其緣由,實際上是在ActivityDemoBinding類中添加了一個屬性 public  final  ContentDemoBinding views,正好符合個人要求,提供了公共的訪問權限。

    在佈局文件中,全部帶id的標籤都會映射爲佈局文件生成的對象的一個屬性,由生成的binding對象的構造函數能夠看出來:

public ActivityDemoBinding(android.databinding.DataBindingComponent bindingComponent, View root) {
    super(bindingComponent, root, 2);
    // 首先會將全部帶id的view映射爲object數組
    final Object[] bindings = mapBindings(bindingComponent, root, 3, sIncludes, sViewsWithIds);
    // 這裏至於 view 對應的 bindings第幾個元素,須要細究ViewDataBinding類的mapBindings方法
    this.mboundView0 = (android.support.design.widget.CoordinatorLayout) bindings[0];
    this.mboundView0.setTag(null);
    this.toolbar = (android.support.v7.widget.Toolbar) bindings[2];
    this.views = (com.zdj.presentation.databinding.ContentDemoBinding) bindings[1];
    setRootTag(root);
    // listeners
    invalidateAll();
}

    最後不忘貼出參考地址

相關文章
相關標籤/搜索