FirebaseRecyclerAdapter :将 Activity 上下文传递给 ViewHolder
FirebaseRecyclerAdapter : pass Activity Context to ViewHolder
列表项中的每个动作都是从 RecyclerView.ViewHolder
处理的实际上,我想将 Activity 上下文传递给 FirebaseRecyclerAdapter
中的 ViewHolder,所以我尝试将 Constructor 添加到此 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());
}
}
我创建了 class 并为我的目的修改了 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) {
//
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:
[class android.view.View]
at
com.letsnurture.android.firebasedatabasedemo.adapter.MyFirebaseAdapter.onCreateViewHolder(MyFirebaseAdapter.java:120)
at
android.support.v7.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:5779)
at
android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5003)
at
android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4913)
at
android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2029)
at
android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1414)
at
android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1377)
at
android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:578)
at
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)
at android.view.ViewGroup.layout(ViewGroup.java:5440)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743)
at
android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1732)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1497)
at android.view.View.layout(View.java:16651)
at android.view.ViewGroup.layout(ViewGroup.java:5440)
at
android.support.design.widget.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:120)
at
android.support.design.widget.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:42)
at
android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:1319)
at
android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:815)
at android.view.View.layout(View.java:16651)
at android.view.ViewGroup.layout(ViewGroup.java:5440)
at
android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:1191)
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 android.view.View.layout(View.java:16651)
at android.view.ViewGroup.layout(ViewGroup.java:5440)
at android.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 android.view.View.layout(View.java:16651)
at android.view.ViewGroup.layout(ViewGroup.java:5440)
at android.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)
at
android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
at android.vi
您的 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 的人。 :-)
将 Activity 上下文传递给适配器并不总是正确的处理方式。您应该创建一个您的 Activity 实现的接口并将其传递给您的适配器。
另一种流行的方法是使用 pubsub 模式来引发事件并在 EventBus.
等库发生某些事情时订阅它们
解决方案:
我创建了一个界面 OnTodoActionListener.java
如下:
public interface OnTodoActionListener {
void onCheckBoxChange(CompoundButton compoundButton, boolean checked);
void onTextViewClick(View view);
void onImageButtonClick(View view);
}
然后,我在Activity中创建了这个接口的对象为:
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());
}
};
我在我的 TodoViewHolder
中创建了一个 setter 方法并使用了它的参考如下:
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);
}
最后,我将 Activity 中创建的侦听器设置为:
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);
最后,我现在可以使用 Firebase 实时数据库创建 "Todo App" 的完整工作演示。一旦我上传它,我将 post link 到 Github。谢谢。
更新:您可以使用 firebase 数据库创建我的 Todo 应用程序演示。这是 link:Firebase Database Demo
列表项中的每个动作都是从 RecyclerView.ViewHolder
处理的实际上,我想将 Activity 上下文传递给 FirebaseRecyclerAdapter
中的 ViewHolder,所以我尝试将 Constructor 添加到此 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());
}
}
我创建了 class 并为我的目的修改了 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) {
//
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: [class android.view.View] at com.letsnurture.android.firebasedatabasedemo.adapter.MyFirebaseAdapter.onCreateViewHolder(MyFirebaseAdapter.java:120) at android.support.v7.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:5779) at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5003) at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4913) at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2029) at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1414) at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1377) at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:578) at 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) at android.view.ViewGroup.layout(ViewGroup.java:5440) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743) at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1732) at android.widget.LinearLayout.onLayout(LinearLayout.java:1497) at android.view.View.layout(View.java:16651) at android.view.ViewGroup.layout(ViewGroup.java:5440) at android.support.design.widget.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:120) at android.support.design.widget.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:42) at android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:1319) at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:815) at android.view.View.layout(View.java:16651) at android.view.ViewGroup.layout(ViewGroup.java:5440) at android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:1191) 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 android.view.View.layout(View.java:16651) at android.view.ViewGroup.layout(ViewGroup.java:5440) at android.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 android.view.View.layout(View.java:16651) at android.view.ViewGroup.layout(ViewGroup.java:5440) at android.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) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858) at android.vi
您的 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 的人。 :-)
将 Activity 上下文传递给适配器并不总是正确的处理方式。您应该创建一个您的 Activity 实现的接口并将其传递给您的适配器。 另一种流行的方法是使用 pubsub 模式来引发事件并在 EventBus.
等库发生某些事情时订阅它们解决方案:
我创建了一个界面 OnTodoActionListener.java
如下:
public interface OnTodoActionListener {
void onCheckBoxChange(CompoundButton compoundButton, boolean checked);
void onTextViewClick(View view);
void onImageButtonClick(View view);
}
然后,我在Activity中创建了这个接口的对象为:
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());
}
};
我在我的 TodoViewHolder
中创建了一个 setter 方法并使用了它的参考如下:
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);
}
最后,我将 Activity 中创建的侦听器设置为:
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);
最后,我现在可以使用 Firebase 实时数据库创建 "Todo App" 的完整工作演示。一旦我上传它,我将 post link 到 Github。谢谢。
更新:您可以使用 firebase 数据库创建我的 Todo 应用程序演示。这是 link:Firebase Database Demo