2016-07-18 16 views
3

Jede Aktion in der Liste Artikel aus RecyclerView.ViewHolder Eigentlich behandelt, ich will Aktivität Kontext ViewHolder in FirebaseRecyclerAdapter zu übergeben, so habe ich versucht Constructor dieser ViewHolder wie unten hinzuzufügen:FirebaseRecyclerAdapter: Kontextpass Aktivität zu 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()); 
    } 
} 

ich habe meine Klasse und modifizierte FirebaseRecyclerAdapter für meine Zwecke wie folgt:

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

Fehler wegen dieser Linie kommt:

return constructor.newInstance(mContext, view); 

Aber ich bekomme NoSuchMethod Ausnahme. Ich wusste, dass ich es falsch mache. Aber ich bekomme nicht den Weg, es zu tun. Kann mir jemand dabei helfen?

java.lang.RuntimeException: java.lang.NoSuchMethodException: [Klasse android.view.View] bei com.letsnurture.android.firebasedatabasedemo.adapter.MyFirebaseAdapter.onCreateViewHolder (MyFirebaseAdapter.java:120) bei android.support.v7.widget.RecyclerView $ Adapter.createViewHolder (RecyclerView.java:5779) bei android.support.v7.widget.RecyclerView $ Recycler.getViewForPosition (RecyclerView.java:5003) bei android .support.v7.widget.RecyclerVie w $ Recycler.getViewForPosition (RecyclerView.java:4913) bei android.support.v7.widget.LinearLayoutManager $ LayoutState.next (LinearLayoutManager.java:2029) bei android.support.v7.widget.LinearLayoutManager.layoutChunk (LinearLayoutManager.java:1414) bei android.support.v7.widget.LinearLayoutManager.fill (LinearLayoutManager.java:1377) bei android.support.v7.widget.LinearLayoutManager.onLayoutChildren (LinearLayoutManager.java:578) bei android.support.v7.widget.RecyclerView.dispatchLayoutStep2 (RecyclerView.java:3260) bei android.support.v7.widget.RecyclerView.dispatchLayout (RecyclerView.java:3069) bei android.support.v7.widget.RecyclerView.onLayout (RecyclerView.java:3518) bei android.view.View.layout (View.java:16651) bei android.view.ViewGroup.layout (ViewGroup.java:5440) bei android.widget.LinearLayout.setChildFrame (LinearLayout.java:1743) bei android.widget.LinearLayout.layoutHorizontal (LinearLayout.java:1732) bei android.widget.LinearLayout.onLayout (LinearLayout.java:1497) bei android.view.View.layout (View. Java: 16651) bei android.view.ViewGroup.layout (ViewGroup.java:5440) bei android.support.design.widget.HeaderScrollingViewBehavior.layoutChild (HeaderScrollingViewBehavior.java:120) bei android.support.design. widget.ViewOffsetBehavior.onLayoutChild (ViewOffsetBehavior.java:42) um android.support.design.widget.AppBarLayout $ ScrollingViewBehavior.onLayoutChild (AppBarLayout.Java: 1319) bei android.support.design.widget.CoordinatorLayout.onLayout (CoordinatorLayout.java:815) bei android.view.View.layout (View.java:16651) bei android.view.ViewGroup.layout (ViewGroup.java:5440) bei android.support.v4.widget.DrawerLayout.onLayout (DrawerLayout.java:1191) bei android.view.View.layout (View.java:16651) bei android.view. ViewGroup.layout (ViewGroup.java:5440) bei android.widget.FrameLayout.layoutChildren (FrameLayout.java:336) bei android.widget.FrameLayout.onLayout (Fr. ameLayout.java:273) bei android.view.View.layout (View.java:16651) bei android.view.ViewGroup.layout (ViewGroup.java:5440) bei android.widget.LinearLayout.setChildFrame (LinearLayout. java: 1743) bei android.widget.LinearLayout.layoutVertical (LinearLayout.java:1586) bei android.widget.LinearLayout.onLayout (LinearLayout.java:1495) bei android.view.View.layout (View.java: 16651) bei android.view.ViewGroup.layout (ViewGroup.java:5440) bei android.widget.FrameLayout.layoutChildren (FrameLayout.java:336) bei android.widget.FrameLayout.onLayout (FrameLayout.java:273) bei android.view.View.layout (View.java:16651) bei android.view.ViewGroup.layout (ViewGroup.java:5440) bei android .widget.LinearLayout.setChildFrame (LinearLayout.java:1743) bei android.widget.LinearLayout.layoutVertical (LinearLayout.java:1586) bei android.widget.LinearLayout.onLayout (LinearLayout.java:1495) bei android.view .View.layout (View.java:16651) bei android.view.ViewGroup.layout (ViewGroup.java:5440) bei android.widget.FrameLayout.layoutChildren (FrameLayout.java:336) bei android.widget.FrameLayout.onLayout (FrameLayout.java:273) bei com.android.internal.policy.PhoneWindow $ DecorView.onLayout (PhoneWindow.java:2678) bei android.view.View.layout (Blick .java-: 16651) bei android.view.ViewGroup.layout (ViewGroup.java:5440) bei android.view.ViewRootImpl.performLayout (ViewRootImpl.java:2183) bei android.view.ViewRootImpl.performTraversals (ViewRootImpl.java : 1943) bei android.view.ViewRootImpl.doTraversal (ViewRootImpl.java:1119) um android.view.ViewRootImpl $ TraversalRunnable .run (ViewRootImpl.java:6060) bei android.view.Choreographer $ CallbackRecord.run (Choreographer.java:858) bei android.vi

+0

Rückgabe constructor.newInstance (mContext, anzeigen); versuchen Rückgabe constructor.newInstance ((Activity) mContext, Ansicht); –

+0

@VishalPatoliya Ich glaube nicht, dass wir Casting brauchen. –

+0

also, versuchen Sie selbst –

Antwort

0

Lösung:

ich eine Schnittstelle geschaffen OnTodoActionListener.java wie folgt:

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

Dann habe ich eine Aufgabe dieser Schnittstelle in Tätigkeit als:

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

ich eine Setter-Methode hergestellt in meinem TodoViewHolder und benutzte seine Referenz wie folgt:

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

Und schließlich habe ich den Hörer in Aktivität erstellt als:

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

Und schließlich kann ich jetzt eine voll funktionsfähige Demoversion von „Todo App“ mit Firebase Realtime-Datenbank zu erstellen. Ich werde den Link zu Github veröffentlichen, sobald ich es hochgeladen habe. Vielen Dank.

Aktualisierung: Sie können meine Demo von Todo App mit Firebase-Datenbank erstellt haben. Hier ist Link: Firebase Database Demo

2

Ihre ViewHolder Unterklasse muss einen Konstruktor mit nur einem Parameter View . Vom FirebaseUI documentation:

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

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

Der Grund dafür ist in this code, die nur für eine einzige Unterschrift sucht. Das Hinzufügen von Code zur Suche nach einem ViewHolder(Context, View) Konstruktor könnte eine gute Ergänzung sein.Können Sie dem FirebaseUI github repo eine Feature-Anfrage hinzufügen?

Update: die feature request on Github für diejenigen, die es +1 wünschen. :-)

+0

Sure Sir. Ich würde das gerne machen .. :) –

0

Das Übergeben eines Aktivitätskontexts an Adapter ist nicht immer der richtige Weg, um Dinge zu tun. Sie sollten stattdessen eine Schnittstelle erstellen, die von Ihrer Activity implementiert und an Ihren Adapter übergeben wird. Ein anderer beliebter Weg ist es, pubsub-Muster zu verwenden, um Ereignisse auszulösen und sie zu abonnieren, wenn etwas mit Bibliotheken wie EventBus passiert.

Verwandte Themen