Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/211.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 使用数据绑定库更新UI_Android_Android Databinding - Fatal编程技术网

Android 使用数据绑定库更新UI

Android 使用数据绑定库更新UI,android,android-databinding,Android,Android Databinding,上下文: 我使用的是的v1.0-rc1 我有以下视图模型: public class DrawerPageHeaderViewModelImpl extends BaseObservable implements DrawerPageHeaderViewModel { @Nullable private Location currentLocation; public DrawerPageHeaderViewModelImpl(@Nullable final Loca

上下文:

我使用的是的v1.0-rc1

我有以下视图模型:

public class DrawerPageHeaderViewModelImpl extends BaseObservable implements DrawerPageHeaderViewModel {

    @Nullable
    private Location currentLocation;

    public DrawerPageHeaderViewModelImpl(@Nullable final Location currentLocation) {
        this.currentLocation = currentLocation;
    }

    @Bindable
    @Nullable
    @Override
    public String getDistanceDisplayString() {
        if (currentLocation == null) {
            return null;
        }

        float[] results = new float[1];
        Location.distanceBetween(landmark.getLatitude(), landmark.getLongitude(), currentLocation.getLatitude(), currentLocation.getLongitude(), results);
        final float metersToTargetLocation = results[0];

        final float feetToTargetLocation = DistanceUtil.convertMetersToFeet(metersToTargetLocation);
        return DistanceUtil.convertFeetToFeetOrMilesString(feetToTargetLocation);
    }

    @Override
    public void setCurrentLocation(@Nullable final Location currentLocation) {
        this.currentLocation = currentLocation;
        notifyPropertyChanged(BR.distanceDisplayString);
    }

}
此视图模型被传递到
片段
,并存储在实例变量中。然后将视图模型绑定到片段的
onCreateView
回调中的布局(此处
headerView
是一个空的
FrameLayout
):

定期调用并传递用户当前位置的
viewModel.setCurrentLocation

@Override
public void update(final Observable observable, Object data) {
    new Handler(Looper.getMainLooper()).post(() -> {
        if (isAdded()) {
            viewModel.setCurrentLocation(locationController.getCachedUserLocation());
        }
    });
}
当前行为:

当第一次创建每个
片段时,UI会正确显示距离
字符串
。每次重新创建
片段
,UI都会正确显示距离
字符串
(这些片段位于
查看页面
中)

当使用新位置调用
viewModel.setCurrentLocation
时,UI不会更新

期望的行为:

每次使用新位置调用
viewModel.setCurrentLocation
时,UI都会更新

到目前为止我一直在看/思考的东西:

据我所知,让视图模型实现
Observable
(在本例中,通过扩展
BaseObservable
)应该能够在调用
notifyPropertyChanged
时自动进行UI更新。至少,当我看到时,这就是我得到的消息

BaseObservable
类维护一个私有的
OnPropertyChangedCallback
s列表。如果我在
BaseObservable.notifyPropertyChanged
方法上设置了调试断点:

public void notifyPropertyChanged(int fieldId) {
    if(this.mCallbacks != null) {
        this.mCallbacks.notifyCallbacks(this, fieldId, (Object)null);
    }
}

我看到
mCallbacks
在运行时总是
null
。因此,可能生成的数据绑定内容不会调用
BaseObservable.addOnPropertyChangedCallback
来提供一个自动连接组件的
OnPropertyChangedCallback
。这意味着我需要手动执行吗?这看起来似乎很简单击败了数据绑定库的许多要点。

您好,这对我的有效。由于信用不足,我不得不将其作为答案发布

public class DataBindingTest extends Fragment {


private LinearLayout headerView;

public DataBindingTest() {
    // Required empty public constructor
}

private static Handler mHandler;
DrawerPageHeaderViewModelImpl viewModel;

private Runnable runnable;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View rootView = inflater.inflate(R.layout.fragment_font_test, container, false);
    headerView = (LinearLayout) rootView.findViewById(R.id.headerView);
    viewModel = new DrawerPageHeaderViewModelImpl(null);
    mHandler = new Handler();
    RecyclerItemBinding bindingView = DataBindingUtil.inflate(inflater, R.layout.recycler_item, headerView, true);
    runnable = new Runnable() {
        @Override
        public void run() {
            changeLocation();
        }
    };
    bindingView.setViewModel(viewModel);
    return rootView;
}

@Override
public void onResume() {
    super.onResume();
    changeLocation();
}

@Override
public void onPause() {
    super.onPause();
    mHandler.removeCallbacks(runnable);
}

public void changeLocation() {
    viewModel.setCurrentLocation(new Location("New"));
    mHandler.postDelayed(runnable, 2000);
}

public class DrawerPageHeaderViewModelImpl extends BaseObservable {

    @Nullable
    private Location currentLocation;

    public DrawerPageHeaderViewModelImpl(@Nullable final Location currentLocation) {
        this.currentLocation = currentLocation;
    }

    @Bindable
    @Nullable
    public String getDistanceDisplayString() {
        if (currentLocation == null) {
            return null;
        }

        return "Some String " + new Random().nextInt(100);
    }

    public void setCurrentLocation(@Nullable final Location currentLocation) {
        this.currentLocation = currentLocation;
        notifyPropertyChanged(BR.distanceDisplayString);
    }

}

}
和布局文件:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/tools">

<data>
    <variable
        name="viewModel"
        type="com.androidbolts.databindingsample.DataBindingTest.DrawerPageHeaderViewModelImpl" />
</data>

<android.support.v7.widget.CardView
    android:id="@+id/card_view"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="100dp"
    android:layout_height="130dp"
    android:layout_gravity="center"
    card_view:cardCornerRadius="2dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/image"
            android:layout_width="match_parent"
            android:layout_height="100dp"/>

        <TextView
            android:id="@+id/name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{viewModel.distanceDisplayString}"
            app:font="@{@string/kenyan}"/>

    </LinearLayout>
</android.support.v7.widget.CardView>
</layout>

我认为应该在XML中使用类似isAdded()或isLocationUpdate()的标志:

    <TextView
        android:id="@+id/location"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{location.isUpdated? newLocation : oldLocation}" />


您所拥有的和他们所拥有的之间的一个区别是,它们在方法名称中具有并行性。它们具有具有
@Bindable
的getter和具有
notifyPropertyChanged()的相应setter
调用,并且它们也与相应的
BR
字段匹配。您的方法名称不共享一个共同的基础。您可以暂时将它们重命名为更像getter/setter的名称,看看这是否会影响行为。如果这样做,您可能不得不使用这些名称,即使您更愿意使用您正在使用的名称来调用它们正在使用。如果这有帮助,我会感到惊讶,但这是一个简单的测试。@Commonware感谢您的建议;将试用并报告。@Commonware遗憾的是,在您建议的修改后,行为没有改变。FWIW,我使用
getCurrentLocation
/
setCurrentLocation
/
currentLocation
作为我的测试工具riple。虽然我希望在接下来的几周内对数据绑定进行更多的研究,但我只是轻轻地踢了踢轮胎。我将特别尝试对这种情况进行建模。但是,目前,除了RC中可能存在的错误之外,我没有任何其他建议——抱歉!没问题。期待着在深入研究时看到您对它的理解!之后将您的答案与我的答案相比较,我注意到主要区别在于您在任何地方都使用了具体的类。在我的代码中,xml布局中的
标记和片段中的实例字段都是使用接口声明的。
getDistanceDisplayString
方法的接口声明没有注释
@Bindable
在我的代码中-只有子类实现是。为了能够将
@Bindable
注释添加到接口中,我需要接口本身扩展
Observable
。在做了更改之后,一切都按预期进行了!太棒了,没想到这可能是因为这个。只是想知道为什么它在你身上不起作用urs.谢谢你,学到了一些新东西!!我希望文档中有一个提示,我们应该使用具体类型来表示
元素,这些元素具有
@Bindable
-注释方法。@DenisKniazhev只要对接口方法进行注释,你仍然可以在
变量
元素中使用接口-但是,这不是从文件中清除!
    <TextView
        android:id="@+id/location"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{location.isUpdated? newLocation : oldLocation}" />