2017-02-27 35 views
7

我正在嘗試創建一個自定義ImageButton,當用戶停止單擊該按鈕1秒鐘時,它將累積點擊並觸發一個事件。RxJava2反彈功能在RecyclerView中無法正常工作 - Android

我用debounce函數來完成這個。

定製的ImageButton:

public class MBImageButton extends ImageButton { 

    private AtomicInteger mCounter; 
    private Disposable mDisposable; 
    private Observable<Object> observable; 
    private OnAccumulatedRequestsRead mOnAccumulatedRequestsRead; 
    private OnEverClickListener mOnEverClickListener; 
    private int emitEveryMilli = 1000; // every 1 second by default 
    private boolean shouldDisposeOnDetachFromWindow = true; 

    public MBImageButton(Context context) { 
     super(context); 
     init(); 
    } 

    public MBImageButton(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     init(); 
    } 

    public MBImageButton(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 
     init(); 
    } 

    public void setAccumulatedClickListeners(OnEverClickListener onEverClickListener, 
              OnAccumulatedRequestsRead onAccumulatedRequestsRead) { 
     setOnAccumulatedRequestsRead(onAccumulatedRequestsRead); 
     setOnEverClickListener(onEverClickListener); 
     initClickObservable(); 
     subscribe(); 
    } 

    private void initClickObservable() { 
     observable = Observable.create(emitter -> { 
      emitter.setCancellable(() -> setOnClickListener(null)); 
      try { 
       setOnClickListener(view -> { 
        try { 
         final int currentCount = mCounter.incrementAndGet(); 
         Timber.d("Clicked: " + currentCount); 
         if (mOnEverClickListener != null) { 
          mOnEverClickListener.onEveryClickListener(currentCount); 
         } 
         emitter.onNext(new Object()); 
        } catch (Exception e) { 
         emitter.onError(e); 
        } 
       }); 
      } catch (Exception e) { 
       emitter.onError(e); 
      } 
     }).doOnSubscribe(disposable -> mDisposable = disposable) 
           .debounce(emitEveryMilli, TimeUnit.MILLISECONDS); 
    } 

    private void subscribe() { 
     observable.subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread()) 
       .subscribe(o -> { 
        try { 
         final int count = mCounter.get(); 
         if(count==0) return; 
         mCounter.set(0); 
         Timber.d("Accumulated Clicks: " + count); 
         if (mOnAccumulatedRequestsRead != null) { 
          mOnAccumulatedRequestsRead.onAccumulatedRequestsReady(count); 
         } 
        } catch (Exception e) { 
         Timber.e(e); 
        } 
       }, Timber::e); 
    } 

    private void init() { 
     mCounter = new AtomicInteger(0); 
    } 

    public void disposeAccumulatedClickListeners() { 
     if (mDisposable != null) { 
      mDisposable.dispose(); 
     } 
    } 

    public void shouldDisposeOnDetachFromWindow(boolean shouldDisposeOnDetachFromWindow) { 
     this.shouldDisposeOnDetachFromWindow = shouldDisposeOnDetachFromWindow; 
    } 

    public void setEmitEveryMilliseconds(int emitEveryMilli) { 
     this.emitEveryMilli = emitEveryMilli; 
     initClickObservable(); 
     subscribe(); 
    } 

    private void setOnEverClickListener(OnEverClickListener onEverClickListener) { 
     mOnEverClickListener = onEverClickListener; 
    } 

    private void setOnAccumulatedRequestsRead(OnAccumulatedRequestsRead onAccumulatedRequestsRead) { 
     mOnAccumulatedRequestsRead = onAccumulatedRequestsRead; 
    } 

    @Override 
    protected void onDetachedFromWindow() { 
     super.onDetachedFromWindow(); 
     if (shouldDisposeOnDetachFromWindow) { 
      if (mDisposable != null) { 
       mDisposable.dispose(); 
      } 
     } 
    } 

    public interface OnAccumulatedRequestsRead { 
     void onAccumulatedRequestsReady(int count); 
    } 

    public interface OnEverClickListener { 
     void onEveryClickListener(int currentCount); 
    } 
} 

的功能設置此的ImageButton的反跳是:

setAccumulatedClickListeners(OnEverClickListener, OnAccumulatedRequestsRead) 

當我安裝這個觀點出來RecyclerView,一切工作正常,

的結果看起來像這樣,當我按順序點擊9次時:

D/MBImageButton: Clicked: 1 
D/MBImageButton: Clicked: 2 
D/MBImageButton: Clicked: 3 
D/MBImageButton: Clicked: 4 
D/MBImageButton: Clicked: 5 
D/MBImageButton: Clicked: 6 
D/MBImageButton: Clicked: 7 
D/MBImageButton: Clicked: 8 
D/MBImageButton: Clicked: 9 
D/MBImageButton: Accumulated Clicks: 9 

當我這個自定義的ImageButton添加到RecyclerView ViewHolder結果是不是相同數量的點擊正確的:

D/MBImageButton: Clicked: 1 
D/MBImageButton: Clicked: 2 
D/MBImageButton: Clicked: 1 
D/MBImageButton: Clicked: 3 
D/MBImageButton: Clicked: 2 
D/MBImageButton: Clicked: 4 
D/MBImageButton: Accumulated Clicks: 4 
D/MBImageButton: Clicked: 1 
D/MBImageButton: Accumulated Clicks: 2 
D/MBImageButton: Clicked: 2 
D/MBImageButton: Accumulated Clicks: 2 
D/MBImageButton: Accumulated Clicks: 0 
D/MBImageButton: Clicked: 1 
D/MBImageButton: Accumulated Clicks: 1 
D/MBImageButton: Accumulated Clicks: 0 
D/MBImageButton: Accumulated Clicks: 0 

這是9再次連續點擊另一個結果:

D/MBImageButton: Clicked: 1 
D/MBImageButton: Clicked: 2 
D/MBImageButton: Clicked: 1 
D/MBImageButton: Clicked: 3 
D/MBImageButton: Clicked: 2 
D/MBImageButton: Clicked: 4 
D/MBImageButton: Clicked: 3 
D/MBImageButton: Accumulated Clicks: 4 
D/MBImageButton: Clicked: 1 
D/MBImageButton: Accumulated Clicks: 3 
D/MBImageButton: Accumulated Clicks: 1 
D/MBImageButton: Accumulated Clicks: 0 
D/MBImageButton: Clicked: 1 
D/MBImageButton: Accumulated Clicks: 1 
D/MBImageButton: Accumulated Clicks: 0 
D/MBImageButton: Accumulated Clicks: 0 
D/MBImageButton: Accumulated Clicks: 0 

在這兩個次,我用相同的間隔時間點擊,但是當這個按鈕添加到RecyclerView它給出了奇怪的結果。

可能是什麼問題?

更新:

我的適配器簡化實現:

public class ProductRVAdapter extends BaseProductRVAdapter<ProductRVAdapter.ProductVH> { 

    private ProductAdapterListener mProductAdapterListener; 

    public ProductRVAdapter(List<Product> productList, ProductAdapterListener productAdapterListener) { 
     super(productList); 
     mProductAdapterListener = productAdapterListener; 
    } 

    @Override 
    public ProductVH onCreateViewHolder(ViewGroup parent, int viewType) { 
     final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_product, parent, false); 
     return new ProductVH(view); 
    } 

    @Override 
    public void onBindViewHolder(ProductVH holder, int position) { 
     holder.bind(productList.get(position), position); 

     holder.ib_decrease.setAccumulatedClickListeners(currentCount -> onProductAdapterDecreaseClicked.onClick(holder.ib_decrease), 
       count -> { 
        if (mProductAdapterListener != null) { 
         mProductAdapterListener.onProductAdapterProductChangeToWSListener(productList.get(position), position, -count); 
        } 
       }); 

     holder.ib_add.setAccumulatedClickListeners(currentCount -> onProductAdapterAddToCartClicked.onClick(holder.ib_add), 
       count -> { 
        if (mProductAdapterListener != null) { 
         mProductAdapterListener.onProductAdapterProductChangeToWSListener(productList.get(position), position, count); 
        } 
       }); 
    } 

    public interface ProductAdapterListener { 

     void onProductAdapterAddToCartClicked(Product product, int position); 

     void onProductAdapterProductChangeToWSListener(Product product, int position, int amountChanged); 

     void onProductAdapterDecreaseClicked(Product product, int position); 
    } 

    public static class ProductVH extends RecyclerView.ViewHolder { 
     @BindView(R.id.iv_productImage) 
     ImageView iv_producImage; 
     @BindView(R.id.tv_productName) 
     TextView tv_productName; 
     @BindView(R.id.tv_prodAmount) 
     MBTextView tv_prodAmount; 

     @BindView(R.id.ib_decrease) 
     MBImageButton ib_decrease; 
     @BindView(R.id.ib_add) 
     MBImageButton ib_add; 

     ProductVH(View itemView) { 
      super(itemView); 
      ButterKnife.bind(this, itemView); 
     } 


     public void bind(Product product, int position) { 
      tv_productName.setText(product.getName()); 
      tv_prodAmount.setText(product.getAmount()); 

      ImageLoader.loadImage(iv_producImage.getContext(), iv_producImage, product.getImg(), R.drawable.ic_category_item); 

      ib_decrease.setTag(position); 
      ib_add.setTag(position); 
     } 
    } 
} 
+0

你可以顯示你的適配器實現嗎? – azizbekian

+0

@azizbekian我添加了適配器實現 – MBH

+0

我看不到'getItemCount()'實現,這大概在'BaseProductRVAdapter'中。你有多少物品? – azizbekian

回答

4

我得到了解決

的主要問題是,當我在RecyclerView Adapter滾動時,搶答得到分離從窗口和函數onDetachedFromWindow被調用,在那個函數我unsubscribe (dispose)從可觀察。

的解決方案的嘗試:

1.我加入attachFunction

@Override 
protected void onAttachedToWindow() { 
    super.onAttachedToWindow(); 
    if (shouldDisposeOnDetachFromWindow) { 
     if (mDisposable != null) { 
      if (mDisposable.isDisposed()) { 
       initClickObservable(); 
       subscribe(); 
      } 
     } 
    } 
} 

2.刪除了notifyItemChanged(位置)調用

一般我使用更新一些修改後的視圖notifyItemChange()。現在我通過setText或類似的函數直接更新視圖。

它現在正常工作。