2015-09-18 28 views
8

Bối cảnh:Đang cập nhật giao diện người dùng sử dụng dữ liệu ràng buộc thư viện

Tôi đang sử dụng v1.0-rc1 của new data binding library.

tôi có mô hình quan điểm sau đây:

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); 
    } 

} 

mô hình Quan điểm này được chuyển cho một Fragment và lưu trữ trong một biến ví dụ. Mô hình điểm sau đó được ràng buộc với một bố trí trong onCreateView callback của Fragment (ở đây headerView là một sản phẩm nào 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; 
    } 

Định kỳ, viewModel.setCurrentLocation được gọi và thông qua hiện tại vị trí của người dùng:

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

Hành vi hiện tại:

Giao diện người dùng hiển thị chính xác khoảng cách String khi mỗi Fragment được tạo đầu tiên. Giao diện người dùng hiển thị một cách chính xác khoảng cách String mỗi lần Fragment được tái tạo (những mảnh vỡ đang sống trong một ViewPager

UI KHÔNG cập nhật khi viewModel.setCurrentLocation được gọi với một vị trí mới

hành vi mong muốn:..

Giao diện cập nhật mỗi lần viewModel.setCurrentLocation được gọi với một vị trí mới

Nội dung tôi đã nhìn/suy nghĩ về cho đến nay:.

Theo như tôi có thể biết, có mô hình xem thực hiện Observable (trong trường hợp này, thông qua mở rộng BaseObservable) được yêu cầu tự động cập nhật giao diện người dùng khi gọi notifyPropertyChanged. Ít nhất, khi tôi nhìn vào the Android documentation for data binding, đó là thông điệp tôi lấy đi.

Lớp BaseObservable duy trì danh sách riêng là OnPropertyChangedCallback s. Nếu tôi đặt một breakpoint debug vào phương pháp BaseObservable.notifyPropertyChanged:

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

Tôi thấy rằng mCallbacks luôn null là khi chạy. Vì vậy, có lẽ, các công cụ ràng buộc dữ liệu được tạo ra không gọi BaseObservable.addOnPropertyChangedCallback để cung cấp một OnPropertyChangedCallback tự động kết nối các thành phần. Điều đó có nghĩa là tôi cần phải làm điều đó bằng tay? Điều đó dường như sẽ đánh bại rất nhiều điểm của thư viện ràng buộc dữ liệu.

+1

Một sự khác biệt giữa những gì bạn có và những gì họ có là họ có song song trong tên phương pháp. Chúng có các getters với '@ Bindable' và các bộ giải mã tương ứng với các lời gọi' notifyPropertyChanged() 'và chúng cũng khớp với trường' BR' tương ứng. Tên phương thức của bạn không có chung cơ sở. Bạn có thể tạm thời đổi tên chúng để có nhiều getter/setter-like và xem nếu điều đó ảnh hưởng đến hành vi. Nếu có, bạn có thể sẽ phải đi với những tên đó, ngay cả khi bạn muốn gọi chúng bằng tên mà bạn đang sử dụng. Tôi sẽ ngạc nhiên nếu điều này đã giúp, nhưng đó là một thử nghiệm dễ dàng. – CommonsWare

+0

@CommonsWare cảm ơn đề xuất; sẽ dùng thử và báo cáo lại. – stkent

+0

@CommonsWare thật đáng buồn, không thay đổi hành vi sau khi thực hiện các sửa đổi bạn đề xuất. FWIW, tôi đã sử dụng 'getCurrentLocation' /' setCurrentLocation'/'currentLocation' làm triple của tôi. – stkent

Trả lời

4

Xin chào điều này đã làm việc với tôi. Tôi đã phải đăng nó như là câu trả lời do thiếu tín dụng đủ.

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); 
    } 

} 

} 

Và bố trí file:

<?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> 
+1

Sau khi so sánh câu trả lời của bạn với tôi, tôi lưu ý rằng sự khác biệt chính là việc bạn sử dụng một lớp bê tông ở khắp mọi nơi. Trong mã của tôi, thẻ '' trong bố cục xml và trường cá thể trong Phân đoạn của tôi đều được khai báo sử dụng giao diện. Khai báo giao diện của phương thức 'getDistanceDisplayString' không được chú thích' @ Bindable' trong mã của tôi - chỉ thực hiện lớp con. Để có thể thêm chú thích '@ Bindable' vào giao diện, tôi cần giao diện để mở rộng' Observable'. Sau khi thực hiện thay đổi đó, mọi thứ hoạt động như mong đợi! – stkent

+1

Tuyệt vời, không bao giờ nghĩ rằng nó có thể là vì điều đó. Chỉ cần tự hỏi tại sao nó không làm việc trên máy của bạn. Cảm ơn bạn, đã học được điều gì đó mới !! – subhash

+1

Tôi muốn có một gợi ý trong tài liệu mà chúng ta nên sử dụng các loại cụ thể cho các phần tử '' có các phương thức có chú thích '@ Bindable'. –

0

Tôi nghĩ rằng bạn nên sử dụng lá cờ như isAdded() hoặc isLocationUpdated() bên trong XML của bạn:

<TextView 
     android:id="@+id/location" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="@{location.isUpdated? newLocation : oldLocation}" /> 
Các vấn đề liên quan