我有一个RecyclerView,其中装有2种列表项:书籍和食谱。
为此,我为书和食谱创建了一个抽象视图持有人和2个视图持有人,并将它们绑定在一起。它的工作
完美。我所坚持的是,我想在回收者视图项目上设置一个单击侦听器,并根据另一个视图中的数据来获取一些数据。
假设我的“回收者”视图有5个项目(3本书和2个食谱),我已经成功实现了这些图书项目的点击侦听器,并且结果按预期显示。
但是,对于食谱,在ABC行中会出现错误java.lang.IndexOutOfBoundsException: Index: 3, Size: 1
(在我的代码中标记在SearchResultActivity类中),除非我得到预览查看器的大小并将位置的负值重置为0。
但是我不认为这是正确的方法,因为如果我说5个不同的视图持有者,这将增加冗余代码。
问题: 如何在此处正确设置监听器?
SearhResultActivity(显示带有数据的回收者视图)
public class SearchResultActivity extends HomeActivity {
private static final String TAG = "SearchResultActivity";
private static final String TAG = "SearchResultActivity";
protected FrameLayout frames;
@BindView(R.id.search_result_recycler)
RecyclerView recyclerView;
private SearchRecyclerAdapter searchRecyclerAdapter;
private FragmentManager mFragmentManager;
private RecyclerView.LayoutManager mLayoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search_result);
ButterKnife.bind(this);
frames = findViewById(R.id.search_bar_holder);
mFragmentManager = (this).getSupportFragmentManager();
mFragmentManager.beginTransaction().add(R.id.search_bar_holder, new SearchTabFragment()).commit();
recyclerFunctions();
}
public void recyclerFunctions() {
recyclerView.setHasFixedSize(true);
// use a linear layout manager
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager);
ArrayList<Book> getBookArrayList = new ArrayList<>();
getBookArrayList = (ArrayList<Book>) getIntent().getSerializableExtra("bookList");
ArrayList<Recipe> getRecipeArrayList = new ArrayList<>();
getRecipeArrayList = (ArrayList<Recipe>) getIntent().getSerializableExtra("recipeList");
searchRecyclerAdapter = new SearchRecyclerAdapter(this);
recyclerView.setAdapter(searchRecyclerAdapter);
//searchRecyclerAdapter.add(foodData);
searchRecyclerAdapter.add(getBookArrayList);
searchRecyclerAdapter.add(getRecipeArrayList);
final ArrayList<Book> finalGetBookArrayList = getBookArrayList;
final ArrayList<Recipe> finalGetRecipeArrayList = getRecipeArrayList;
searchRecyclerAdapter.setOnItemClickListener(new SearchRecyclerAdapter.OnItemClickListener() {
@Override
public void onItemClick(int i) {
int itemType = searchRecyclerAdapter.getItemViewType(i);
Log.d(TAG, "onItemClick: " + searchRecyclerAdapter.getItemCount()+""+searchRecyclerAdapter.getItemId(i));
if (itemType == TYPE_BOOK){
Intent intent = new Intent(SearchResultActivity.this, DetailsActivity.class);
Bundle bundle=new Bundle();
bundle.putSerializable("bookData", finalGetBookArrayList.get(i));
intent.putExtras(bundle);
startActivity(intent);
} else if (itemType == TYPE_RECIPE){
int size = finalGetBookArrayList.size();
/*LINE ABC*/
Intent intent = new Intent(SearchResultActivity.this, DetailsActivity.class);
Bundle bundle=new Bundle();
bundle.putSerializable("recipeData", finalGetRecipeArrayList.get(i - size));
intent.putExtras(bundle);
startActivity(intent);
}
}
});
}
}
SearchRecyclerAdapter(此适配器保留用于声明的代码,以及通过连接到回收站视图和OnItemClickListener接口将所有viewHolders连接到抽象viewHolder的代码)
package com.example.naisse.AdapterAndClass;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.example.naisse.Api.Model.Search.Food;
import com.example.naisse.Api.Model.Search.Quran;
import com.example.naisse.R;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
public class SearchRecyclerAdapter extends RecyclerView.Adapter<SearchRecyclerAdapter.AbstractViewHolder>{
private static final String TAG = "SearchRecyclerAdapter";
public static final int TYPE_FOOD = 0;
public static final int TYPE_BOOK = 1;
private Context context;
private List<Object> data;
private OnItemClickListener mListener;
public void setOnItemClickListener(OnItemClickListener listener) {
mListener = listener;
}
public interface OnItemClickListener {
void onItemClick(int i);
}
/*I belive im missing something here*/
public SearchRecyclerAdapter(Context context){
this.context = context;
}
public void add(ArrayList newData){
if(data == null){
data = new ArrayList<>();
}
data.addAll(newData);
notifyDataSetChanged();
}
@Override
public AbstractViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
switch (i){
case TYPE_BOOK:{
/*search_result_fragment is the xml layout for food adapter*/
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.viewholder_book, viewGroup, false);
return new BookViewAdapter(view, mListener);
}
case TYPE_RECIPE:{
/*search_result_fragment is the xml layout for book adapter*/
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.viewholder_recipe, viewGroup, false);
return new RecipeViewAdapter(view, mListener);
}
default:
throw new IllegalArgumentException("Invalid view type");
}
}
@Override
public void onBindViewHolder(AbstractViewHolder abstractViewHolder, int i) {
Object object = data.get(i);
if (abstractViewHolder instanceof BookViewAdapter) {
abstractViewHolder.bind(object);
} else if (abstractViewHolder instanceof RecipeViewAdapter) {
abstractViewHolder.bind(object);
} else {
throw new IllegalArgumentException("Invalid position");
}
}
@Override
public int getItemViewType(int i){
Object object = data.get(i);
if (object instanceof Book){
return TYPE_BOOK;
}else if (object instanceof Recipe){
return TYPE_RECIPE;
}
throw new IllegalArgumentException("Invalid position");
}
@Override
public int getItemCount() {
return data == null ? 0 : data.size();
}
public abstract class AbstractViewHolder<T> extends RecyclerView.ViewHolder{
public AbstractViewHolder(@NonNull View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
public abstract void bind(T type);
}
public class BookViewAdapter extends AbstractViewHolder<Book> {
@BindView(R.id.result_book_title)
TextView bookTitle;
@BindView(R.id.result_book_content)
TextView content;
private BookViewAdapter(View itemView, final OnItemClickListener listener){
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position);
}
}
}
});
}
@Override
public void bind(Book type) {
bookTitle.setText("Book");
content.setText("title");
}
}
public class RecipeViewAdapter extends AbstractViewHolder<Recipe> {
@BindView(R.id.result_recipe_title)
TextView recipesTitle;
@BindView(R.id.result_recipe_content)
TextView content;
private RecipeViewAdapter(View itemView, final OnItemClickListener listener){
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position);
}
}
}
});
}
@Override
public void bind(Recipe type) {
recipesTitle.setText("title");
content.setText("Text");
}
}
}
我该如何解决这个问题?
答案 0 :(得分:0)
不太了解为什么要在循环中调用“ bundle.putSerializable”。但是有一种解决问题的方法,就是在两个RecipeViewAdapter的bind()函数中设置点击侦听器,如下所示:
@Override
public void bind(Recipe type) {
recipesTitle.setText("title");
content.setText("Text");
// setOnClickListener here, and pass the "type" object for further use.
// this onClickListener handles Recipe item only.
}
和
@Override
public void bind(Book type) {
bookTitle.setText("Book");
content.setText("title");
// setOnClickListener here, and pass the "type" object for further use.
// this onClickListener handles Book item only.
}
通过这种方式,您不必担心数组的索引。