2017-12-27 193 views
1

場景:
我有一個使用其他適配器(HomePageProductSliderAdapter & HomePageHotDealsSliderAdapter)的HomePageProductAdapter
主頁有兩個RecyclerView for Regular產品和熱門產品;這兩個列表中有一些產品是相同的。例如在第一個列表中,有product1,product2,product3product4;在第二個列表中,有product1product5安卓:RecyclerView的項目不通過數據綁定刷新和境界

問題:
當前顯示在屏幕上的項目不會在另一個列表中刷新。例如,當我增加第一個列表中的product1的數量時,它不會刷新第二個列表中的數量。

詳細說明:

產品(其在使用HomePageProductAdapterHomeProductSliderModel):

public class Product extends RealmObject implements Observable/*BaseObservable*/ { 
@PrimaryKey 
public String productId; 
private String quantity = "0"; 
@Ignore 
private transient PropertyChangeRegistry mCallbacks; 

//Constructor, getters and setters 

@Bindable 
public String getQuantity() { 
    return quantity; 
} 

public void setQuantity(String quantity) { 
    if (quantity != null && !quantity.equals("")) { 
     this.quantity = quantity; 
     notifyPropertyChanged(BR.quantity); 
    } 
} 

public synchronized void notifyChange() { 
    if (mCallbacks != null) { 
     mCallbacks.notifyCallbacks(this, 0, null); 
    } 
} 

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

@Override 
public void addOnPropertyChangedCallback(OnPropertyChangedCallback onPropertyChangedCallback) { 
    if (mCallbacks == null) { 
     mCallbacks = new PropertyChangeRegistry(); 
    } 
    mCallbacks.add(onPropertyChangedCallback); 
} 

@Override 
public void removeOnPropertyChangedCallback(OnPropertyChangedCallback onPropertyChangedCallback) { 
    if (mCallbacks != null) { 
     mCallbacks.remove(onPropertyChangedCallback); 
    } 
} 
} 

HomePageProductAdapter(其在使用HomePageProductSliderAdapterHomePageHotDealsSliderAdapter):

public class HomePageProductAdapter extends RecyclerView.Adapter<HomePageProductAdapter.Viewholder> { 
private List<Product> productsList = new ArrayList<>(); 

public HomePageProductAdapter(List<Product> product) { 
    productsList = product; 
    Realm realm = null; 
    realm = mRealmManager.getLocalInstance(); 
    for(final Product prd: productsList) 
     realm.executeTransaction(new Realm.Transaction() { 
      @Override 
      public void execute(@NonNull Realm realm) { 
       Product productRealm = realm.where(Product.class).equalTo(ProductFields.PRODUCT_ID, prd.getProductId()).findFirst(); 
       if (productRealm == null) { 
        realm.insert(prd); 
       } 
      } 
     }); 
} 

@Override 
public Viewholder onCreateViewHolder(ViewGroup parent, int viewType) { 
    HomeProductItemBinding item = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.home_product_item, parent, false); 
    return new Viewholder(item); 
} 

@Override 
public void onBindViewHolder(final Viewholder holder, final int position) { 
    final Product productIns = productsList.get(holder.getAdapterPosition()); 
    Realm realm = null; 
    realm = mRealmManager.getLocalInstance(); 
    realm.executeTransaction(new Realm.Transaction() { 
     @Override 
     public void execute(@NonNull Realm realm) { 
      Product productRealm = realm.where(Product.class).equalTo(ProductFields.PRODUCT_ID, productIns.getProductId()).findFirst(); 

      if (productRealm == null) { 
       productRealm = realm.createObject(Product.class, productIns.getProductId()); 
      } 

      if (productRealm != null) { 
       if (productRealm.getQuantity() == null || productRealm.getQuantity().equalsIgnoreCase("0")) { 
        holder.HomeProductBindGrid.strCount.setText("0"); //And I'm wondering why should I use set value manually, when there is holder.HomeProductBindGrid.setProd 
        productRealm.setQuantity("0"); 
       } 
       else { 
        holder.HomeProductBindGrid.strCount.setText(String.valueOf(productRealm.getQuantity())); 
       } 
      } 

      holder.HomeProductBindGrid.setProd(productRealm); // I'm using this line and android:text="@{prod.quantity}" in the XML, why should I set the values manually?! 
      holder.HomeProductBindGrid.executePendingBindings(); 
     } 
    }); 

    holder.HomeProductBindGrid.inc_CountButton.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      final Product productIns = productsList.get(holder.getAdapterPosition()); //Which one should I use?! -> //holder.HomeProductBindGrid.getProd(); //productsList.get(position); //productsList.get(holder.getAdapterPosition()); 
      Realm realm = null; 
      realm = mRealmManager.getLocalInstance(); 
      realm.executeTransaction(new Realm.Transaction() { 
       @Override 
       public void execute(@NonNull Realm realm) { 
        Product productRealm = realm.where(Product.class).equalTo(ProductFields.PRODUCT_ID, productIns.getProductId()).findFirst(); 

        if (productRealm == null) { 
         productRealm = realm.createObject(Product.class, productIns.getProductId()); 
        } 

        if (productRealm != null) { 
         if (productRealm.getQuantity() == null || productRealm.getQuantity().equalsIgnoreCase("0")) { 
          productRealm.setQuantity("1"); 
          holder.HomeProductBindGrid.strCount.setText(String.valueOf(productRealm.getQuantity())); 
         } 
         else { 
          productRealm.setQuantity(String.valueOf(Integer.valueOf(productRealm.getQuantity()) + 1)); 
          holder.HomeProductBindGrid.strCount.setText(String.valueOf(productRealm.getQuantity())); 
         } 

         holder.HomeProductBindGrid.setProd(productRealm); 
         holder.HomeProductBindGrid.executePendingBindings(); 
        } 
       } 
      }); 
     } 
    }); 
} 

class Viewholder extends RecyclerView.ViewHolder { 
    HomeProductItemBinding HomeProductBindGrid; 
    ItemListBinding ItemListBindList; 

    Viewholder(HomeProductItemBinding binding) { 
     super(binding.getRoot()); 
     this.HomeProductBindGrid = binding; 
    } 
} 
} 

HomeProductSliderModel(其在使用HomePageProductSliderAdapterHomePageHotDealsSliderAdapter):

public class HomeProductSliderModel extends BaseObservable{ 
//I extended this model from BaseObservable, in the hope that the other lists refresh, but didn't make any different. 
private List<Product> productList; 

public HomeProductSliderModel(List<Product> productList) { 
    this.productList = productList; 
} 

@NonNull 
@Bindable 
public List<Product> getProductList() { 
    return productList; 
} 

public void setProductList(List<Product> productList) { 
//I don't know where should I use it (Like setQuantity in HomePageProductAdapter?! 
    this.productList = productList; 
    //notifyChange(); 
    notifyPropertyChanged(BR.productList); 
} 

@Override 
public void addOnPropertyChangedCallback(OnPropertyChangedCallback callback) { 
    super.addOnPropertyChangedCallback(callback); 
} 

@Override 
public void removeOnPropertyChangedCallback(OnPropertyChangedCallback callback) { 
    super.removeOnPropertyChangedCallback(callback); 
} 

@Override 
public void notifyChange() { 
    super.notifyChange(); 
} 

@Override 
public void notifyPropertyChanged(int fieldId) { 
    super.notifyPropertyChanged(fieldId); 
} 
} 

HomePageProductSliderAdapter(在MainActivity使用哪個):

public class HomePageProductSliderAdapter extends RecyclerView.Adapter<HomePageProductSliderAdapter.Holder> { 
private List<HomeProductSliderModel> mHomeProductSliderModels; 

public HomePageProductSliderAdapter(List<HomeProductSliderModel> homeProductSliderModels, int screenWidth) { 
    mHomeProductSliderModels = homeProductSliderModels; 
} 

@Override 
public Holder onCreateViewHolder(ViewGroup parent, int viewType) { 
    ProductSliderBinding bind = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), 
      R.layout.product_slider, parent, false); 

    return new Holder(bind); 
} 

@Override 
public void onBindViewHolder(Holder holder, int position) { 
    HomeProductSliderModel homeProductSliderModel = mHomeProductSliderModels.get(holder.getAdapterPosition()); 
    holder.bindHomeProduct(homeProductSliderModel); 
} 

@Override 
public int getItemCount() { 
    return mHomeProductSliderModels.size(); 
} 

class Holder extends RecyclerView.ViewHolder { 
    ProductSliderBinding productSliderBind; 

    Holder(ProductSliderBinding binding) { 
     super(binding.getRoot()); 
     productSliderBind = binding; 
    } 

    public void bindHomeProduct(@NonNull HomeProductSliderModel homeProductSlider) { 
     productSliderBind.setHomeProductSlider(homeProductSlider); 
     productSliderBind.executePendingBindings(); 
     productSliderBind.productRecycler.setAdapter(new HomePageProductAdapter(/*mHomeProductSliderModels.get(position)*/homeProductSlider.getProductList())); 
     productSliderBind.executePendingBindings(); 
    } 
} 
} 

HomePageHotDealsSliderAdapter(在MainActivity使用哪個):

public class HomePageHotDealsSliderAdapter extends RecyclerView.Adapter<HomePageHotDealsSliderAdapter.Holder> { 
private List<HomeProductSliderModel> mHomeProductSliderModels; 

public HomePageHotDealsSliderAdapter(List<HomeProductSliderModel> homeProductSliderModels) { 
    mHomeProductSliderModels = homeProductSliderModels; 
} 

@Override 
public Holder onCreateViewHolder(ViewGroup parent, int viewType) { 
    HomeHotDealsItemBinding bind = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), 
      R.layout.home_hot_deals_item, parent, false); 

    return new Holder(bind); 
} 

@Override 
public void onBindViewHolder(Holder holder, int position) { 
    HomeProductSliderModel homeProductSliderModel = mHomeProductSliderModels.get(holder.getAdapterPosition()); 
    holder.bindHomeProduct(homeProductSliderModel); 
} 

@Override 
public int getItemCount() { 
    return mHomeProductSliderModels.size(); 
} 

class Holder extends RecyclerView.ViewHolder { 
    HomeHotDealsItemBinding homeHotDealsItemBind; 

    Holder(HomeHotDealsItemBinding binding) { 
     super(binding.getRoot()); 
     homeHotDealsItemBind = binding; 
    } 

    public void bindHomeProduct(@NonNull HomeProductSliderModel homeProductSlider) { 
     homeHotDealsItemBind.setHomeHotProductSlider(homeProductSlider); 
     homeHotDealsItemBind.executePendingBindings(); 
     homeHotDealsItemBind.recyclerView.setAdapter(new HomePageProductAdapter(mContext, /*mHomeProductSliderModels.get(position)*/homeProductSlider.getProductList(), screenWidth, true)); 
     homeHotDealsItemBind.executePendingBindings(); 
    } 
} 
} 

home_product_item.xml(在HomePageProductAdapter使用):

<layout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:apps="http://schemas.android.com/apk/res-auto" 
xmlns:card_view="http://schemas.android.com/tools"> 
<data> 
    <import type="android.view.View" /> 
    <variable 
     name="prod" 
     type="com.see.core_app.Model.Product" /> 
</data> 
... 
<TextView 
    android:id="@+id/str_count" 
    android:text="@{prod.quantity}"/> 

<Button 
    android:id="@+id/inc_CountButton"/> 
... 
</layout> 

product_slider.xml(在HomePageProductSliderAdapter使用):

<?xml version="1.0" encoding="utf-8"?> 
<layout xmlns:android="http://schemas.android.com/apk/res/android"> 
<data> 
    <import type="android.view.View" /> 
    <variable 
     name="homeProductSlider" 
     type="com.see.core_app.Model.HomeProductSliderModel" /> 
</data> 
... 

    <android.support.v7.widget.RecyclerView 
     android:id="@+id/product_recycler"/> 
... 
</layout> 

home_hot_deals_item。XML(在HomePageHotDealsSliderAdapter使用):

<?xml version="1.0" encoding="utf-8"?> 
<layout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:app="http://schemas.android.com/apk/res-auto" 
xmlns:tools="http://schemas.android.com/tools"> 
<data> 
    <import type="android.view.View" /> 
    <variable 
     name="homeHotProductSlider" 
     type="com.see.core_app.Model.HomeProductSliderModel" /> 
</data> 
... 
    <android.support.v7.widget.RecyclerView 
     android:id="@+id/recycler_view"/> 
... 
</layout> 

更新上@ EpicPandaForce的評論:

我改變了所有本地產品變量來一個全局變量,象下面這樣:

private Product productRealm; 

並更改where查詢onBindViewHolderinc_CountButtondec_CountButton範圍,如:

productRealm = realm.where(Product.class).equalTo(ProductFields.PRODUCT_ID, productIns.getProductId()).findFirst(); 

而且對onBindViewHolder範圍的底部寫RealmChangeListener

@Override 
public void onBindViewHolder(final Viewholder holder, final int position) { 
productRealm = realm.where ... 
    realm.executeTransaction(new Realm.Transaction() { 
... 
}); 
     productRealm.addChangeListener(new RealmChangeListener<RealmModel>() { 
     @Override 
     public void onChange(RealmModel realmModel) { 
      Product localProductRealm = (Product) realmModel; 
      if (localProductRealm.getQuantity() == null || localProductRealm.getQuantity().equalsIgnoreCase("0")) { 
       holder.HomeProductBindGrid.strCount.setText("0"); 
      } else { 
       holder.HomeProductBindGrid.strCount.setText(String.valueOf(productRealm.getQuantity())); 
      } 

      ((Product) realmModel).notifyChange(); 
     } 
    }); 
} 

但有時,notifyChange不叫!

+1

您需要保留對RealmObject的引用,並且還要註冊一個RealmChangeListener,它可以調用該項目上的'notifyChange' – EpicPandaForce

+0

@EpicPandaForce我應該在哪裏寫這個'RealmChangeListener'?原因我在多個列表中有多個項目。例如,是否只有一個構造函數的監聽者? –

+0

您很可能需要在視圖中註冊此更改偵聽器。 – EpicPandaForce

回答

0

如果不使用RealmRecyclerViewAdapter,我無法解決此問題。


解決方案:

HomePageProductAdapter

public HomePageProductAdapter(@Nullable OrderedRealmCollection<Product> data, boolean autoUpdate, boolean updateOnModification) { 
    super(data, autoUpdate, updateOnModification); 
    setHasStableIds(true); 
} 
  • 添加implementation 'io.realm:android-adapters:2.1.1'到應用程序的build.gradle
  • 刪除所有realm.where查詢onBindViewHolder
  • 刪除所有holder.HomeProductBindGrid.setProd(productRealm);綁定onBindViewHolder
  • 變化HomeProductSliderModel構造函數
    public HomeProductSliderModel(String title, OrderedRealmCollection<Product> productList) {

P.S
唯一的問題仍然是該項目從每通知更改閃爍兩次。