如何克服实现String Resource DataBinding的问题

时间:2017-07-02 11:12:50

标签: android-xml android-resources android-databinding

我遇到了数据绑定问题。我正在尝试添加XML布局,设置所包含的 tag TextView 。但是,它解析为包含的布局名称以布局为前缀,后缀为_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);
}

我查看了How do I use databinding to combine a string from resources with a dynamic variable in XML?

上的代码

我已阅读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'
}

1 个答案:

答案 0 :(得分:0)

经过一段时间的游戏后,我似乎找到了一个解决方案,即使用dataBindingUtil的{​​{1}}方法替换setContentView方法。

e.g。的 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);
        ....
    }

我通过阅读 Obaro Ogbo 撰写的文章Android Authority - Data Binding in Android找到了这一点。相关的摘录是: -

  

数据绑定活动

     

目前,我们有一个支持数据绑定的布局文件。   但是,要利用其数据绑定能力,我们必须将其加载到   不同的方式。

     

以前,你会加载你的布局:

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

使用数据绑定,可以从布局自动生成Binding类   文件。默认情况下,使用您的布局文件名命名该类。该   默认名称是通过大写每个字母的第一个字母生成的   下划线后面的单词,删除所有下划线,然后添加   '绑定'到名称。因此,activity_main.xml将导致a   类叫ActivityMainBinding。   要在您的代码中关联此自动生成的绑定类,您   调用DataBindingUtil的setContentView

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

在上面的代码段中,您会注意到我们可以访问   updateButton Button直接。数据中包含“@ + id”的所有视图   绑定布局自动分配给的最终字段   正确的类型。因此,为布局Button创建了Button updateButton   使用'@ + id / updateButton',并为其创建TextView textView1   id / text_view1 TextView。

它似乎不会干扰现有的视图,例如非数据绑定/硬编码的TextView onClick处理仍然无需其他代码更改。