Reputation: 2652
The title says it all, I have a RecyclerView
which is used to store values dynamically, but only one item at a time. The item contains 3 TextViews
When I add all the items normally, it works, but when I add x item, then remove the last one, and then click on "submit", the app crashes.
I do removeAt(getAdapterPosition()
in the viewholder where `removeAt(int) is :
private void removeAt(int removePosition){
grosirList.product_grosir_list.remove(removePosition);
notifyItemRemoved(removePosition);
}
And submit button :
promoConfirmBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Gson gson = new Gson();
if (postProductPromoAdapter.getGrosirList() == null){
} else {
String grosirAddJson = gson.toJson(postProductPromoAdapter.getGrosirList());
Intent intent = new Intent();
intent.putExtra("grosirPromoPrice", grosirAddJson);
intent.putExtra("promoPrice", promoPriceET.getText().toString());
setResult(RESULT_OK, intent);
finish();
}
}
});
getGrosirList()
is
public GrosirAddList getGrosirList(){
if (mAwesomeValidation.validate()){
return this.grosirList;
} else {
return null;
}
}
Basically the submit button validates the TextViews
and if it's validated, returns true.
This is where the error happens :
minRangeET.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if(!s.toString().equals("")){
grosirList.product_grosir_list.get(getAdapterPosition()).grosir_min = String.valueOf(s);
} else {
grosirList.product_grosir_list.get(getAdapterPosition()).grosir_min = null; // Error happens here
}
}
});
I save user's input to an object inside the adapter to be retrieved later through TextWatcher
This is the error log :
java.lang.ArrayIndexOutOfBoundsException: length=12; index=-1
at java.util.ArrayList.get(ArrayList.java:310)
at xx.PostProductPromoAdapter$FiturPromoHolder$1.afterTextChanged(PostProductPromoAdapter.java:236)
at android.widget.TextView.sendAfterTextChanged(TextView.java:7563)
at android.widget.TextView.setText(TextView.java:3920)
at android.widget.TextView.setText(TextView.java:3769)
at android.widget.EditText.setText(EditText.java:84)
at android.widget.TextView.setText(TextView.java:3744)
at com.basgeekball.awesomevalidation.helper.SpanHelper.setColor(SpanHelper.java:22)
at com.basgeekball.awesomevalidation.validators.ColorationValidator$1.execute(ColorationValidator.java:34)
at com.basgeekball.awesomevalidation.validators.Validator.checkFields(Validator.java:76)
at com.basgeekball.awesomevalidation.validators.ColorationValidator.trigger(ColorationValidator.java:25)
at com.basgeekball.awesomevalidation.AwesomeValidation.validate(AwesomeValidation.java:81)
at xx.getGrosirList(PostProductPromoAdapter.java:76)
at xx$3.onClick(PostProductPromoActivityRecycler.java:164)
Update :
I use this to check whether the items are valid :
public boolean filledCheck(int itemNumber){
return this.grosirList.product_grosir_list.size() > 0
&& this.grosirList.product_grosir_list.get(itemNumber - 1).grosir_price != null
&& this.grosirList.product_grosir_list.get(itemNumber - 1).grosir_max != null
&& this.grosirList.product_grosir_list.get(itemNumber - 1).grosir_min != null;
}
And this to add the values to the EditText
. Values is taken from user input using TextWatcher
if(grosirList.product_grosir_list.get(position).grosir_min == null) {
((FiturPromoHolder)holder).minRangeET.setText("");
} else {
((FiturPromoHolder)holder).minRangeET.setText(grosirList.product_grosir_list.get(position).grosir_min);
}
if(grosirList.product_grosir_list.get(position).grosir_max == null) {
((FiturPromoHolder)holder).maxRangeET.setText("");
} else {
((FiturPromoHolder)holder).maxRangeET.setText(grosirList.product_grosir_list.get(position).grosir_max);
}
if(grosirList.product_grosir_list.get(position).grosir_price == null) {
((FiturPromoHolder)holder).grossPriceET.setText("");
} else {
((FiturPromoHolder)holder).grossPriceET.setText(grosirList.product_grosir_list.get(position).grosir_price);
}
Update, here's the whole Adapter code :
public boolean uploadProductLoading = true;
private Context context;
private AwesomeValidation mAwesomeValidation;
public GrosirAddList grosirList = new GrosirAddList();
private SharedPreferencesList sharedPreferencesList;
private SharedPreferenceUtilities sharedPreferenceUtilities;
private Utilities utilities;
private UtilityUriHelper utilityUriHelper;
// Allows to remember the last item shown on screen
private int lastPosition = -1;
// User information
private String userIdString;
private String userAliasString;
private String userEmailString;
private String loginSharedPrefsString;
private String userId;
private String userAlias;
public PostProductPromoAdapter(Context context) {
this.sharedPreferencesList = new SharedPreferencesList();
this.sharedPreferenceUtilities = new SharedPreferenceUtilities();
this.context = context;
this.userIdString = sharedPreferencesList.userIDString;
this.userAliasString = sharedPreferencesList.userAliasString;
this.loginSharedPrefsString = sharedPreferencesList.loginSharedPreference;
this.utilities = new Utilities();
this.utilityUriHelper = new UtilityUriHelper();
this.userId = sharedPreferenceUtilities.getValue(context, loginSharedPrefsString, userIdString);
this.userAlias = sharedPreferenceUtilities.getValue(context, loginSharedPrefsString, userAliasString);
this.mAwesomeValidation = new AwesomeValidation(ValidationStyle.COLORATION);
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View productView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.activity_marketplace_upload_produk_fitur_promo_card, parent, false);
return new FiturPromoHolder(productView);
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
// Animation, disabled for now
// setAnimation(holder.itemView, position);
/*((FiturPromoHolder)holder).grossPriceDeleteBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// notifyItemRangeChanged(position, grosirList.product_grosir_list.size());
// notifyDataSetChanged();
// notifyItemRemoved(position);
// notifyItemRangeChanged(position, grosirList.product_grosir_list.size());
}
});*/
/*((FiturPromoHolder)holder).minRangeET.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if(!s.toString().equals("")){
if (grosirList.product_grosir_list.size() != 0){
grosirList.product_grosir_list.get(position).grosir_min = String.valueOf(s);
}
} else {
if (grosirList.product_grosir_list.size() != 0){
grosirList.product_grosir_list.get(position).grosir_min = null;
}
}
}
});
((FiturPromoHolder)holder).maxRangeET.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (!s.toString().equals("")) {
if (grosirList.product_grosir_list.size() != 0){
grosirList.product_grosir_list.get(position).grosir_max = String.valueOf(s);
}
} else {
if (grosirList.product_grosir_list.size() != 0){
grosirList.product_grosir_list.get(position).grosir_max = null;
}
}
}
});
((FiturPromoHolder)holder).grossPriceET.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (!s.toString().equals("")) {
if (grosirList.product_grosir_list.size() != 0){
grosirList.product_grosir_list.get(position).grosir_price = String.valueOf(s);
}
} else {
if (grosirList.product_grosir_list.size() != 0){
grosirList.product_grosir_list.get(position).grosir_price = null;
}
}
}
});*/
int x = holder.getLayoutPosition();
if(grosirList.product_grosir_list.get(x).grosir_min != null) {
((FiturPromoHolder)holder).minRangeET.setText(grosirList.product_grosir_list.get(x).grosir_min);
} else {
((FiturPromoHolder)holder).minRangeET.setText(null);
}
if(grosirList.product_grosir_list.get(x).grosir_max != null) {
((FiturPromoHolder)holder).maxRangeET.setText(grosirList.product_grosir_list.get(x).grosir_max);
} else {
((FiturPromoHolder)holder).maxRangeET.setText(null);
}
if(grosirList.product_grosir_list.get(x).grosir_price != null) {
((FiturPromoHolder)holder).grossPriceET.setText(grosirList.product_grosir_list.get(x).grosir_price);
} else {
((FiturPromoHolder)holder).grossPriceET.setText(null);
}
}
/**
* Here is the key method to apply the animation
*/
private void setAnimation(View viewToAnimate, int position)
{
// If the bound view wasn't previously displayed on screen, it's animated
if (position > lastPosition)
{
viewToAnimate.clearAnimation();
// Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
Animation animation = AnimationUtils.loadAnimation(context, R.anim.fade_in);
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
public boolean filledCheck(int itemNumber){
return this.grosirList.product_grosir_list.size() > 0
&& this.grosirList.product_grosir_list.get(itemNumber - 1).grosir_price.trim().length() > 0
&& this.grosirList.product_grosir_list.get(itemNumber - 1).grosir_max.trim().length() > 0
&& this.grosirList.product_grosir_list.get(itemNumber - 1).grosir_min.trim().length() > 0;
}
private void removeAt(int removePosition){
grosirList.product_grosir_list.remove(removePosition);
// notifyItemRemoved(removePosition);
// notifyItemRangeChanged(removePosition, grosirList.product_grosir_list.size());
// notifyDataSetChanged();
notifyItemRemoved(removePosition);
notifyDataSetChanged();
// notifyItemRangeRemoved(removePosition, grosirList.product_grosir_list.size());
// notifyItemRangeChanged(removePosition, grosirList.product_grosir_list.size());
}
private void removeRange(int removePosition){
int tempSize = grosirList.product_grosir_list.size();
for (int i = removePosition; i < tempSize; i++){
grosirList.product_grosir_list.remove(removePosition);
// notifyItemRemoved(i);
}
notifyDataSetChanged();
// notifyItemRangeRemoved(removePosition, grosirList.product_grosir_list.size());
// notifyItemRangeChanged(0, this.grosirList.product_grosir_list.size());
}
private void clearAnimation(View viewToAnimate, int position)
{
// If the bound view wasn't previously displayed on screen, it's animated
viewToAnimate.clearAnimation();
}
public void addGrosirList(GrosirAddList dataset){
this.grosirList.product_grosir_list.addAll(dataset.product_grosir_list);
notifyDataSetChanged();
// notifyItemInserted(grosirList.product_grosir_list.size() - 1);
// this.grosirList.add(grosirList.size(), dataset.product_grosir_list.get());
// notifyItemInserted(grosirList.size() - 1);
}
public GrosirAddList getGrosirList(){
if (mAwesomeValidation.validate()){
return this.grosirList;
} else {
return null;
}
// return this.grosirList;
}
@Override
public int getItemCount() {
return grosirList.product_grosir_list.size();
}
public class FiturPromoHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
Handler handler;
RelativeLayout minRangeWrapper;
OpenSansEditText minRangeET;
RelativeLayout maxRangeWrapper;
OpenSansEditText maxRangeET;
RelativeLayout grossPriceWrapper;
OpenSansEditText grossPriceET;
OpenSansButton grossPriceDeleteBtn;
public FiturPromoHolder(View promoView) {
super(promoView);
minRangeWrapper = (RelativeLayout)promoView.findViewById(R.id.fragment_marketplace_upload_produk_fitur_promo_card_minRangeWrapper);
minRangeWrapper.setOnClickListener(this);
minRangeET = (OpenSansEditText)promoView.findViewById(R.id.fragment_marketplace_upload_produk_fitur_promo_card_minRangeET);
maxRangeWrapper = (RelativeLayout)promoView.findViewById(R.id.fragment_marketplace_upload_produk_fitur_promo_card_maxRangeWrapper);
maxRangeWrapper.setOnClickListener(this);
maxRangeET = (OpenSansEditText)promoView.findViewById(R.id.fragment_marketplace_upload_produk_fitur_promo_card_maxRangeET);
grossPriceWrapper = (RelativeLayout)promoView.findViewById(R.id.fragment_marketplace_upload_produk_fitur_promo_card_grossPriceWrapper);
grossPriceWrapper.setOnClickListener(this);
grossPriceET = (OpenSansEditText)promoView.findViewById(R.id.fragment_marketplace_upload_produk_fitur_promo_card_grossPriceET);
grossPriceDeleteBtn = (OpenSansButton)promoView.findViewById(R.id.fragment_marketplace_upload_produk_fitur_promo_card_grossPriceDeleteBtn);
grossPriceDeleteBtn.setOnClickListener(this);
this.setIsRecyclable(false);
handler = new Handler();
minRangeET.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(final CharSequence s, int start, int before, int count) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
grosirList.product_grosir_list.get(getLayoutPosition()).grosir_min = String.valueOf(s);
}
}, 200);
}
@Override
public void afterTextChanged(Editable s) {
}
});
maxRangeET.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(final CharSequence s, int start, int before, int count) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
grosirList.product_grosir_list.get(getLayoutPosition()).grosir_max = String.valueOf(s);
}
}, 200);
}
@Override
public void afterTextChanged(Editable s) {
}
});
grossPriceET.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(final CharSequence s, int start, int before, int count) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
grosirList.product_grosir_list.get(getLayoutPosition()).grosir_price = String.valueOf(s);
}
}, 200);
}
@Override
public void afterTextChanged(Editable s) {
}
});
grossPriceET.addTextChangedListener(new NumberTextWatcher(grossPriceET));
mAwesomeValidation.addValidation(minRangeET, RegexTemplate.NOT_EMPTY, "Jumlah minimum tidak boleh kosong");
mAwesomeValidation.addValidation(maxRangeET, RegexTemplate.NOT_EMPTY, "Jumlah maximum tidak boleh kosong");
mAwesomeValidation.addValidation(grossPriceET, RegexTemplate.NOT_EMPTY, "Harga tidak boleh kosong");
}
@Override
public void onClick(View v) {
if (v.equals(grossPriceDeleteBtn)) {
int removePosition = getAdapterPosition();
try {
grosirList.product_grosir_list.remove(removePosition);
notifyItemRemoved(removePosition);
notifyDataSetChanged();
minRangeET.setError(null);
maxRangeET.setError(null);
grossPriceET.setError(null);
//
mAwesomeValidation.addValidation(minRangeET, RegexTemplate.NOT_EMPTY, "Jumlah minimum tidak boleh kosong");
mAwesomeValidation.addValidation(maxRangeET, RegexTemplate.NOT_EMPTY, "Jumlah maximum tidak boleh kosong");
mAwesomeValidation.addValidation(grossPriceET, RegexTemplate.NOT_EMPTY, "Harga tidak boleh kosong");
}catch (ArrayIndexOutOfBoundsException e){e.printStackTrace();}
} else if(v.equals(minRangeWrapper)) {
minRangeET.requestFocusFromTouch();
} else if(v.equals(maxRangeWrapper)) {
maxRangeET.requestFocusFromTouch();
} else if(v.equals(grossPriceWrapper)) {
grossPriceET.requestFocusFromTouch();
}
}
}
Hopefully the mistake isn't so stupid.....
Upvotes: 2
Views: 2587
Reputation: 2818
May be it's due to the animation while we use notifyItemRemoved()
. So during that animation delay, if we instantly call getAdapterPosition()
method, then it'll return -1
. I had the same issue while I repeatedly remove more than one items instantly, I got this exception.
Possible solution: You can just first check position first, like below code:
private void removeAt(int removePosition){
if(removePosition == -1)
return;
grosirList.product_grosir_list.remove(removePosition);
notifyItemRemoved(removePosition);
}
This is a late answer, but Hope that helps! :)
Upvotes: 2
Reputation:
There might be several reasons for this. First of all, check your getItemCount()
in your Adapter, make sure it returns the size of your stack. Second, instead of notifyItemRemoved()
notify your adapter that the stack has changed with notifyDataSetChanged()
If above those not solve your issue please post your Adapter code, and every code that you work around with your stack. Problems should be rising from one of those points.
Best, Renç.
Upvotes: 0