Android:RecyclerView的项目不会通过Databinding和Realm刷新

时间:2017-12-27 12:04:12

标签: android data-binding realm android-databinding

情境:
我有一个HomePageProductAdapter用于其他适配器(HomePageProductSliderAdapter& HomePageHotDealsSliderAdapter)。
主页有两个RecyclerView for Regular产品和Hot产品;两个列表中的某些产品相同。例如,在第一个列表中,有product1product2product3product4;在第二个列表中,有product1product5

问题:
当前在屏幕上显示的项目不会在另一个列表中刷新。例如,当我增加第一个列表中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的评论

更新

我将所有本地产品变量更改为 a 全局变量,如下所示:

private Product productRealm;

更改了whereonBindViewHolderinc_CountButton范围内的dec_CountButton查询,例如:

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

并在RealmChangeListener范围的底部写了onBindViewHolder

@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 个答案:

答案 0 :(得分: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
唯一遗留问题是每次通知更改时项目会闪烁两次。