1

I had this working in the past, but I made some changes to my code and now, whenever I delete a row from the ListView and click on one of the remaining rows, I am getting IndexOutOfBoundsException: Index: 1, Size: 1.

This only seems to be happening when there is a single row remaining. If there are more than one row remain, this error does not appear.

enter image description here The image above shows that the when there are more than one row remaining the error does not occur.

I am not sure why this would be happening since none of the code for selecting and deleting a row has changed.

I have checked other posts on this site but none of them seem to be similar to what I am experiencing.

Android IndexOutOfBoundsException: Index: 1, Size: 1

OutOfBoundException index:1, size:1

java jtable removeRow : java.lang.IndexOutOfBoundsException: Index: 1, Size: 1

I have posted my code below.

Logcat:

java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
        at java.util.ArrayList.get(ArrayList.java:411)
        at ca.rvogl.tpbcui.views.LeagueAdapter$2.onClick(LeagueAdapter.java:116)
        at android.view.View.performClick(View.java:5637)
        at android.view.View$PerformClick.run(View.java:22429)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6119)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

Code for selecting a row in the listview:

@Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        League league = leaguesList.get(position);
        int id = league.getId();
        String leagueId = String.valueOf(id);
        holder.id.setText(leagueId);
        holder.name.setText(league.getName());
        holder.basescore.setText(league.getBaseScore());
        holder.basescorepercentage.setText(league.getBaseScorePercentage());
        if (league.getAverage() != "") {
            holder.leagueAverage.setText(String.format("League Avg: %s", league.getAverage()));
        } else {
            holder.leagueAverage.setText(String.format("League Avg: %s", "0"));
        }
        //Formatting And Displaying Timestamp
        holder.timestamp.setText(formatDate(league.getTimestamp()));
        holder.buttonViewOption.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                //creating a popup menu
                PopupMenu popup = new PopupMenu(context, holder.buttonViewOption);
                //inflating menu from xml resource
                popup.inflate(R.menu.league_options_menu);
                //adding click listener
                popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                    @Override
                    public boolean onMenuItemClick(MenuItem item) {
                        switch (item.getItemId()) {
                            case R.id.profile:
                                ((MainActivity) context).showLeagueDialog(true, leaguesList.get(position), position);
                                break;
                            case R.id.delete:
                                ((MainActivity) context).deleteLeague(position);
                                break;
                        }
                        return false;
                    }
                });
                //displaying the popup
                popup.show();

            }
        });
        holder.name.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                int leagueId = leaguesList.get(position).getId();
                Intent myIntent = new Intent(context, BowlerActivity.class);
                myIntent.putExtra("leagueId", leagueId);
                context.startActivity(myIntent);
            }
        });
    }

Code for deleting a row:

//Deleting League From SQLite Database And Removing The League Item From The List By Its Position
    public void deleteLeague(int position) {

        Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), "Series will be deleted.", Snackbar.LENGTH_LONG)
               .setActionTextColor(Color.YELLOW)
               .setAction("OK", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //Deleting The League From The Database
                        db.deleteLeague(leaguesList.get(position));
                        //Removing League From The List
                        leaguesList.remove(position);
                        mAdapter.notifyItemRemoved(position);
                        toggleEmptyLeagues();
                   }
                });
        snackbar.show();
    }

The error seems to be happening with this line int leagueId = leaguesList.get(position).getId();

Any help getting this error fixed would be greatly appreciated.

BowlerActivity.java

public class BowlerActivity extends AppCompatActivity {

    private BowlerAdapter mAdapter;
    private final List<Bowler> bowlersList = new ArrayList<>();
    private TextView noBowlersView;

    private DatabaseHelper db;

    private TextView leagueId;
    private String savedLeagueId;

    private TextView seriesleagueId;
    private String seriesLeagueId;
    private TextView bowlerAverage;
    private TextView bowlerHandicap;
    private String savedBowlerAverage;


    private static final String PREFS_NAME = "prefs";
    private static final String PREF_BLUE_THEME = "blue_theme";
    private static final String PREF_GREEN_THEME = "green_theme";
    private static final String PREF_ORANGE_THEME = "purple_theme";
    private static final String PREF_RED_THEME = "red_theme";
    private static final String PREF_YELLOW_THEME = "yellow_theme";


    @Override protected void onResume() {
        super.onResume();
        db = new DatabaseHelper( this );
        mAdapter.notifyDatasetChanged( db.getAllBowlers( savedLeagueId ) );
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        //Use Chosen Theme
        SharedPreferences preferences = getSharedPreferences( PREFS_NAME, MODE_PRIVATE );
        boolean useBlueTheme = preferences.getBoolean( PREF_BLUE_THEME, false );
        if (useBlueTheme) {
            setTheme( R.style.AppTheme_Blue_NoActionBar );
        }
        boolean useGreenTheme = preferences.getBoolean( PREF_GREEN_THEME, false );
        if (useGreenTheme) {
            setTheme( R.style.AppTheme_Green_NoActionBar );
        }
        boolean useOrangeTheme = preferences.getBoolean( PREF_ORANGE_THEME, false );
        if (useOrangeTheme) {
            setTheme( R.style.AppTheme_Orange_NoActionBar );
        }
        boolean useRedTheme = preferences.getBoolean( PREF_RED_THEME, false );
        if (useRedTheme) {
            setTheme( R.style.AppTheme_Red_NoActionBar );
        }
        boolean useYellowTheme = preferences.getBoolean( PREF_YELLOW_THEME, false );
        if (useYellowTheme) {
            setTheme( R.style.AppTheme_Yellow_NoActionBar );
        }

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bowler);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        Objects.requireNonNull( getSupportActionBar() ).setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setDisplayShowHomeEnabled(true);

        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(getApplicationContext(),MainActivity.class));
                finish();
                overridePendingTransition(0, 0);

            }
        });

        savedLeagueId = String.valueOf(getIntent().getIntExtra("leagueId",2));
        leagueId = findViewById(R.id.tvLeagueId);
        bowlerAverage = (TextView) findViewById(R.id.tvBowlerAverage);

                bowlerHandicap = (TextView) findViewById(R.id.tvBowlerHandicap);

        CoordinatorLayout coordinatorLayout = findViewById( R.id.coordinator_layout );
        RecyclerView recyclerView = findViewById( R.id.recycler_view );
        noBowlersView = findViewById(R.id.empty_bowlers_view);

        db = new DatabaseHelper(this);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.add_bowler_fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                showBowlerDialog(false, null, -1);
            }
        });

        mAdapter = new BowlerAdapter(this, bowlersList);
        RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
        recyclerView.setLayoutManager(mLayoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        //recyclerView.addItemDecoration(new MyDividerItemDecoration(this, LinearLayoutManager.VERTICAL, 16));
        recyclerView.setAdapter(mAdapter);

        toggleEmptyBowlers();
    }

    //Inserting New Bowler In The Database And Refreshing The List
    private void createBowler(String leagueId, String bowlerName) {
        String bowlerAverage = "0";
        //Inserting Bowler In The Database And Getting Newly Inserted Bowler Id
        long id = db.insertBowler(leagueId, bowlerName, bowlerAverage);

        //Get The Newly Inserted Bowler From The Database
        Bowler n = db.getBowler(leagueId);

        if (n != null) {
            //Adding New Bowler To The Array List At Position 0
            bowlersList.add( 0, n );
            //Refreshing The List
            mAdapter.notifyDatasetChanged(db.getAllBowlers(savedLeagueId));
            //mAdapter.notifyDataSetChanged();
            toggleEmptyBowlers();
        }
    }

    //Updating Bowler In The Database And Updating The Item In The List By Its Position
    private void updateBowler(String bowlerName, int position) {
        Bowler n = bowlersList.get(position);

        //Updating Bowler Text
        n.setLeagueId(savedLeagueId);
        n.setName(bowlerName);

        //Updating The Bowler In The Database
        db.updateBowler(n);

        //Refreshing The List
        bowlersList.set(position, n);
        mAdapter.notifyItemChanged(position);

        toggleEmptyBowlers();
    }

    //Deleting Bowler From SQLite Database And Removing The Bowler Item From The List By Its Position
    public void deleteBowler(int position) {

        Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), "Series will be deleted.", Snackbar.LENGTH_LONG)
                .setActionTextColor(Color.YELLOW)
                .setAction("OK", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //Deleting The Bowler From The Database
                        db.deleteBowler(bowlersList.get(position));
                        //Removing The Bowler From The List
                        bowlersList.remove(position);
                        mAdapter.notifyItemRemoved(position);
                        db.leagueAverageScore(savedLeagueId);
                        toggleEmptyBowlers();
                    }
                });
        snackbar.show();
    }


    //Opens Dialog With Edit/Delete Options

    private void showActionsDialog(final int position) {
        LayoutInflater layoutInflaterAndroid = LayoutInflater.from(getApplicationContext());
        View view = View.inflate(this, R.layout.dialog_options_1, null);

        final AlertDialog.Builder alertDialogBuilderUserInput = new AlertDialog.Builder(new ContextThemeWrapper(BowlerActivity.this, R.style.AppTheme));
        alertDialogBuilderUserInput.setView(view);
        alertDialogBuilderUserInput.setCancelable(true);

        final AlertDialog alertDialog = alertDialogBuilderUserInput.create();

        //Cancel
        final ImageButton cancel_btn = (ImageButton) view.findViewById(R.id.cancel);
        cancel_btn.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                alertDialog.cancel();
            }
        });

        //Edit
        ImageButton edit_btn = (ImageButton) view.findViewById(R.id.edit);
        edit_btn.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                showBowlerDialog(true, bowlersList.get(position), position);
                alertDialog.dismiss();
            }
        });

        ImageButton delete_btn = (ImageButton) view.findViewById(R.id.delete);
        delete_btn.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

                Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), "Bowler will be deleted.", Snackbar.LENGTH_LONG)
                        .setAction("OK", new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                deleteBowler(position);
                            }
                        });

                snackbar.show();
                alertDialog.dismiss();
            }
        });
        Window window = alertDialog.getWindow();
        window.setGravity(Gravity.TOP);
        alertDialog.show();
    }

    //Show Alert Dialog With EditText Options to Enter/Edit A League
    //When shouldUpdate = true, It Will Automatically Display Old Bowler Name And Change The Button Text To UPDATE
    public void showBowlerDialog(final boolean shouldUpdate, final Bowler bowler, final int position) {
        LayoutInflater layoutInflaterAndroid = LayoutInflater.from(getApplicationContext());
        final View view = View.inflate(this, R.layout.dialog_bowler, null);
        AlertDialog.Builder alertDialogBuilderUserInput = new AlertDialog.Builder(new ContextThemeWrapper(BowlerActivity.this, R.style.AppTheme));
        alertDialogBuilderUserInput.setView(view);
        alertDialogBuilderUserInput.setCancelable(true);
        leagueId.setText(savedLeagueId);
        final EditText inputBowlerName = view.findViewById(R.id.etBowlerNameInput);
        TextView dialogTitle = view.findViewById(R.id.dialog_title);
        dialogTitle.setText(!shouldUpdate ? getString(R.string.lbl_new_bowler_title) : getString(R.string.lbl_edit_bowler_title));

        if (shouldUpdate && bowler != null) {
            leagueId.setText(bowler.getLeagueId());
            inputBowlerName.setText(bowler.getName());

        }
        alertDialogBuilderUserInput
                .setCancelable(false)
                .setPositiveButton(shouldUpdate ? "update" : "save", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialogBox, int id) {

                    }
                })
                .setNegativeButton("cancel",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialogBox, int id) {
                                dialogBox.cancel();
                            }
                        });
        ImageView bowlerName = (ImageView) view.findViewById (R.id.ivBowlerName);
        bowlerName.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {

                AlertDialog.Builder bowlerName = new AlertDialog.Builder(BowlerActivity.this);
                bowlerName.setMessage("Enter the name of the bowler to hold your new scores.");
                bowlerName.setCancelable(true);
                bowlerName.create();
                bowlerName.show();
            }
        });

        final AlertDialog alertDialog = alertDialogBuilderUserInput.create();
        alertDialog.show();

        alertDialog.getButton( AlertDialog.BUTTON_POSITIVE).setOnClickListener( new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                //Show Toast Message When No Text Is Entered
                if (TextUtils.isEmpty(inputBowlerName.getText().toString())) {
                    Snackbar.make( view, "Enter Bowler Name", Snackbar.LENGTH_LONG )
                            .setAction( "Action", null ).show();
                    return;
                } else {
                    alertDialog.dismiss();
                }

                //Check If User Is Updating Bowler
                if (shouldUpdate && bowler != null) {

                    //Updating Bowler By Its Id
                    updateBowler(inputBowlerName.getText().toString(), position);

                } else {
                    //Creating New Bowler
                    createBowler(leagueId.getText().toString(), inputBowlerName.getText().toString());

                }
            }
        });
    }

    //Toggling List And Empty Bowler View
    private void toggleEmptyBowlers() {
        //You Can Check bowlerList.size() > 0

        if (db.getBowlersCount() > 0) {
            noBowlersView.setVisibility( View.GONE);
        } else {
            noBowlersView.setVisibility( View.VISIBLE);
        }
    }

    @Override
    public void onRestart() {
        super.onRestart();
        //When BACK BUTTON is pressed, the activity on the stack is restarted
        //Do what you want on the refresh procedure here
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate( R.menu.menu_main, menu );
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            Intent intent = new Intent(this, SettingsActivity.class);
            startActivity(intent);
            overridePendingTransition(0, 0);
            return true;
        }

        return super.onOptionsItemSelected( item );
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        super.onActivityResult(requestCode, resultCode, data);
        //Check If Request Code Is The Same As What Is Passed - Here It Is 1
        if(requestCode==1)
        {
            String savedLeagueId=data.getStringExtra("seriesLeagueId");
            String seriesBowlerId=data.getStringExtra("seriesBowlerId");
            bowlersList.addAll(db.getAllBowlers(savedLeagueId));
        }
    }

    @Override
    public void onBackPressed() {
        startActivity(new Intent(getApplicationContext(),MainActivity.class));
        finish();
        overridePendingTransition(0, 0);
    }
}

This is the line that it is complaining about. This worked perfectly before I move the onClick() to the adapter.

savedLeagueId = String.valueOf(getIntent().getIntExtra("leagueId",2));

I am really hoping that someone can help me get this issue resolved. I have tried several different approaches from other stackoverflow posts and I am still not able to resolve it.

Robert Vogl
  • 250
  • 5
  • 19

4 Answers4

1
mAdapter.notifyItemRemoved(position);

Means that the adapter will shift and animate items up. However, the items will not be redrawn.

You can observe that by clicking on the last item of your list after deleting any item: you should see the same crash.

And by clicking on any item after the one you deleted (except the last one), the details view should show the next item instead of the one you clicked.

The issue is that position is no longer relevant, because the indices have changed. Instead use the value for leagueId that you already have in your binder. Simply remove the int leagueId that is shadowing the String leagueId and that should work as expected.

njzk2
  • 38,969
  • 7
  • 69
  • 107
  • If I read your answer correctly, I removed `int leagueId = leaguesList.get(position).getId();` from the onClick(). While this did stop the IndexOutOfBoundsException, I can now longer get the id of the row being click, which results in all the rows displaying incorrect data. – Robert Vogl Sep 16 '18 at 12:07
  • `leagueId` is set in the intent as a String, since that's how you declare it in your method. Possibly your activity receiving it is not expecting a String – njzk2 Sep 16 '18 at 18:30
  • you where correct about the String and the receiving Activity looking for something else. `java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer at android.os.BaseBundle.getInt(BaseBundle.java:873) at android.content.Intent.getIntExtra(Intent.java:6178) at ca.rvogl.tpbcui.views.BowlerActivity.onCreate(BowlerActivity.java:118)` – Robert Vogl Sep 17 '18 at 20:58
  • I believe I found the issue, I was actually calling the wrong variable in the next Activity. The variable I was calling was some left over code from moving the onClick() to the Adapter. Thanks for pointing me in the correct direction. – Robert Vogl Sep 18 '18 at 01:12
  • as a side note, you may want to have a look at https://en.wikipedia.org/wiki/Variable_shadowing (which is what `leagueId` was doing). It's not directly the cause of the issue, but it's still worth looking at. – njzk2 Sep 18 '18 at 01:31
  • I will definitely give a read through. Thanks again for your assistance. – Robert Vogl Sep 18 '18 at 01:46
0

The problem is that the view was already bind and the position at this method:

    holder.name.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view) {
            int leagueId = leaguesList.get(position).getId(); // here position will still be 1 after deletion
            //...
        }
    });

belongs to the old index. To fix it, use the same object you fot previously.

    holder.name.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            int leagueId = league.getId(); //league object will be the same
            //...
        }
    });
Marcos Vasconcelos
  • 18,136
  • 30
  • 106
  • 167
  • I switched the out the line in the onClick() as you mentioned above. This did fix the IndexOutOfBoundsException issue, but now no matter what row I click on it does not display the information in the next activity that is associated to the previous activity. – Robert Vogl Sep 16 '18 at 12:10
0

****Try This****

@Override
protected void onBindViewHolder(@NonNull final BoardsViewHolder holder, final int position, @NonNull final Board model) {

    holder.setTitle(model.getBoardTitle());
    holder.setDesc(model.getBoardDesc());
    holder.setDate(model.getCreatedOn());
    holder.mDeleteBoardButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            AlertDialog.Builder alert = new AlertDialog.Builder(mContext);
            alert.setTitle("Delete Board");
            alert.setMessage("This Board will be deleted forever");
            alert.setPositiveButton("Delete", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    final ProgressDialog loading = new ProgressDialog(mContext);
                    loading.setMessage("Deleting...");
                    loading.show();
                   getSnapshots().getSnapshot(position).getReference().delete().addOnCompleteListener(new OnCompleteListener<Void>() {
                       @Override
                       public void onComplete(@NonNull Task<Void> task) {

                           if (task.isSuccessful()){
                               notifyDataSetChanged();
                               loading.dismiss();

                           }else {
                               loading.dismiss();
                               Toast.makeText(mContext,"Something went wrong please try again later",Toast.LENGTH_LONG).show();
                           }

                       }
                   });



                }
            });
            alert.setNegativeButton("Keep", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            });
            alert.show();
        }
    });
-2

This is the problem of zero based elements. Your code is trying to access an non existing element index. Launch your app in debug mode and line by line see what is happening. Android studio has an excellent debugger built-in, so it is very easy to go step by step and see what is happening with your variables.

q74
  • 88
  • 8
  • I am aware that the is due to the fact that I am trying to access an element index that no longer exists. I am also aware of Android Studios debugging capabilities. I just don't know how to fix the problem I have encountered. – Robert Vogl Sep 16 '18 at 12:15