2016-07-18 37 views
3

每一個動作在列表項從RecyclerView.ViewHolder實際處理,我想Activity上下文傳遞給ViewHolder在FirebaseRecyclerAdapter所以我試圖構造函數添加到這個ViewHolder如下:FirebaseRecyclerAdapter:通過活動上下文來ViewHolder

public class TodoViewHolder extends RecyclerView.ViewHolder { 

    @BindView(R.id.accbListItemHome) 
    AppCompatCheckBox mAppCompatCheckBox; 
    @BindView(R.id.actvListItemHome) 
    AppCompatTextView mAppCompatTextView; 
    @BindView(R.id.acibListItemHome) 
    AppCompatImageButton mAppCompatImageButton; 
    private Context mContext; 

    public TodoViewHolder(Context context, View itemView) { 
     super(itemView); 
     mContext = context; 
     ButterKnife.bind(this, itemView); 
    } 

    public AppCompatCheckBox getmAppCompatCheckBox() { 
     return mAppCompatCheckBox; 
    } 

    public AppCompatTextView getmAppCompatTextView() { 
     return mAppCompatTextView; 
    } 

    public AppCompatImageButton getmAppCompatImageButton() { 
     return mAppCompatImageButton; 
    } 

    @OnCheckedChanged(R.id.accbListItemHome) 
    void onCheckBoxChange(CompoundButton compoundButton, boolean checked) { 
     TodoMasterModel todoMasterModel = (TodoMasterModel) compoundButton.getTag(); 
     todoMasterModel.getmTodoModel().setmIsCompleted(checked); 
     ((HomeActivity) mContext).onDoneClick(todoMasterModel, AddEditDialogFragment.ACTION_Edit); 
     Log.i("Checkbox", todoMasterModel.toString()); 
    } 

    @OnClick(R.id.actvListItemHome) 
    void onTextViewClick(View view) { 
     TodoMasterModel todoMasterModel = (TodoMasterModel) view.getTag(); 
     ((HomeActivity) mContext).showAddEditDialog(todoMasterModel, AddEditDialogFragment.ACTION_Edit); 
     Log.i("TextView", todoMasterModel.toString()); 
    } 

    @OnClick(R.id.acibListItemHome) 
    void onImageButtonClick(View view) { 
     TodoMasterModel todoMasterModel = (TodoMasterModel) view.getTag(); 
     FirebaseDatabase.getInstance().getReference("todos").child(todoMasterModel.getmId()).setValue(todoMasterModel.getmTodoModel()); 
     Log.i("Delete", todoMasterModel.toString()); 
    } 
} 

我建立了我的階級和修改FirebaseRecyclerAdapter我的目的如下:

public abstract class MyFirebaseAdapter<T, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> { 

    private Context mContext; 
    protected int mModelLayout; 
    Class<T> mModelClass; 
    Class<VH> mViewHolderClass; 
    FirebaseArray mSnapshots; 

    /** 
    * @param modelClass  Firebase will marshall the data at a location into an instance of a class that you provide 
    * @param modelLayout  This is the layout used to represent a single item in the list. You will be responsible for populating an 
    *      instance of the corresponding view with the data from an instance of modelClass. 
    * @param viewHolderClass The class that hold references to all sub-views in an instance modelLayout. 
    * @param ref    The Firebase location to watch for data changes. Can also be a slice of a location, using some 
    *      combination of <code>limit()</code>, <code>startAt()</code>, and <code>endAt()</code> 
    */ 
    public MyFirebaseAdapter(Context context, Class<T> modelClass, int modelLayout, Class<VH> viewHolderClass, Query ref) { 
     mContext = context; 
     mModelClass = modelClass; 
     mModelLayout = modelLayout; 
     mViewHolderClass = viewHolderClass; 
     mSnapshots = new FirebaseArray(ref); 

     mSnapshots.setOnChangedListener(new FirebaseArray.OnChangedListener() { 
      @Override 
      public void onChanged(EventType type, int index, int oldIndex) { 
       switch (type) { 
        case Added: 
         notifyItemInserted(index); 
         break; 
        case Changed: 
         notifyItemChanged(index); 
         break; 
        case Removed: 
         notifyItemRemoved(index); 
         break; 
        case Moved: 
         notifyItemMoved(oldIndex, index); 
         break; 
        default: 
         throw new IllegalStateException("Incomplete case statement"); 
       } 
      } 
     }); 
    } 

    /** 
    * @param modelClass  Firebase will marshall the data at a location into an instance of a class that you provide 
    * @param modelLayout  This is the layout used to represent a single item in the list. You will be responsible for populating an 
    *      instance of the corresponding view with the data from an instance of modelClass. 
    * @param viewHolderClass The class that hold references to all sub-views in an instance modelLayout. 
    * @param ref    The Firebase location to watch for data changes. Can also be a slice of a location, using some 
    *      combination of <code>limit()</code>, <code>startAt()</code>, and <code>endAt()</code> 
    */ 
    public MyFirebaseAdapter(Context context, Class<T> modelClass, int modelLayout, Class<VH> viewHolderClass, DatabaseReference ref) { 
     this(context, modelClass, modelLayout, viewHolderClass, (Query) ref); 
    } 

    public void cleanup() { 
     mSnapshots.cleanup(); 
    } 

    @Override 
    public int getItemCount() { 
     return mSnapshots.getCount(); 
    } 

    public T getItem(int position) { 
     return parseSnapshot(mSnapshots.getItem(position)); 
    } 

    /** 
    * This method parses the DataSnapshot into the requested type. You can override it in subclasses 
    * to do custom parsing. 
    * 
    * @param snapshot the DataSnapshot to extract the model from 
    * @return the model extracted from the DataSnapshot 
    */ 
    protected T parseSnapshot(DataSnapshot snapshot) { 
     return snapshot.getValue(mModelClass); 
    } 

    public DatabaseReference getRef(int position) { 
     return mSnapshots.getItem(position).getRef(); 
    } 

    @Override 
    public long getItemId(int position) { 
     // http://stackoverflow.com/questions/5100071/whats-the-purpose-of-item-ids-in-android-listview-adapter 
     return mSnapshots.getItem(position).getKey().hashCode(); 
    } 

    @Override 
    public VH onCreateViewHolder(ViewGroup parent, int viewType) { 
     ViewGroup view = (ViewGroup) LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false); 
     try { 
      Constructor<VH> constructor = mViewHolderClass.getConstructor(View.class); 
      return constructor.newInstance(mContext, view); 
     } catch (NoSuchMethodException e) { 
      throw new RuntimeException(e); 
     } catch (InvocationTargetException e) { 
      throw new RuntimeException(e); 
     } catch (InstantiationException e) { 
      throw new RuntimeException(e); 
     } catch (IllegalAccessException e) { 
      throw new RuntimeException(e); 
     } 
    } 

    @Override 
    public void onBindViewHolder(VH viewHolder, int position) { 
     T model = getItem(position); 
     populateViewHolder(viewHolder, model, position); 
    } 

    @Override 
    public int getItemViewType(int position) { 
     return mModelLayout; 
    } 

    /** 
    * Each time the data at the given Firebase location changes, this method will be called for each item that needs 
    * to be displayed. The first two arguments correspond to the mLayout and mModelClass given to the constructor of 
    * this class. The third argument is the item's position in the list. 
    * <p> 
    * Your implementation should populate the view using the data contained in the model. 
    * 
    * @param viewHolder The view to populate 
    * @param model  The object containing the data used to populate the view 
    * @param position The position in the list of the view being populated 
    */ 
    abstract protected void populateViewHolder(VH viewHolder, T model, int position); 
} 

的錯誤是因爲該行的未來:

return constructor.newInstance(mContext, view); 

但我越來越NoSuchMethod異常。我知道我做錯了。但我沒有辦法做到這一點。任何人都可以幫助我嗎?

了java.lang.RuntimeException:java.lang.NoSuchMethodException: [類android.view.View] 在 com.letsnurture.android.firebasedatabasedemo.adapter.MyFirebaseAdapter.onCreateViewHolder(MyFirebaseAdapter.java:120) 在 android.support.v7.widget.RecyclerView $ Adapter.createViewHolder(RecyclerView.java:5779) 在 android.support.v7.widget.RecyclerView $ Recycler.getViewForPosition(RecyclerView.java:5003) 在 機器人.support.v7.widget.RecyclerVie w^$ Recycler.getViewForPosition(RecyclerView.java:4913) 在 android.support.v7.widget.LinearLayoutManager $ LayoutState.next(LinearLayoutManager.java:2029) 在 android.support.v7.widget.LinearLayoutManager.layoutChunk( LinearLayoutManager.java:1414) 在 android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1377) 在 android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:578) 在 android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3260) at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3069) at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3518) at android.view.View.layout (View.java:16651) 在android.view.ViewGroup.layout(ViewGroup.java:5440) 在android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743) 在 android.widget.LinearLayout.layoutHorizo​​ntal( LinearLayout.java:1732) at android.widget.LinearLayout.onLayout(LinearLayout.java:1497) at android.view.View.layout(View。的java:16651) 在android.view.ViewGroup.layout(ViewGroup.java:5440) 在 android.support.design.widget.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:120) 在 android.support.design。 widget.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:42) at android.support.design.widget.AppBarLayout $ ScrollingViewBehavior.onLayoutChild(AppBarLayout。(android.view.java:16651) android.view.ViewGroup.layout(android:android: (ViewGroup.java:5440) 在 android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:1191) 在android.view.View.layout(View.java:16651) 在android.view。 ViewGroup.layout(ViewGroup.java:5440) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336) at android.widget.FrameLayout.onLayout(Fr ameLayout.java:273) 在android.view.View.layout(View.java:16651) 在android.view.ViewGroup.layout(ViewGroup.java:5440) 在android.widget.LinearLayout.setChildFrame(LinearLayout中。的java:1743) 在android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586) 在android.widget.LinearLayout.onLayout(LinearLayout.java:1495) 在android.view.View.layout(View.java: 16651) at android.view.ViewGroup.layout(ViewGroup.java:5440) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336) 在android.widget.FrameLayout.onLayout(FrameLayout.java:273) 在android.view.View.layout(View.java:16651) 在android.view.ViewGroup.layout(ViewGroup.java:5440) 在機器人.widget.LinearLayout.setChildFrame(LinearLayout.java:1743) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586) at android.widget.LinearLayout.onLayout(LinearLayout.java:1495) at android.view .View.layout(View.java:16651) at android.view.ViewGroup.layout(ViewGroup.java:5440) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336) at android.widget.FrameLayout.onLayout(FrameLayout.java:273) at com.android.internal.policy.PhoneWindow $ DecorView.onLayout(PhoneWindow.java:2678) at android.view.View.layout(View .java:16651) at android.view.ViewGroup.layout(ViewGroup.java:5440) at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2183) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java :1943) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1119) at android.view.ViewRootImpl $ TraversalRunnable .RUN(ViewRootImpl.java:6060) 在 android.view.Choreographer $ CallbackRecord.run(Choreographer.java:858) 在android.vi

+0

return constructor.newInstance(mContext,view); 嘗試 return constructor.newInstance((Activity)mContext,view); –

+0

@VishalPatoliya我不認爲我們需要任何鑄件。 –

+0

所以,試試你的自我 –

回答

0

解決方案:

我創建如下面的接口OnTodoActionListener.java

public interface OnTodoActionListener { 
    void onCheckBoxChange(CompoundButton compoundButton, boolean checked); 
    void onTextViewClick(View view); 
    void onImageButtonClick(View view); 
} 

然後,我創造了這個接口的一個目的是在活動爲:

private OnTodoActionListener mOnTodoActionListener; 

mOnTodoActionListener = new OnTodoActionListener() { 
     @Override 
     public void onCheckBoxChange(CompoundButton compoundButton, boolean checked) { 
      TodoMasterModel todoMasterModel = (TodoMasterModel) compoundButton.getTag(); 
      todoMasterModel.getmTodoModel().setmIsCompleted(checked); 
      onDoneClick(todoMasterModel, AddEditDialogFragment.ACTION_Edit); 
      Log.i("Checkbox", todoMasterModel.toString()); 
     } 

     @Override 
     public void onTextViewClick(View view) { 
      TodoMasterModel todoMasterModel = (TodoMasterModel) view.getTag(); 
      showAddEditDialog(todoMasterModel, AddEditDialogFragment.ACTION_Edit); 
      Log.i("TextView", todoMasterModel.toString()); 
     } 

     @Override 
     public void onImageButtonClick(View view) { 
      TodoMasterModel todoMasterModel = (TodoMasterModel) view.getTag(); 
      mDatabaseReferenceTodo.child(todoMasterModel.getmId()).setValue(null); 
      Log.i("Delete", todoMasterModel.toString()); 
     } 
    }; 

我由setter方法在我的TodoViewHolder,並使用其參考如下:

private OnTodoActionListener mOnTodoActionListener; 

public void setListener(OnTodoActionListener onTodoActionListener) { 
    mOnTodoActionListener = onTodoActionListener; 
} 

@OnCheckedChanged(R.id.accbListItemHome) 
void onCheckBoxChange(CompoundButton compoundButton, boolean checked) { 
    mOnTodoActionListener.onCheckBoxChange(compoundButton, checked); 
} 

@OnClick(R.id.actvListItemHome) 
void onTextViewClick(View view) { 
    mOnTodoActionListener.onTextViewClick(view); 
} 

@OnClick(R.id.acibListItemHome) 
void onImageButtonClick(View view) { 
    mOnTodoActionListener.onImageButtonClick(view); 
} 

最後,我設置活動創建的監聽器:

FirebaseRecyclerAdapter mHomeRecyclerAdapter = new FirebaseRecyclerAdapter<TodoModel, TodoViewHolder>(TodoModel.class, R.layout.list_item_home, TodoViewHolder.class, mDatabaseReferenceTodo) { 
     @Override 
     public void populateViewHolder(TodoViewHolder todoViewHolder, TodoModel todoModel, int position) { 

      todoViewHolder.setListener(mOnTodoActionListener); 

      TodoMasterModel todoMasterModel = new TodoMasterModel(getRef(position).getKey(), todoModel); 

      todoViewHolder.getmAppCompatCheckBox().setTag(todoMasterModel); 
      todoViewHolder.getmAppCompatTextView().setTag(todoMasterModel); 
      todoViewHolder.getmAppCompatImageButton().setTag(todoMasterModel); 

      todoViewHolder.getmAppCompatCheckBox().setChecked(todoModel.ismIsCompleted()); 
      todoViewHolder.getmAppCompatTextView().setText(todoModel.getmTodoContent()); 

     } 
    }; 
    mRecyclerView.setAdapter(mHomeRecyclerAdapter); 

最後,我現在可以創建一個使用火力地堡實時數據庫「的Todo應用程序」的全面工作演示。一旦上傳,我會將鏈接發佈到Github上。謝謝。

更新:您可以使用我的Firebase數據庫創建Todo應用程序演示。這裏的鏈接:Firebase Database Demo

2

你ViewHolder子類需要一個構造函數,只需View參數。從FirebaseUI documentation

public static class ChatHolder extends RecyclerView.ViewHolder { 
    View mView; 

    public ChatHolder(View itemView) { 
     super(itemView); 
     mView = itemView; 
    } 

的原因是this code,其中僅搜索一個簽名。添加代碼來搜索ViewHolder(Context, View)構造函數可能是一個好的補充。您可以將功能請求添加到FirebaseUI github回購中嗎?

更新:feature request on Github爲那些想要+1的人。 :-)

+0

當然可以。我很樂意這樣做.. :) –

0

將活動上下文傳遞給適配器並不總是正確的做事方式。您應該創建一個您的Activity實現的接口並將其傳遞給您的Adapter。 另一種流行的方式是使用pubsub模式來引發事件並訂閱它們,當類似EventBus這樣的庫發生某些事情時。