Context on Adapter for RecyclerView - java

I am trying to send the context from my java class to my adapter of a RecyclerView, so I can click on the elements and be redirected to an intent. Apparently, the context isn't right. I've commented its line and the app works, but as soon as i try to prove it, it starts crashing again.
I assume its a context thing, but it would be pretty helpful if there's another way to set a click method to my elements.
The exception it throw its a null pointer exception:
java.lang.RuntimeException: Unable to start activity:
java.lang.NullPointerException: Attempt to invoke virtual method 'void
android.widget.Button.setOnClickListener(android.view.View$OnClickListener)'
on a null object reference
Here is the adapter code:
public class SubsidioAdapter extends RecyclerView.Adapter<SubsidioAdapter.SubsidioViewHolder> {
private Context context;
private List<Producto> productoList;
private LayoutInflater inflater;
public SubsidioAdapter(Context context, List<Producto> productoList) {
this.context = context;
this.productoList = productoList;
this.inflater = LayoutInflater.from(context);
}
#Override
public SubsidioViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = this.inflater.inflate(R.layout.producto_item, null);
return new SubsidioViewHolder(view);
}
#Override
public void onBindViewHolder(SubsidioViewHolder subsidioViewHolder, int position) {
subsidioViewHolder.imageView.setImageResource(this.productoList.get(position).getFoto());
subsidioViewHolder.textView1.setText(this.productoList.get(position).getNombre());
subsidioViewHolder.textView2.setText(this.productoList.get(position).getDescripcion());
subsidioViewHolder.textView3.setText(this.productoList.get(position).getPrecio());
subsidioViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
context.startActivity(new
Intent(context, ModificarProductoActivity.class));
}
});
}
#Override
public int getItemCount() {
return this.productoList.size();
}
public class SubsidioViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
TextView textView1;
TextView textView2;
TextView textView3;
public SubsidioViewHolder(View itemView) {
super(itemView);
this.imageView = itemView.findViewById(R.id.fotoSub);
this.textView1 = itemView.findViewById(R.id.descSub);
this.textView2 = itemView.findViewById(R.id.nombreSub);
this.textView3 = itemView.findViewById(R.id.precioSub);
}
}
}

set an id to root element of adapter item layout, then find that view by id and use it instead of itemView ,
instead of :
subsidioViewHolder.itemView.setOnClickListener(new View.OnClickListener(){
public void onClick(View view) {
...
}
});
use:
subsidioViewHolder.rootLayout.setOnClickListener(new View.OnClickListener(){
public void onClick(View view) {
...
}
});
. and remember you can get context in recyclerView adapter inside onCreateViewHolder() without using constructor like this:
#Override
public SubsidioViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
context=viewGroup.getContext();
View view = this.inflater.inflate(R.layout.producto_item, null);
return new SubsidioViewHolder(view);
}
although it seems like that your problem is with

Related

Why i can't click my item on recyclerview

I can't click the item on recyclerview, I don't know why, so can somebody help me to clear this problem?
so this in my code in MainActivity, and I call this function in onCreate :
private void showRecyclerList(){
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
UserAdapter userAdapter = new UserAdapter(this, userModel);
recyclerView.setAdapter(userAdapter);
userAdapter.setOnItemClickCallback(new UserAdapter.OnItemClickCallback() {
#Override
public void onItemClicked(UserModel data) {
Intent intent = new Intent(MainActivity.this, UserDetailActivity.class);
intent.putExtra(UserDetailActivity.EXTRA_DATA, (Parcelable) userModel);
startActivity(intent);
}
});
}
I used the Interface from OnItemClickCallback and I up it on User Adapter, and this is my UserAdapter:
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.ListViewHolder> {
private Context context;
private List<UserModel> userData = new ArrayList<>();
private OnItemClickCallback onItemClickCallback;
public void setOnItemClickCallback(final OnItemClickCallback onItemClickCallback) {
this.onItemClickCallback = onItemClickCallback;
}
public static final String DATA_EXTRA = "data_extra";
public UserAdapter(Context context, List<UserModel> userData) {
this.context = context;
this.userData = userData;
}
#NonNull
#Override
public ListViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item_user, parent,false);
return new ListViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ListViewHolder holder, int position) {
//UserModel user = userData.get(position);
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onItemClickCallback.onItemClicked(userData.get(holder.getAdapterPosition()));
}
});
Glide.with(context)
.load(userData.get(position).getAvatarUrl())
.into(holder.imgPhoto);
holder.tvName.setText(userData.get(position).getLogin());
}
#Override
public int getItemCount() {
return userData.size();
}
public class ListViewHolder extends RecyclerView.ViewHolder
{
ImageView imgPhoto;
TextView tvName;
public ListViewHolder(View itemView) {
super(itemView);
imgPhoto = itemView.findViewById(R.id.iv_avatar);
tvName = itemView.findViewById(R.id.tv_name);
}
}
public interface OnItemClickCallback {
void onItemClicked(UserModel data);
}
and this is my error message :
java.lang.NullPointerException: Attempt to invoke interface method 'void com.dicoding.githubuserwithapi.UserAdapter$OnItemClickCallback.onItemClicked(com.dicoding.githubuserwithapi.model.UserModel)' on a null object reference
at com.dicoding.githubuserwithapi.UserAdapter$1.onClick(UserAdapter.java:60)
at android.view.View.performClick(View.java:7357)
at android.view.View.performClickInternal(View.java:7334)
at android.view.View.access$3600(View.java:808)
at android.view.View$PerformClick.run(View.java:28200)
at android.os.Handler.handleCallback(Handler.java:907)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7478)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:549)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)
I/Process: Sending signal. PID: 9602 SIG: 9
I have an error in UserAdapter line 60
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
**onItemClickCallback.onItemClicked(userData.get(holder.getAdapterPosition()));**
}
});
on my UserModel class, there is only the data from the user and I used Parcelable on it.
I think I can't get the position, but I don't know where can I fix it, so can u guys help me with this problem..
When creating LayoutInflater you should use parent.context.
View view = LayoutInflater.from(parent.context).inflate(R.layout.item_user, parent,false);
Why are you calling adapter's getAdapterPosition() if position is already available to you as a parameter of onBindViewHolder()?
onItemClickCallback.onItemClicked(userData.get(position));
When you're defining that click listener you're not using the data you passed to it.
userAdapter.setOnItemClickCallback(new UserAdapter.OnItemClickCallback() {
#Override
public void onItemClicked(UserModel data) {
Intent intent = new Intent(MainActivity.this, UserDetailActivity.class);
intent.putExtra(UserDetailActivity.EXTRA_DATA, (Parcelable) **userModel**);
startActivity(intent);
}
});

Null pointer exception trying to invoke onClick method from custom Adapter

I was trying to write own adapter class in Android Studio which looks something like this:
public class Adapter extends RecyclerView.Adapter<Adapter.MyViewHolder>{
private List<Article> articles;
private Context context;
private OnItemClickListener onItemClickListener;
public Adapter(List<Article> articles, Context context) {
this.articles = articles;
this.context = context;
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView title, desc, author, published_ad, source, time;
ImageView imageView;
ProgressBar progressBar;
OnItemClickListener onItemClickListener;
public MyViewHolder(View itemView, OnItemClickListener onItemClickListener) {
super(itemView);
itemView.setOnClickListener(this);
title = itemView.findViewById(R.id.title);
desc = itemView.findViewById(R.id.decs);
author = itemView.findViewById(R.id.author);
published_ad = itemView.findViewById(R.id.publishedAt);
source = itemView.findViewById(R.id.source);
time = itemView.findViewById(R.id.time);
imageView = itemView.findViewById(R.id.img);
progressBar = itemView.findViewById(R.id.progress_load_photo);
this.onItemClickListener = onItemClickListener;
}
#Override
public void onClick(View v) {
onItemClickListener.onItemClick(v, getAdapterPosition());
}
}
}
And the class in which I use my Adapter looks like this:
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.news, container, false);
recyclerView = view.findViewById(R.id.recyclerView);
layoutManager = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setNestedScrollingEnabled(false);
adapter = new Adapter(articles, getActivity().getApplicationContext());
recyclerView.setAdapter(adapter);
LoadJson();
return view;
}
I am getting an error about null pointer exception: "Attempt to invoke interface method 'void com.example.app2.Adapter$OnItemClickListener.onItemClick(android.view.View, int)' on a null object reference"
Your field Adapter.onItemClickListener is null until you set it up (what you never do in your actual code)
So you should test if there is a listener before trying to notify it.
#Override
public void onClick(View v) {
if (onItemClickListener != null)
onItemClickListener.onItemClick(v, getAdapterPosition());
}
And I guess you would use it in your onCreateView method :)
adapter = new Adapter(articles, getActivity().getApplicationContext());
adapter.setOnItemClickListener(() -> { System.out.println("Click !") });
recyclerView.setAdapter(adapter);

How to avoid RadioGroup checked twice in RecyclerView

I've noticed RecyclerView "recycle" the views in the adapter but i want stop RecyclerView adapter duplicate the checked action in another item of the RecyclerView.
I have 10 items drawed into a RecyclerView, each one of them have a RadioGroup with 2 RadioButton within, but when i fired the check in the first item, for example, the number ten item have a checked too.
I was reading this question but i could'nt got it work.
Using Radio button with recyclerview in android
How to avoid this?
My adapter:
...
public class PreguntaAdapter extends RecyclerView.Adapter<PreguntaAdapter.ViewHolder> {
private Context context;
private ArrayList<VistaEncuestaActivity.PreguntasSiNo> preguntas;
public ArrayList<Respuestas> respuestas = new ArrayList<Respuestas>();
public PreguntaAdapter(Context context, ArrayList<VistaEncuestaActivity.PreguntasSiNo> preguntas) {
this.context = context;
this.preguntas = preguntas;
}
public ArrayList<Respuestas> getCheckedItems() {
return respuestas;
}
#NonNull
#Override
public PreguntaAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
Context context = viewGroup.getContext();
LayoutInflater layoutInflater = LayoutInflater.from(context);
View v = layoutInflater.inflate(R.layout.item_pregunta_sino, viewGroup, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull final PreguntaAdapter.ViewHolder viewHolder, int i) {
final VistaEncuestaActivity.PreguntasSiNo currentPregunta = preguntas.get(i);
//viewHolder.pregunta.setText(currentEncuesta.getString_pregunta());
viewHolder.pregunta.setText(currentPregunta.getQuestion());
viewHolder.myLinearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
viewHolder.setIsRecyclable(false);
}
#Override
public int getItemCount() {
return preguntas.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public SharedPreferences prefs;
private LinearLayout myLinearLayout;
public TextView pregunta;
public RadioGroup radio_group;
public ViewHolder(#NonNull View itemView) {
super(itemView);
pregunta = (TextView) itemView.findViewById(R.id.pregunta);
radio_group = (RadioGroup) itemView.findViewById(R.id.radio_group_pregunta);
prefs = (SharedPreferences) context.getSharedPreferences("logged", Context.MODE_PRIVATE);
myLinearLayout = (LinearLayout) itemView.findViewById(R.id.myLinearLayout);
}
}
}
Thanks all of you for your responses. Unfortunally any response helped me to solve this issue, i used this function and i added the getItemViewType function to my adapter and it's working well now:
#Override
public int getItemViewType(int position) {
return position;
}
And going to the official google docs i could find the next information:
Return the view type of the item at position for the purposes of view recycling. The default implementation of this method returns 0, making the assumption of a single view type for the adapter. Unlike ListView adapters, types need not be contiguous. Consider using id resources to uniquely identify item view types. https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter
This make sense at the time RecyclerView "recycle" the views but when this is use it in the adapter this have a different behavior treating each view as unique.
Thank you to all of you.
RadioGroup.getCheckedRadioButtonId() is the way to go. In conjunction with a SparseArray<Integer>.
In onBindViewHolder():
On each RadioGroup, set a RadioGroup.OnCheckedChangeListener(). Add the checked state to the a SparseArray or Map<Integer,Integer> mapping the index of the item position to the updated value in RadioGroup.OnCheckedChangeListener() onCheckedChanged.
So your onBindViewHolder would look something like this:
private SparseArray<Integer> mMapping = new SparseArray<>();
public void onBindViewHolder(#NonNull final PreguntaAdapter.ViewHolder viewHolder,final int position) {
final VistaEncuestaActivity.PreguntasSiNo currentPregunta = preguntas.get(i);
//viewHolder.pregunta.setText(currentEncuesta.getString_pregunta());
viewHolder.pregunta.setText(currentPregunta.getQuestion());
viewHolder.myLinearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
viewHolder.radio_group.setOnCheckedChangeListener(new OnCheckedChangeListener(){
void onCheckedChanged(RadioGroup group,int checked) {
mMapping.put(position,checked);
}
}};
// Check to see if a previous checked value exists and restore.
if(mMapping.get(position) != null && mMapping.get(position) != -1){
radio_group.check(mMapping.get(position));
}
viewHolder.setIsRecyclable(false);
}
onCheckedChanged(RadioGroup group, int checkedId)
You should give each RadioButton a unique ID, like radioButton_1, radioButton_2 in your layout file.

How to fix "NullPointerException" on ViewHolder?

I'm trying to do the clickable RecyclerView, I watched a tutorial on how to do it, but it gave me interface NullPointerException when I click the RecyclerView.
public class ViewHolder extends RecyclerView.ViewHolder {
View mView;
private ViewHolder.ClickListener mClickListener;
public interface ClickListener{
void onItemClick(View view, int position);
}
public void setOnClickListener(ViewHolder.ClickListener clickListener){
mClickListener = clickListener;
}
public ViewHolder(View itemView){
super(itemView);
mView = itemView;
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mClickListener.onItemClick(v, getAdapterPosition()); //Line that called the Exception
}
});
}
}
Is it something that has to do with the interface? Do I need to pass the interface to adapter like this one suggests?
Here's the exception
java.lang.NullPointerException: Attempt to invoke interface method 'void com.example.jobseeker.ViewHolder$ClickListener.onItemClick(android.view.View, int)' on a null object reference
at com.example.jobseeker.ViewHolder$1.onClick(ViewHolder.java:32)
...etc.
Here's the adapter
adapter = new FirebaseRecyclerAdapter<Model, ViewHolder>(options) {
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull final ViewGroup viewGroup, int i) {
final View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.row, viewGroup, false);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TextView mCompNameTv = view.findViewById(R.id.rCompNameTv);
TextView mDescTv = view.findViewById(R.id.rDescTv);
TextView mPosTv = view.findViewById(R.id.rPosTv);
ImageView mImageTv = view.findViewById(R.id.rImageIv);
String mCompName = mCompNameTv.getText().toString();
String mDesc = mDescTv.getText().toString();
String mPos = mPosTv.getText().toString();
Drawable mDrawable = mImageTv.getDrawable();
Bitmap mBitmap = ((BitmapDrawable)mDrawable).getBitmap();
Intent intent = new Intent(viewGroup.getContext(), DetailActivity.class);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
mBitmap.compress(Bitmap.CompressFormat.PNG, 80, stream);
byte[] bytes = stream.toByteArray();
intent.putExtra("image", bytes);
intent.putExtra("companyName", mCompName);
intent.putExtra("description", mDesc);
intent.putExtra("position", mPos);
startActivity(intent);
}
});
return new ViewHolder(view);
}
#Override
protected void onBindViewHolder(#NonNull ViewHolder holder, int position, #NonNull Model model) {
holder.setDetails(model.getCompanyName(), model.getDescription(), model.getPosition(), model.getImage());
}
#Override
public int getItemCount() {
return super.getItemCount();
}
};
Most likely you have not initialized your ViewHolder class with the listener attribute. Use the setOnClickListener function to initialize the ViewHolder.
Hence your return statement from onCreateViewHolder might look like the following.
ViewHolder vh = new ViewHolder(view);
vh.setOnClickListener(clickListener); // Initialize a click listener in your Activity maybe and pass it here.
return vh;
I would like to suggest checking my answer here for a better understanding of how you can achieve the click listening in your RecyclerView.

Intent fails because of Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()

What I have: I have a RecyclerView with images of bars, coffee shops. etc
What I want: That when you click on one of these images I show you the info of the selected place, but on the moment that you click the selected image the app crashes and shows this error "Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference" on the line where i create the Intent. I have already looked for this error but i am doing everything as they say
My question: How do I fix this? Please, I would really appreciate the examples with code, i am not good at programming yet, thanks in advance
My java class
public class foodAndGo extends AppCompatActivity {
ArrayList<ClaseNueva> listalugares;
RecyclerView recyclerview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_food_and_go);
listalugares = new ArrayList<ClaseNueva>();
recyclerview = (RecyclerView) findViewById(R.id.RecyclerID);
recyclerview.setLayoutManager(new LinearLayoutManager(this));
llenarLugares();
AdapterDatos adapter = new AdapterDatos(foodAndGo.this, listalugares);
recyclerview.setAdapter(adapter);
}
private void llenarLugares() {
listalugares.add(new ClaseNueva("Restaurantes", R.drawable.carnemejor));
listalugares.add(new ClaseNueva("Bares", R.drawable.beers));
listalugares.add(new ClaseNueva("CafeterĂ­as", R.drawable.desayunosmejor));
listalugares.add(new ClaseNueva("PizzerĂ­as", R.drawable.pizzaamejor));
listalugares.add(new ClaseNueva("Favoritos", R.drawable.favoritosmejo));
}
}
My Adapter
public class AdapterDatos extends RecyclerView.Adapter<AdapterDatos.ViewHolder> {
ArrayList<ClaseNueva>listalugares;
Context context;
public AdapterDatos(foodAndGo foodAndGo, ArrayList<ClaseNueva> listalugares) {
this.context = context;
this.listalugares = listalugares;
}
static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {//quizas poner esto en estatic
TextView etiNombre;
ImageView foto;
// Context context;
public ViewHolder(View itemView) {
super(itemView);
// context = itemView.getContext();
etiNombre = (TextView) itemView.findViewById(R.id.idNombre);
foto = (ImageView) itemView.findViewById(R.id.idImagen);
}
void setOnClickListeners(){
foto.setOnClickListener(this);
}
#Override
public void onClick(View v) {
// switch (v.getId()){
// case R.id.idImagen:
// Intent intent = new Intent(context, MapsActivity.class);
// context.startActivity(intent);
// break;
// }
}
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list,null,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position) {
holder.etiNombre.setText(listalugares.get(position).getNombre());
holder.foto.setImageResource(listalugares.get(position).getFoto());
// holder.setOnClickListeners();
if (position == 0){
holder.foto.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent myIntent = new Intent(context, MapsActivity.class);
context.startActivity(myIntent);
}
});
}
}
#Override
public int getItemCount() {
return listalugares.size();
}
}
I think you forget to pass context from activity !
AdapterDatos adapter = new AdapterDatos(foodAndGo.this,listalugares);
Receive context in Adapter :-
public AdapterDatos(Context context , ArrayList<ClaseNueva> listalugares) {
this.context = context;
this.listalugares = listalugares;
}
I hope this help you!
You need to fetch the context in adapter. I've another solution for. You can get context using the code below
context = holder.foto.getContext();
So, we will get context from foto component in adapter. Lets try!
UPDATE
You need to put that code in onBindViewHolder and above
if (position == 0){

Categories

Resources