getAdapterPosition returns -1 in ViewHolder class - java

I'm trying to show an AlertDialog in my ViewHolder class and after clicking on accept button I'm getting the Model item with getAdapterPosition from a list of items but in Fabric Crashlytics I have 13 crashes because of ArrayIndexOutOfBoundsException which says length is 12 but the index requested is -1 and the crash is for getPaymentMode in this part of code
class ViewHolder extends RecyclerView.ViewHolder {
TextView time, capacity, description;
View button;
ImageView avatar;
ViewHolder(View v) {
super(v);
time = v.findViewById(R.id.reserve_times_time);
capacity = v.findViewById(R.id.reserve_times_capacity);
button = v.findViewById(R.id.button);
description = v.findViewById(R.id.reserve_times_description);
avatar = v.findViewById(R.id.avatar);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
alertDialogBuilder.setView(R.layout.layout_dialog);
alertDialogBuilder.setPositiveButton("accept", null);
alertDialogBuilder.setNegativeButton("cancel", null);
final AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources().getDimension(R.dimen.dialog_button_text_size));
alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources().getDimension(R.dimen.dialog_button_text_size));
alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
alertDialog.dismiss();
getPaymentMode(arrayList.get(getAdapterPosition()), button);
}
});
}
});
}
in RecyclerView source code getAdapterPosition returns -1 when owner RecyclerView is null and that will happen if activity is closed but how this can be happened? when AlertDialog is displaying user can't close activity!

According to the docs, getAdapterPosition() will return NO_POSITION (aka -1) if your view holder has already been recycled.
The adapter position of the item if it still exists in the adapter. NO_POSITION if item has been removed from the adapter, notifyDataSetChanged() has been called after the last layout pass or the ViewHolder has already been recycled.
My guess is that by the time you're clicking on your dialog button, your view holder has already been recycled. Try to store the position right when your onClick() method begins and then use it when you need it, something like:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final int position = getAdapterPosition()
//Your code here
alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
alertDialog.dismiss();
getPaymentMode(arrayList.get(position), button);
}
});
}
});

Related

How can I get the text from EditText of a recyclerview item when user clicks on a button of the same item?

I am designing a RecyclerView list. Each item of the Recyclerview contains a LinearLayout. This LinearLayout contains two views, the first one is an EditText and the second one is Button. When user taps on the button, it fires an onclick event. From onClick listener, I need to get the content of the EditText. I don't find a way to access the content of a sibling view when the user taps on another sibling view.
My question is not "how can I set on click listener to a button inside adapter". Most of the people answered how to set onClick listener to a button which is there inside the recyclerview item. My question is bit different, when I am inside onClick method which is fired from button, how will I access the edittext which is a sibling of button. Every item has one edittext, so when I click on a button how will I find the correct edittext?
For example, I have a recylerview of size 10. And each item of recyclerview contains a LinearLayout and inside linearlayout two item, one is an Edittext and the other one is a Button. when I tap on 7th items button, how will I get the text of 7th item's Edittext? I hope I have explained it well
Any help would be appreciated.
First of, you need two references: one to your EditText and one to your Button. You can get those in your ViewHolder. Next, you need an OnClickListener. The ViewHolder can conveniently also implement one but you could also use onBindViewHolder() for that.
Inside that OnClickListener you can filter out your id with a switch statement if you want to and then get the content of the EditText like this:
switch(viewId) {
case R.id.buttonId:
String text = editText.getText().toString();
// do something with that text
return true;
}
In case you implemented an OnClickListener in your ViewHolder you can then do this button.setOnClickListener(this); inside your ViewHolder to make sure onClick() is actually called when you click the button.
EDIT:
Here's some sample code that should work for your case. I'm implementing View.OnClickListener here as mentioned above.
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
EditText editText;
Button button;
public ViewHolder(View itemView) {
super(itemView);
editText = itemView.findViewById(R.id.editText);
button = itemView.findViewById(R.id.button);
button.setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch(view.getId()) {
case R.id.button:
String text = editText.getText().toString();
break;
}
}
}
This is what it would look like if you were to do it in your onBindViewHolder() (in this case you would NOT implement the OnClickListener in your ViewHolder obviously):
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String text = holder.editText.getText().toString();
}
});
}
Step 1 :Make an abstract function in your adapter.
abstract void onButtonClicked(String text);
Step 2: Declare your adapter Abstract.
Step 3: Override the method (onButtonClicked(String text);) in your activity were you have instantiated the adapter.
Step 4: In your adapter inside the onClickListener for your button call the function :
onButtonClicked(editText.getText().toString());
and you'll get the string in your activity where you overrided the method.
You can use holder pattern for RecylcerView adapter. Then you can set click listener on your button and get the text from EditText.
public class SimpleViewHolder extends RecyclerView.ViewHolder {
private EditText simpleEditText;
private Button simpleButton;
public SimpleViewHolder(final View itemView) {
super(itemView);
simpleEditText = (EditText) itemView.findViewById(R.id.simple_edit_text);
simpleButton = (Button) itemView.findViewById(R.id.simple_button);
simpleButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String text = simpleEditText.getText().toString()
}
});
}
}
You can do it inside your adapter which is being set on the recycler view.
public class MyViewHolder extends RecyclerView.ViewHolder {
public ImageView mImageView;
public MyViewHolder(View itemView) {
super(itemView);
mImageView = itemView.findViewById(R.id.imageView);
}
}
And in the bindview holder you can access the views
public void onBindViewHolder(#NonNull final ImageAdapter.MyViewHolder holder, int position) {
holder.mImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Your Code to access the edit text content
}
});
}
use a custom listener like this in the holder:
public class SimpleViewHolder extends RecyclerView.ViewHolder {
private EditText simpleEditText;
private Button simpleButton;
public SimpleViewHolder(final View itemView, final OnItemSelectedListener listener) {
super(itemView);
simpleEditText = (EditText) itemView.findViewById(R.id.simple_edit_text);
simpleButton = (Button) itemView.findViewById(R.id.simple_button);
simpleButton.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View v) {
String text = simpleEditText.getText().toString();
if(listener != null) listener.onItemSelected(text);
}
});
}
public interface OnItemSelectedListener{
void onItemSelected(String value);
}
}
Simply Use Your ViewHolder. It contains all the children you want. Implement the code inside your adapter where each item is inflated. Here is an example.
//inside the onBindViewHolder
viewHolder.button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String text = viewHolder.editText.getText().toString();
Log.d("output", text);
}
});
If you are using FirebaseUI Implement this inside the populateViewHolder for older version and onBindViewHolder for the later versions.
People put -1 when they don't know the answer or when they do not understand question. So funny!! In onclick I took parent(getParent()) from the view and accessed the second child of the parent. With that I am able to access the content of the sibling.
` public void onClick(View v) {
for(int i = 0;i<parent.getChildCount();i++){
if(parent.getChildAt(i)instanceof EditText){
passwordView = (EditText)parent.getChildAt(i);
}
}
}`

popping up an AlertDialog on click a button in a ListView

I have ListView that is populated using a CursorAdapter. In each ListView row there are too textviews and a button. An AlerDialog is supposed to pop on button click.The AlertDiaog itself is filled with a cursor.
the problem is that when i try to make and alert dialog builder it needs an argument that i don't know how to get it. the code that i"m posting here has a syntax error that i don't know how to fix it.
i tried to move the ItemClickListener to original activity class but the button has null value when i try to assign it to an object.
this is the bindView of the CursorAdapter:
public void bindView(final View view, Context context, Cursor cursor) {
//ListView list= (ListView) view.findViewById(R.id.words);
Button addButton=(Button)view.findViewById(R.id.add_btn);
addButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view1) {
//Dictionary d=new Dictionary();
AlertDialog.Builder builder=new AlertDialog.Builder(Dictionary.this); // the error
final Cursor boxes=Dictionary.getCursor();
builder.setCursor(boxes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Dictionary.getCursor().moveToPosition(i);
String text = boxes.getString(boxes.getColumnIndex("_id"));
Log.d("select", "onClick: "+text);
}
}, "name");
builder.show();
}
});
TextView english=(TextView) view.findViewById(R.id.english);
TextView farsi=(TextView) view.findViewById(R.id.farsi);
english.setText(cursor.getString(1));
farsi.setText(cursor.getString(2));
}

how can I update ArrayAdapter data individually in Android

I want to update in and ArrayAdapter a TextView when user will click + or - button. I cannot figure out how can I change data of individual in ArrayApapter.
Here is a image for better explanation what I want to do :
public View getView(int position, View countView, ViewGroup parent) {
View listView = countView;
if (listView == null) {
listView = LayoutInflater.from(getContext()).inflate(R.layout.listview, parent, false);
}
word currentWord = getItem(position);
TextView foodName = (TextView) listView.findViewById(R.id.food);
Button minus = (Button) listView.findViewById(R.id.minus);
Button add = (Button) listView.findViewById(R.id.add);
TextView total = (TextView) listView.findViewById(R.id.total);
add.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
minus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
return listView;
}
Whenever you are making a change through onclicklistener then just only change your data. like if your are using ArrayList> then just change the any value whatever you want like if your press 4th element with add+ then get the 4th item from the list and set it to +1. and then refresh your adapter with notifydatasetChanged().
In the above code you are only showing the UI part in the list whenever you will use data with you can do it then very easily.
Inside onClickListener, Increase or decrease the quantity and call onDataSetChanged().

android keep dialogbox open until user click on button [duplicate]

i am having an custom alert view which pop ups on a button click event.all the things are going fine.but the problem is:
if user clicks outside alert dialog it disappear.i want to restrict user for clicking out side.I am giving him the choice of cancel/cross button to close alert dialog.
so how to restrict user clicking outside the alert box?
code:
the code in onCreate for button click where i am calling show dialog:
final Button cdButton = (Button) findViewById(R.id.denonCdImage);
cdButton.setOnClickListener(new Button.OnClickListener(){
public void onClick(View v)
{
showDialog(CD_CATG_ID);
}
});
protected Dialog onCreateDialog(int id) {
AlertDialog.Builder builder;
Context mContext = this;
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.categorydialog,(ViewGroup) findViewById(R.id.layout_root));
GridView gridview = (GridView)layout.findViewById(R.id.gridview);
gridview.setAdapter(new ImageAdapter(this));
/** Check the id for the device type for image tobe change */
switch(id) {
case 1 : // for the cd image
gridview.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,final int position, long id) {
Toast.makeText(view.getContext(), "Image selected for CD", 3000).show();
cdImageId = getImageId(position);
int elementId = getApplicationContext().getResources().getIdentifier(cdImageId, "drawable", getPackageName());
cdImageView.setImageResource(elementId);
Log.d("CdImageid", ""+cdImageId);
closeDialog(view);
}
});
builder = new AlertDialog.Builder(mContext);
builder.setView(layout);
dialog = builder.create();
break;
default:
dialog = null;
}
/** onclick listner for the close button */
ImageView close = (ImageView) layout.findViewById(R.id.close);
close.setOnClickListener(new View.OnClickListener() {
public void onClick(View v){
dialog.dismiss();
}
});
return dialog;
}
any suggestions?
thanks!
There are two methods concerning this behaviour: setCancelable() and setCanceledOnTouchOutside() as you can see in the reference.

Cannot set EditText? Issue From dialog in a fragment - Strange - Android Java

I've come across an issue which I've never had before. I have a Fragment containing a button. This button (ViewBookingButton) shows a popup dialog. When the dialog opens I would like to set a string in an EditText (AllBooking). Unfortunately it crashes and shows NullPointerExecption. What is going wrong? Here is my code:
ViewBookingButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
AlertDialog.Builder ViewBookingHelpBuilder = new AlertDialog.Builder(getActivity());
ViewBookingHelpBuilder.setTitle("view booking:");
LayoutInflater inflater = getActivity().getLayoutInflater();
View DialogLayout = inflater.inflate(R.layout.view_booking, null);
ViewBookingHelpBuilder.setView(DialogLayout);
TextView AllBooking = (TextView)view.findViewById(R.id.AllBooking);
AllBooking.setText("Hello World");//WHEN I REMOVE THIS THE DIALOG WORKS
ViewBookingHelpBuilder.setPositiveButton("Done", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which)
{
}
});
AlertDialog helpDialog = ViewBookingHelpBuilder.create();
helpDialog.show();
}
});
Change this
TextView AllBooking = (TextView)view.findViewById(R.id.AllBooking);
to
TextView AllBooking = (TextView)DialogLayout.findViewById(R.id.AllBooking);
TextView belongs to the inflated layout and `findViewById looks for the view in the current view hierarchy.

Categories