如何克服实现字符串资源数据绑定的问题

How to overcome issues with implementing String Resource DataBinding

我遇到了数据绑定问题。我正在尝试包含一个 XML 布局,设置包含的 TextViewtag。但是,它解析为包含的布局名称,前缀为 layout,后缀为 _0,即 layout/common_helpinfo_0

在主布局中我有:-

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <LinearLayout
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:orientation="vertical"
        ....
        <LinearLayout
            .....
            >
            <TextView
                .... />
            <include layout="@layout/common_helpinfo"
                android:id="@+id/hi_tag_world1"
                app:tagstr="@{@string/hi_tag_world1}"
                >
            </include>
        </LinearLayout>
        ....
    </LinearLayout>
</layout>

包含的布局 common_helpinfo 是:-

<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="tagstr" type="String"/>
    </data>
    <TextView
        ....
        android:tag="@{tagstr}"
        ''''
        android:onClick="clickHelpInfo"
        >
    </TextView>
</layout>

为了测试这一点,我的 MainActivity 中有以下内容:-

     public void clickHelpInfo(View v) {
        String hicaller = v.getTag().toString();
        int vid = v.getId();

        Toast.makeText(this,"You Clicked Help from button=" + hicaller + " ID+" + Integer.toString(vid)
                , Toast.LENGTH_SHORT).show();
    }

在我的主布局中,包含的 TextView 的硬编码等效项:-

        <TextView
            ....
            android:tag="@string/hi_tag_world1"
            ''''
            android:onClick="clickHelpInfo"
            >
        </TextView>

这按预期工作,Toast 显示字符串资源的内容 hi_tag_world1.

ActivitMainBinding 中,编译成功后,我有以下显示错误数据设置的位置 (注意我实际上已经包含了两次 common_helpinfo 两者的行为相同) :-

private static final android.util.SparseIntArray sViewsWithIds;
static {
    sIncludes = new android.databinding.ViewDataBinding.IncludedLayouts(12);
    sIncludes.setIncludes(1, 
        new String[] {"common_helpinfo"}, <<<<<
        new int[] {3},
        new int[] {R.layout.common_helpinfo}); <<<<<
    sIncludes.setIncludes(2, 
        new String[] {"common_helpinfo"}, <<<<<
        new int[] {4},
        new int[] {R.layout.common_helpinfo}); <<<<<
    sViewsWithIds = new android.util.SparseIntArray();
    sViewsWithIds.put(R.id.vtext01, 5);
    sViewsWithIds.put(R.id.vtext02, 6);
    sViewsWithIds.put(R.id.vtext03, 7);
    sViewsWithIds.put(R.id.tvhi03, 8);
    sViewsWithIds.put(R.id.etext01, 9);
    sViewsWithIds.put(R.id.actvemail, 10);
    sViewsWithIds.put(R.id.lvemail, 11);
}

但是后来在 ActivityMainBinding 中,我得到以下内容,似乎是在尝试获取正确的数据:-

@Override
protected void executeBindings() {
    long dirtyFlags = 0;
    synchronized(this) {
        dirtyFlags = mDirtyFlags;
        mDirtyFlags = 0;
    }
    // batch finished
    if ((dirtyFlags & 0x4L) != 0) {
        // api target 1

        this.hiTagWorld1.setTagstr(getRoot().getResources().getString(R.string.hi_tag_world1));
        this.hiTagWorld2.setTagstr(getRoot().getResources().getString(R.string.hi_tag_world2));
    }
    executeBindingsOn(hiTagWorld1);
    executeBindingsOn(hiTagWorld2);
}

我查看了我的代码并基于

我读完了Data Binding Library

我打开了 DataBinding 并将 build.gradle 作为 :-

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "mjt.testvcsuse"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    dataBinding {
        enabled = true
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.1.0'
    testCompile 'junit:junit:4.12'
}

经过一番折腾,我似乎找到了一个解决办法,那就是用dataBindingUtilsetContentView方法来代替setContentView方法。

例如final ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);

即而不是:-

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

绑定工作使用:-

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);
        ....
    }

我通过阅读这篇文章 Android Authority - Data Binding in Android 发现了这一点,作者是 Obaro Ogbo。相关摘录为:-

Data Binding Activity

At the moment, we have a layout file that is data binding capable. However, to utilize its data binding ability, we have to load it in a different way.

Previously, you would load your layout like this:

setContentView(R.layout.activity_main);
final Button button1 = (Button)findViewById(R.id.button1);
button.setOnClickListener(...);

With data binding, a Binding class is auto generated from your layout file. The class is named using your layout file name by default. The default name is generated by capitalizing the first letter of each word after an underscore, removing all underscores, and adding ‘Binding’ to the name. As such, activity_main.xml will result in a class called ActivityMainBinding. To associate this auto generated binding class in your code, you invoke DataBindingUtil’s setContentView

final ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(
    this, R.layout.activity_main);
activityMainBinding.updateButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        activityMainBinding.textView1.setText(R.string.text1b);
    }
});

In the code snippet above, you will notice that we can access the updateButton Button directly. All views with an ‘@+id’ in a data binding layout are automatically assigned to a final field of the correct type. So Button updateButton is created for the layout Button with ‘@+id/updateButton’, and TextView textView1 is created for the id/text_view1 TextView.

它似乎不会干扰现有视图,例如非数据 bound/hard 编码的 TextView onClick 处理在没有其他代码更改的情况下仍然有效。