Android RecyclerView pass position is always the last one - java

Good day, I want to pass position from RecyclerView's adapter to MainActivity, so I design a interface:
in RecyclerViewAdapter:
publuc interface recyclerViewAdapterListener{
void onDeviceConnect(data, position)
}
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
//here I call onDeviceConnect
holder.button.setOnClickListener(new View.OnClickListener(){
public void onClick(View view) {
listener.onDeviceConnect(data, position);
}
in MainActicity:
private int pos;
public void onDeviceConnect(data,position){
pos = position;
}
I know the problem is pos = position, that will be always get the last position.
but I need data and position from RecyclerView, because when my device connected,
It will change RecyclerView's item.
ex : (in MainActivity)
case BleService.ACTION_NOTIFY_ON: //here my device is connected.
updateStatus(mac,status); //update status
private void updateStatus(mac,status){
Adapter.updateItem(data, pos); //call adapter's item
}
ex : (in RecyclerViewAdapter)
public void updateItem(data,pos){
if (dataList.size() != 0){
dataList.set(pos, data);
notifyItemChanged(pos);
}
is any good idea can fix it , Thanks.

in MainActicity:
`
public class MainActicity extends AppCompatActivity implements YourRecyleAdaptor.recyclerViewAdapterListener{
private int pos;
#Override
public void onDeviceConnect(data,position){
pos = position;
}
`

Try to replace the position with holder.getAdapterPosition()
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
//here I call onDeviceConnect
holder.button.setOnClickListener(new View.OnClickListener(){
public void onClick(View view) {
listener.onDeviceConnect(data, holder.getAdapterPosition());
}
Or you can also setOnClickListener in the constructor of the ViewHolder class

Related

Recyclerview in Android Studio Error - "null object reference"

I'm new in android and I have just screwed something.
I've used recycleView template and it worked fine but I wanted to change type of my object from string to "TagsManagerObject" which contains
private String tagName;
private String gender;
private String mAgeMin;
private String mAgeMax;
private String mDistance;
since then I'm stuck with this error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.tinderapp, PID: 10921
java.lang.NullPointerException: Attempt to invoke interface method 'void com.example.tinderapp.Tags.TagsManagerAdapter$ItemClickListener.onDeleteClick(int)' on a null object reference
at com.example.tinderapp.Tags.TagsManagerAdapter$ViewHolder$1.onClick(TagsManagerAdapter.java:78)
at android.view.View.performClick(View.java:6614)
at android.view.View.performClickInternal(View.java:6587)
at android.view.View.access$3100(View.java:787)
at android.view.View$PerformClick.run(View.java:26122)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6831)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:927)
My adapter looks like:
public class TagsManagerAdapter extends RecyclerView.Adapter<TagsManagerAdapter.ViewHolder>{
private LayoutInflater mInflater;
private ImageView mDeleteImage;
private List<TagsManagerObject> mTagsManagerObject;
private ItemClickListener mItemClickListener;
// data is passed into the constructor
public TagsManagerAdapter(Context context,List<TagsManagerObject> TagsManagerObject) {
this.mInflater = LayoutInflater.from(context);
this.mTagsManagerObject = TagsManagerObject;
}
// inflates the row layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.item_tags_manager, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
// String tag = TagsManagerObject.get(position);
holder.tagName.setText("#"+mTagsManagerObject.get(position).getTagName());
holder.gender.setText(mTagsManagerObject.get(position).getGender());
holder.distance.setText(mTagsManagerObject.get(position).getmDistance());
holder.tagAge.setText(mTagsManagerObject.get(position).getmAgeMin() + "-" + mTagsManagerObject.get(position).getmAgeMax());
}
// binds the data to the TextView in each row
// total number of rows
#Override
public int getItemCount() {
return mTagsManagerObject.size();
}
public void setClickListener(ItemClickListener mItemClickListener) {
this.mItemClickListener = mItemClickListener;
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView tagName,gender,tagAge,distance;
ViewHolder(View itemView) {
super(itemView);
tagName= itemView.findViewById(R.id.tag);
gender = itemView.findViewById(R.id.tag_gender);
distance = itemView.findViewById(R.id.tag_distance);
tagAge = itemView.findViewById(R.id.tag_age);
mDeleteImage = itemView.findViewById(R.id.tag_delete);
itemView.setOnClickListener(this);
mDeleteImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getAdapterPosition();
if(position!=RecyclerView.NO_POSITION){
mItemClickListener.onDeleteClick(position); <<--- HERE IS THE ERROR
}
}
});
}
#Override
public void onClick(View view) {
if (mItemClickListener != null) mItemClickListener.onItemClick(view, getAdapterPosition());
}
}
// convenience method for getting data at click position
String getItem(int id) {
return mTagsManagerObject.get(id).toString();
}
// allows clicks events to be caught
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
void onDeleteClick(int position);
}
}
So when i click delete button it crashes. Does anyone knows why?
Thanks.
You got this exception as you you call onDeleteClick(position) on an object that is null, so you have to set a value to the mItemClickListener before calling this method onDeleteClick(position)
In your code, you have to call setClickListener() of your adapter in your activity/fragment that uses this adapter.
You need to do two things.
First, you need to check mItemClickListener for null. Doing this will prevent from null pointer exception.
mDeleteImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getAdapterPosition();
if(position!=RecyclerView.NO_POSITION){
if(mItemClickListener !=null){
mItemClickListener.onDeleteClick(position); <<--- HERE IS THE ERROR
}
}
}
}
);
And the second thing is you should set/call the setClickListener for the Activity/Fragment, using the instance of RecyclerviewAdapter.
Doing this will make the Activity/Fragment implement your ItemClickListener and onDeleteClick() method.
adapter.setClickListener(this);
Or, you can also use the Anonymous class here.
Thanks guys for help. The problem was that in my acvitivy I have:
1.Created adapter with empty taglist
2.set onclicklistener
adapter.setOnItemClickListener(new TagsManagerAdapter.OnItemClickListener() {
#Override
public void onItemClick(int position) {
}
#Override
public void onDeleteClick(int position) {
System.out.println("works?");
removeItem(position);
}
});
And then add items.
Instead
adapter.notifyDataSetChanged();
Ive used:
adapter = new TagsManagerAdapter(myTagsList);
and that caused problem, that it coudnt find my listener

Can't resolve the Context or Application while navigating from Adapter of a fragment(A) to another Fragment (B)

Am trying to navigate from one fragment (A) to another (B), but the fragment, but the first fragment (A) has a recyclerView meaning when I click on any Item I should navigate to the next one. Am using android Navigation component but I couldn't resolve the method findNavController(xxx) since it requires the ApplicationContext of the fragment. , because I tried v.getContext(), v.getApplicationContext(), mContext, but there wasn't luck.
How can I resolve this issue, below is the onBindViewHolder() in the RecyclerView Adapter class. ?
What could be the best way to reslve this
#Override
public void onBindViewHolder(#NonNull final CoordinatesViewHolder holder, int position) {
final Coordinates coord = mCoordinates.get(position);
holder.place_name.setText(coord.getmUPlaceName());
holder.view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
NavHostFragment.findNavController(xxx).navigate(R.id.action_bookmarking_to_weatherFragment);
}
});
}
It is not the responsibility of RecyclerView's adapter to redirect to another fragment.
Create interface like
public interface OnItemClickListener {
void onItemClicked(int position)
}
Inside your RecyclerView's adapter add method:
public class YourAdapterName extend RecyclerView.Adapter...
private OnItemClickListener onItemClickListener
void setOnItemClickListener(OnItemClickListener listener) {
onItemClickListener = listener
}
...
#Override
public void onBindViewHolder(#NonNull final CoordinatesViewHolder holder, int position) {
final Coordinates coord = mCoordinates.get(position);
holder.place_name.setText(coord.getmUPlaceName());
holder.view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(onItemClickListener != null) {
onItemClickListener.onItemClicked(position)
}
}
});
}
In your fragment with recycler, in place where you set adapter add code:
YourAdapterClassName adapter = new YourAdapterClassName(...init adapter...)
adapter.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClicked(int position) {
//Navigate here
}
})
yourRecyclerName.setAdapter(adapter)
Hope it'll help )

Is there a way for 2 different RecyclerViews to communicate with each other?

I have an activity that has two different recyclerviews that use two different adapters. Is there a way for the recyclerviews to communicate with each other?
For example:
userChoiceRecyclerView(second recyclerview) has a bunch of cardview objects that display text
displayRecyclerView(first recyclerview) has no information until you click a cardview object in userChoiceRecyclerView, and when you click an object in displayRecyclerView it will remove the cardview object in this recycler.
public class AnswerRecyclerViewAdapter extends RecyclerView.Adapter<AnswerViewHolder> {
private Context mContext;
private char[] mCharacterNameToChar;
public AnswerRecyclerViewAdapter(Context context, String name) {
mContext = context;
mCharacterNameToChar = name.toUpperCase().toCharArray();
}
public void answerUpdateName(String name) {
mCharacterNameToChar = name.toUpperCase().toCharArray();
notifyDataSetChanged();
}
#Override
public AnswerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
...
return viewHolder;
}
#Override
public void onBindViewHolder(AnswerViewHolder holder, int position) {
holder.mTextView.setText(...);
holder.mCardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// removes the cardviews that was updated from the
// userChoiceRecyclerView
}
});
}
#Override
public int getItemCount() {
return mCharacterNameToChar.length;
}
}
The userChoiceRecyclerView is basically the same as this recyclerview except that it already has information in cardviews. I was wondering how I can make the recyclers communicate with each other
Firs of all you will need to add a Clicklistener for every object inside for ReRecyclerView .
you will need to add this code in your adapters :
private static MyClickListener myClickListener;
.
.
public void setOnItemClickListener(MyClickListener myClickListenerHolder) {
myClickListener = myClickListenerHolder;
}
.
.
public interface MyClickListener {
void onItemClick(int position, View v);
}
and in your cardView ClickListener add :
holder.mCardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// removes the cardviews that was updated from the
myClickListener.onItemClick(position,view);
}
});
now at MainActivity.java you can control your objects clicks by adding them in onResume at your main .
example:
RecyclerView.Adapter SecondAdapter, displayRecyclerAdapter;
RecyclerView displayRecyclerView= (RecyclerView) findViewById(R.id.my_recycler_view);
.
.
#Override
protected void onResume() {
super.onResume();
((AnswerRecyclerViewAdapter) SecondAdapter).setOnItemClickListener(new AnswerRecyclerViewAdapter
.MyClickListener() {
#Override
public void onItemClick(int position, View v) {
//from here you can send data to your other RecyclerView like this
displayRecyclerAdapter = new displayRecyclerAdapterClass(Context,SomeString);
displayRecyclerView.setAdapter(displayRecyclerAdapter);
}
});
}
i hope this could help you ^_^

Android: customize a single row in RecyclerView

I have a recyclerView behanving like a list, how do I change the background color of only one view? The item I want to change the color's ID is "1", I thought about getting it in the activity by it's ID and add it a decorator, but I don't know how to, or if it's even possible.
Inside the adapter:
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.setEventNameName(i + "");
holder.settheColor(Color.parseColor("#000000"));
}
static int i;
class ViewHolder extends RecyclerView.ViewHolder{
public TextView eventName;
public RelativeLayout theLayout;
public ViewHolder(final View itemView) {
super(itemView);
eventName = (TextView)itemView.findViewById(R.id.eventName);
theLayout = (RelativeLayout)itemView.findViewById(R.id.backgroundevent);
theLayout.setId(++i);
theLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (getAdapterPosition()>0){
removeItem(getAdapterPosition());
}else {
addItem("");
}
}
});
}
public void settheColor(int theColor){
theLayout.setBackgroundColor(Color.parseColor(String.valueOf(theColor)));
}
public void setEventNameName(String TheEventName){
eventName.setText(TheEventName);
}
}
I feel you can do it in this way --
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
currentListItem = List.get(position);
if(position == 0) //this will let you know the first child item
{
holder.textview.setBackgroundColor(Color.RED);
}
}
Hope this helps!
Pretty simple, use the onBindViewHolder method of your adapter, and change the color of the view (which should be referenced in your ViewHolder)
Follow this example if you are new to the Recyclerview concept.

Using Switch in RecyclerView srcoll

I have use the Switch in the RecyclerView. It have facing the issue of recycling behaviour. When I switch on the 1st position ,it automatically on the switch at 10 postion ... I think it due to reuse of the view. How to fix it. find the screenshot:
https://www.dropbox.com/s/4ms2jf9e28fyc7u/error.png?dl=0
private void setAdapter(ArrayList data) {
ManageCategoryAdapter adapter = new ManageCategoryAdapter(data);
adapter.SetOnItemClickListener(listClick);
mRecyclerView.setAdapter(adapter);
}
public class ManageCategoryAdapter extends RecyclerView.Adapter<ManageCategoryAdapter.ViewHolder> {
private ArrayList<String> catData=new ArrayList<>();
private OnItemClickListener mItemClickListener;
public ManageCategoryAdapter(ArrayList<String> listadap) {
catData=listadap;
System.out.println("$$$$$$$$$"+"adapterclass");
}
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_manage_list, parent, false);
return new ViewHolder(v);
}
public void onBindViewHolder(ViewHolder holder, int position) {
holder.category.setText(catData.get(position));
}
public int getItemCount() {
return catData.size();
}
public void onClick(View view) {
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView category;
public Switch switchClick;
public ViewHolder(View itemView) {
super(itemView);
category=(TextView)itemView.findViewById(R.id.cat_text);
switchClick=(Switch)itemView.findViewById(R.id.switch_btn);
switchClick.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (mItemClickListener != null) {
mItemClickListener.onItemClick(v, getPosition());
}
}
}
public void myNotifyDataSetChanged(ArrayList list)
{
System.out.println("$$$notify");
catData.addAll(list);
this.notifyDataSetChanged();
}
public interface OnItemClickListener {
public void onItemClick(View view, int position);
}
public void SetOnItemClickListener(final OnItemClickListener mItemClickListener) {
this.mItemClickListener = mItemClickListener;
}
}
This how I set the adapter class
You need to use this in the adapter:
#Override
public int getItemViewType(int position) {
return position;
}
This is a very common problem with RecyclerView and there are lots of answers there in Stackoverflow.
You already have understood your problem i.e. reusing the views. So you might take a look at these answers to get a better idea about how you can overcome it.
Put an else condition everywhere you need to update a view of a list
item dynamically.
Using another list to keep track of the list items in which the
Switch is enabled or disabled. You can see this answer here.
These will do the trick for you I hope.

Categories