8

语境:

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

}

此视图模型被传递给 aFragment并存储在实例变量中。然后视图模型在 Fragment 的onCreateView回调中绑定到一个布局(这里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());
        }
    });
}

当前行为:

首次创建String时,UI 会正确显示距离。每次重新创建 a 时Fragment,UI 都会正确显示距离(这些片段位于.StringFragmentViewPager

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

期望的行为:

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

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

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

该类BaseObservable维护一个私有列表OnPropertyChangedCallbacks。如果我在方法上设置调试断点BaseObservable.notifyPropertyChanged

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

我看到那mCallbacks总是null在运行时。所以大概,生成的数据绑定的东西不会调用BaseObservable.addOnPropertyChangedCallback来提供OnPropertyChangedCallback自动连接组件的。这是否意味着我需要手动完成?这似乎违背了数据绑定库的很多要点。

4

2 回答 2

4

你好,这对我有用。由于缺乏足够的信用,我不得不将其发布为答案。

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>
于 2015-09-25T10:05:15.933 回答
0

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

    <TextView
        android:id="@+id/location"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{location.isUpdated? newLocation : oldLocation}" />
于 2015-10-01T13:34:14.110 回答