After I changed the parameter of onBindViewHolder,it turned gray,and not be called,why? Here is my adapter:
public class Myadapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private List<String> lists;
private OnItemClickListener onItemClickListener;
public Myadapter(Context context, List<String> lists) {
this.context = context;
this.lists = lists;
}
public interface OnItemClickListener {
void onItemClick(View view, int postion);
void onItemLongClick(View view, int postion);
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.onItemClickListener = listener;
}
#Override
public void onBindViewHolder(final myViewHolder holder, int position) {
holder.textView.setText(lists.get(position));
if (onItemClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int postion = holder.getLayoutPosition();//得到当前点击item的位置postion
onItemClickListener.onItemClick(holder.itemView, postion);
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
int postion = holder.getLayoutPosition();
onItemClickListener.onItemLongClick(holder.itemView, postion);
return true;
}
});
}
}
#Override
public int getItemCount() {
return lists.size();
}
#Override
public myViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(context).inflate(R.layout.item,parent,false);
myViewHolder viewHolder = new myViewHolder(itemView);
return viewHolder;
}
public class myViewHolder extends RecyclerView.ViewHolder{
TextView textView;
public myViewHolder(View itemView){
super(itemView);
textView =(TextView)itemView.findViewById(R.id.text);
}
}
}
It says Myadapter must either be declared abstract of implement abstract method onBindViewHolder(VH,int) in "Adapter"
Since you are trying to use your own ViewHolder for this adapter you need to use it as the type when extending RecyclerView.Adapter.
Change:
public class Myadapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
To:
public class Myadapter extends RecyclerView.Adapter<myViewHolder> {
Related
I have a nested recyclerview with Parent RV: representing a category whereas Child RV: represents a list of items of a certain category. Currently I am getting null pointer exception but I have no idea why. I have 2 interface - 1st, takes the position of the child RV (selected item) and the 2nd one - gets the position of parent RV position (i.e. which category was selected), child RV position and title of the selected item.
Issue:
ParentRVAdapter.java:57 -> rvItemClickListener.onChildItemClick(holder.getAdapterPosition(),position,itemTitle);
CatalogItemChildRVAdapter.java:68 -> onItemListener.onItemClick(getAdapterPosition());
Parent Recycler View:
public class ParentRVAdapter extends RecyclerView.Adapter<ParentRVAdapter.ViewHolder> implements CatalogItemChildRVAdapter.onItemListener{
private Context context;
private List<CatalogCategories> categories;
private CatalogItemChildRVAdapter itemChildRVAdapter;
private List<CategoryItem> categoryItemList;
private RVItemClickListener rvItemClickListener;
public void setRvItemClickListener(RVItemClickListener rvItemClickListener) {
this.rvItemClickListener = rvItemClickListener;
}
public ParentRVAdapter(Context context, List<CatalogCategories> categories) {
this.context = context;
this.categories = categories;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.home_parentrv_item,parent,false));
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.categoryTv.setText(categories.get(position).getCatTitles());
categoryItemList = categories.get(position).getCategoryItemList();
setCategoriesItemRV(holder.itemRv, categoryItemList);
itemChildRVAdapter.setMonItemListener(new CatalogItemChildRVAdapter.onItemListener() {
#Override
public void onItemClick(int position) {
String itemTitle = categoryItemList.get(position).getTitle();
rvItemClickListener.onChildItemClick(holder.getAdapterPosition(),position,itemTitle);
System.out.println("Works");
}
});
}
#Override
public int getItemCount() {
return categories.size();
}
#Override
public void onItemClick(int position) {}
public static final class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
TextView categoryTv;
RecyclerView itemRv;
public ViewHolder(#NonNull View itemView) {
super(itemView);
categoryTv = itemView.findViewById(R.id.categoriesTv);
itemRv = itemView.findViewById(R.id.itemRv);
}
#Override
public void onClick(View view) {
}
}
private void setCategoriesItemRV(RecyclerView recyclerView, List<CategoryItem> categoryItemList){
itemChildRVAdapter = new CatalogItemChildRVAdapter(context,categoryItemList,this);
recyclerView.setLayoutManager(new LinearLayoutManager(context, RecyclerView.HORIZONTAL,false));
recyclerView.setAdapter(itemChildRVAdapter);
}
public interface RVItemClickListener{
void onChildItemClick (int parentPos, int childPos, String item);
}
}
Child RecyclerView:
public class CatalogItemChildRVAdapter extends RecyclerView.Adapter<CatalogItemChildRVAdapter.ViewHolder> {
private Context context;
private List<CategoryItem> categoryItemList;
private onItemListener monItemListener;
public void setMonItemListener(onItemListener monItemListener) {
this.monItemListener = monItemListener;
}
public CatalogItemChildRVAdapter(Context context, List<CategoryItem> categoryItemList, onItemListener monItemListener) {
this.context = context;
this.categoryItemList = categoryItemList;
this.monItemListener = monItemListener;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.childrv_eacat_item,parent,false);
return new ViewHolder(view,monItemListener);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.image.setImageResource(categoryItemList.get(position).getImage());
holder.itemname.setText(categoryItemList.get(position).getTitle());
}
#Override
public int getItemCount() {
return categoryItemList.size();
}
public static final class ViewHolder extends RecyclerView.ViewHolder {
ImageView image;
TextView itemname;
//onItemListener onItemListener;
int itempos;
public ViewHolder(#NonNull View itemView, onItemListener onItemListener) {
super(itemView);
//this.onItemListener = onItemListener;
image = itemView.findViewById(R.id.categoryitemIv1);
itemname = itemView.findViewById(R.id.categoryitemTv1);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onItemListener.onItemClick(getAdapterPosition());
itempos = getAdapterPosition();
System.out.println("Clicked at postion: "+itempos);
}
});
}
/* #Override
public void onClick(View view) {
onItemListener.onItemClick(getAdapterPosition());
itempos = getAdapterPosition();
System.out.println("Clicked at postion: "+itempos);
} */
}
public interface onItemListener{
void onItemClick(int position);
} }
I tried this many times, but now I am having trouble clicking on a GridView.
Here is my adapter.
public class MoviesAdapter extends RecyclerView.Adapter<MoviesAdapter.MoviesViewHolder>{
private Context context;
private List<Movies> moviesList;
final private MoviesAdapterOnClickHandler mClickHandler;
public interface MoviesAdapterOnClickHandler{
void onClick(String movieId);
}
public MoviesAdapter(Context context, List<Movies> moviesList, MoviesAdapterOnClickHandler mClickHandler ){
this.context = context;
this.moviesList = moviesList;
this.mClickHandler = mClickHandler;
}
#Override
public MoviesViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
int layoutIdForListItem = R.layout.movies_row;
LayoutInflater inflater = LayoutInflater.from(context);
boolean shouldAttactToParentImmediately = false;
View view = inflater.inflate(layoutIdForListItem,parent,shouldAttactToParentImmediately);
MoviesViewHolder moviesViewHolder = new MoviesViewHolder(view);
return moviesViewHolder;
}
#Override
public void onBindViewHolder(MoviesViewHolder holder, int position) {
Movies movies = moviesList.get(position);
Picasso.with(context)
.load(NetworkUtils.getImageURL(movies.getImageThumbnail()))
.placeholder(R.drawable.ic_broken_image)
.into(holder.mMovieImage);
Log.v("MovieAdapter",NetworkUtils.getImageURL(movies.getImageThumbnail()));
}
#Override
public int getItemCount() {
return moviesList.size();
}
public void setMoviesData(List<Movies> moviesList){
this.moviesList = moviesList;
notifyDataSetChanged();
}
public class MoviesViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
ImageView mMovieImage;
public MoviesViewHolder(View itemView) {
super(itemView);
mMovieImage = itemView.findViewById(R.id.movieImage);
}
#Override
public void onClick(View v) {
int adapterPosition = getAdapterPosition();
String movieId = moviesList.get(adapterPosition).getMovieId();
Log.v("MovieAdapter",movieId);
mClickHandler.onClick(movieId);
}
}
}
And part of my activity which actually implements the MoviesAdapterOnClickHandler
public class MainActivityFragment extends Fragment
implements LoaderManager.LoaderCallbacks<Object>, MoviesAdapter.MoviesAdapterOnClickHandler {
...
adapter = new MoviesAdapter(getActivity(), moviesArrayList, this);
...
#Override
public void onClick(String position) {
Toast.makeText(getActivity()," id: " + position, Toast.LENGTH_SHORT).show();
}
Any ideas?
Thanks,
Theo
Your view holder implements OnClickListener but you are not setting the listener on your view. You need to do something like view.setOnClickListener(this) in the constructor of the ViewHolder
You forget to add itemView.setOnClickListener(this); inside your MoviesViewHolder Constructor , your MoviesViewHolder implements onClick so you have to add this.
public class MoviesViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
ImageView mMovieImage;
public MoviesViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
mMovieImage = itemView.findViewById(R.id.movieImage);
}
Everything works well and my onClick in my recyclerView is working in getting the positions of my items, but what my design calls for is to be able to click an item of the recyclerView and open up a new activity (as a popover or pop up). I can achieve this but my problems comes with the information I need to display on the popover. The information comes like this inside the activity (inside a Firebase value call)
attributeList.removeAll(attributeList);
for (DataSnapshot child : dataSnapshot.child("Attribute").getChildren()){
Attribute attribute = child.getValue(Attribute.class);
attribute_list newAttributeList = new attribute_list( attribute.Name + ": " + attribute.Value);
attributeList.add(newAttributeList);
}
attributeAdapter = new attribute_list_adapter(attributeList, getContext());
recyclerAttribute.setAdapter(attributeAdapter);
This works perfectly for displaying the information, but there's more then just a "value" and a "name" associated with the click.
Basically when I select an item, I need to get the position of the item clicked (which I have) and compare it to the position inside attributeList so I can call a Firebase call (or pass the data somehow) to the popover to display values from the "Attribute" class (such as Name, Value, Description, and another list (recyclerView).
My recyclerView:
public class attribute_list_adapter extends RecyclerView.Adapter<attribute_list_adapter.ViewHolder> {
private List<attribute_list> listItems;
private Context context;
public attribute_list_adapter(List<attribute_list> listItems, Context context) {
this.listItems = listItems;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.attribute_list, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
attribute_list listItem = listItems.get(position);
holder.txtTitle.setText(listItem.getTxtTitle());
}
#Override
public int getItemCount() {
return listItems.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView txtTitle;
public ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
txtTitle = (TextView) itemView.findViewById(R.id.txtTitle);
}
#Override
public void onClick(View v) {
}
}
}
This is example:
public class attribute_list_adapter extends RecyclerView.Adapter<attribute_list_adapter.ViewHolder> {
private List<attribute_list> listItems;
private Context context;
public attribute_list_adapter(List<attribute_list> listItems, Context context) {
this.listItems = listItems;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.attribute_list, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.itemView.setOnClickListener(new View.onClickListener() {
#Override
public void onClick(View v) {
onItemClickListener.onItemClick(position);
}
});
}
#Override
public int getItemCount() {
return listItems.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView txtberita;
ImageView imgberita;
TextView txtnama;
public ViewHolder(View itemView) {
super(itemView);
txtnama = (TextView) itemView.findViewById(R.id.txtnama);
txtberita = (TextView) itemView.findViewById(R.id.txtberita);
imgberita = (ImageView) itemView.findViewById(R.id.imgberita);
}
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
OnItemClickListener onItemClickListener;
public interface OnItemClickListener{
void onItemClick(int position);
}
}
your Activity. in Oncreate()
public class TestActivity extends AppCompatActivity implements attribute_list_adapter.OnItemClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
attribute_list_adapter adapter = new attribute_list_adapter(listItems, this);
adapter.setOnItemClickListener(this);
}
#Override
public void onItemClick(int position) {
// code here
}
}
Create an interface something like
public interface OnSingleItemClickListener{
void onSingleItemClick(int position);
}
Then implement it on your ViewHolder like this
public class ViewHolder extends RecyclerView.ViewHolder implements OnSingleItemClickListener {
public ViewHolder(View itemView) {
super(itemView);
}
#Override
void onSingleItemClick(int position){
if(listItems.get(position) == listItems.get(getAdapterPosition)){
// TODO do something here
}
}
now on your OnBindViewHolder inside your adapter you must do this.
holder.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
holder.onSingleItemClick(position);
}
}):
I have to two data sets with different adapters inside a single activity and I want to use notifyDataSetChanged() however its not working for the other adapter. So inside my adapterFirst class I have LongCLickListener which is using notifyDataSetChanged() and I want to call the adapterSecond to notify too if adapterFirst is updated. The AdapterSecond data is not being updated when pressing LongClick
public class AdapterFirst extends RecyclerView.Adapter <AdapterFirst .ViewHolder> {
private List<Object> objectList;
private Context mContext;
AdapterSecond adapterSecond;
public AdapteFirst(List<Object> list) { objectList= list; }
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_list, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
//query method
notifyDataSetChanged(); //working
//here it gets the nullpointerexception error
adapterSecond = new AdapteSecond();
adapterSecond.notifyDataSetChanged();
}
});
}
#Override
public int getItemCount() {
return (objectList != null? objectList.size():0);
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView data;
public ViewHolder(View itemView) {
super(itemView);
data= (TextView) itemView.findViewById(R.id.text);
}
}
}
AdapterSecond
public class AdapterSecond extends
RecyclerView.Adapter <AdapterSecond.ViewHolder> {
private List<Object> objectList;
private Context mContext;
public AdapterSecond () {}
public AdapterSecond (List<Object> list) { objectList= list; }
#Override
public AdapterSecond.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_list_2, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final AdapterSecond.ViewHolder holder, int position) {
final Object object = objectList.get(holder.getAdapterPosition());
holder.data2.setText(object.getData());
}
#Override
public int getItemCount() {
return (objectList != null? objectList.size():0);
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView data2;
public ViewHolder(View itemView) {
super(itemView);
data2= (TextView) itemView.findViewById(R.id.text2);
}
}
}
Seems like the order of initialization of the adapters have some issues.
Just make sure that you have initialize the secondAdapter before the firstAdapter
secondAdapter= new SecondAdapter();
firstAdapter = new FirstAdapter();
Just check the order in which they initialize!
Edit
As It is a genericAdapter not simple one and I know the methods to add click listener. And it is not a good practice to do this in onCreateViewHolder. So that's why I need a better suggestion
I have created a Generic Adapter for RecyclerView in android. Now I want some suggestion to improve it. And how could I add clickListener to it.
GenericAdapter.java
public abstract class GenericAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private ArrayList<T> items;
private OnRecyclerItemClicked onRecyclerItemClicked;
public abstract RecyclerView.ViewHolder setViewHolder(ViewGroup parent);
public abstract void onBindData(RecyclerView.ViewHolder holder, T val);
public GenericAdapter(Context context, ArrayList<T> items){
this.context = context;
this.items = items;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder holder = setViewHolder(parent);
return holder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
onBindData(holder,items.get(position));
}
#Override
public int getItemCount() {
return items.size();
}
public void addItems( ArrayList<T> savedCardItemz){
items = savedCardItemz;
this.notifyDataSetChanged();
}
public T getItem(int position){
return items.get(position);
}
public void setOnRecyclerItemClicked(OnRecyclerItemClicked onRecyclerItemClicked){
this.onRecyclerItemClicked = onRecyclerItemClicked;
}
public interface OnRecyclerItemClicked{
void onItemClicked(View view,int position);
}
}
And Call it like
adapter = new GenericAdapter<MyModelClass>(context,listOfModelClass) {
#Override
public RecyclerView.ViewHolder setViewHolder(ViewGroup parent) {
final View view = LayoutInflater.from(context).inflate(R.layout.item_recycler_view, parent, false);
AViewHolder viewHolder = new AViewHolder(context, view);
return viewHolder;
}
#Override
public void onBindData(RecyclerView.ViewHolder holder1, MyModelClass val) {
MyModelClass currentCard = val;
AViewHolder holder = (AViewHolder)holder1;
holder.cardNumber.setText(currentCard.getDisplayNumber());
holder.cardHolderName.setText(currentCard.getCardHolderName());
}
};
mRecyclerView.setAdapter(adapter);
Now how and where could I add a click listener. As adding click listener to onBindData is an overhead. Need suggestion.
Have you tried adding a ViewHolder and add the clicklistener to it
Now GenericAdapter.java.
public abstract class GenericAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private List<T> items;
private OnRecyclerItemClicked onRecyclerItemClicked;
public abstract RecyclerView.ViewHolder setViewHolder(ViewGroup parent , OnRecyclerItemClicked onRecyclerItemClicked);
public abstract void onBindData(RecyclerView.ViewHolder holder, T val);
public abstract OnRecyclerItemClicked onGetRecyclerItemClickListener();
public GenericAdapter(Context context, List<T> items){
this.context = context;
this.items = items;
onRecyclerItemClicked = onGetRecyclerItemClickListener();
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder holder = setViewHolder(parent , onRecyclerItemClicked);
return holder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
onBindData(holder,items.get(position));
}
#Override
public int getItemCount() {
return items.size();
}
public void setItems( ArrayList<T> savedCardItemz){
items = savedCardItemz;
this.notifyDataSetChanged();
}
public T getItem(int position){
return items.get(position);
}
public interface OnRecyclerItemClicked{
void onItemClicked(View view,int position);
}
}
And calling it like this
GenericAdapter<CreditCardItemBO> adaptering = new GenericAdapter<CreditCardItemBO>(mContext,new ArrayList<CreditCardItemBO>()) {
#Override
public RecyclerView.ViewHolder setViewHolder(ViewGroup parent, OnRecyclerItemClicked onRecyclerItemClicked) {
final View view = LayoutInflater.from(mContext).inflate(R.layout.item_save_credit_card, parent, false);
CreditCardViewHolder viewHolder = new CreditCardViewHolder(mContext, view,onRecyclerItemClicked);
return viewHolder;
}
#Override
public void onBindData(RecyclerView.ViewHolder holder, CreditCardItemBO val) {
}
#Override
public OnRecyclerItemClicked onGetRecyclerItemClickListener() {
return new OnRecyclerItemClicked() {
#Override
public void onItemClicked(View view, int position) {
}
};
}
};
You can add the listener in the activity you have declared the RecyclerView:
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(this, recyclerView,
new RecyclerTouchListener.ClickListener() {
#Override
public void onClick(View view, int position) {
//Handle the action
}
}
#Override
public void onLongClick(View view, int position) {
}
}));
I have implemented ViewHolder in Santa solution like this:
public class EmployeeViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView employeeName;
private BaseRecyclerAdapter.OnRecyclerItemClicked mOnRecyclerItemClicked;
public EmployeeViewHolder(View view, BaseRecyclerAdapter.OnRecyclerItemClicked onRecyclerItemClicked) {
super(view);
employeeName = (TextView) view.findViewById(R.id.employee_name);
mOnRecyclerItemClicked = onRecyclerItemClicked;
view.setOnClickListener(this);
}
#Override
public void onClick(View view) {
mOnRecyclerItemClicked.onItemClicked(view, getAdapterPosition());
}
public TextView getEmployeeName() {
return employeeName;
}
}
If you need the context ad it in to constructor as a parameter.
I have created a generic adapter, the aar and the sources are at this url:
it's easy usage:
RecyclerAdapter<Customer> mAdapter = new RecyclerAdapter(customerList, CustomerViewHolder.class);
add attach listener (lambda sample)
RecyclerItemClickListener.affectOnItemClick(mRecycler, (position, view1) -> {
//action
});
see Url link more details