使用数据绑定库更新UI

语境:

我正在使用新的数据绑定库的 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); } } 

这个视图模型被传递给一个Fragment并存储在一个实例variables中。 视图模型然后绑定到Fragment的onCreateViewcallback(这里headerView是一个空的FrameLayout )布局:

  @Nullable @Override public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { final View v = inflater.inflate(R.layout.fragment_drawer_page, container, false); headerView = (ViewGroup) v.findViewById(R.id.headerView); final ViewDrawerPageHeaderBinding binding = DataBindingUtil.inflate(inflater, R.layout.view_drawer_page_header, headerView, true); binding.setViewModel(viewModel); return v; } 

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

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

目前的行为:

用户界面正确显示每个Fragment第一次创build时的距离String 。 UI每次重新创buildFragment都会正确显示距离String (这些片段位于ViewPager

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

期望的行为:

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

我已经看过/到目前为止的东西:

据我所知,视图模型实现Observable (在这种情况下,通过扩展BaseObservable )应该是在notifyPropertyChanged被调用时自动更新UI。 至less,当我查看Android文档进行数据绑定时 ,这是我拿走的信息。

BaseObservable类维护BaseObservable的私有列表。 如果我在BaseObservable.notifyPropertyChanged方法上设置debugging断点:

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

我发现mCallbacks在运行时总是为null 。 所以大概,生成的数据绑定的东西不会调用BaseObservable.addOnPropertyChangedCallback提供一个BaseObservable.addOnPropertyChangedCallback自动连接组件。 这是否意味着我需要手动执行? 这似乎打败了数据绑定库的许多重点。

Solutions Collecting From Web of "使用数据绑定库更新UI"

你好,这对我的工作。 由于缺乏足够的信用,我必须将其作为答复。

 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()或isLocationUpdated()这样的标志:

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