简体   繁体   中英

Why the arraylist empties itself when it is called optionPressed method?

Making a simple BrainTrain app, the updateAnswer method gives out random answers to the question but the issue comes up whenever i call the optionsPressed method and try getting any of the object, the arrayList gives out IndexOutOfBoundsException .

package com.example.nishantsaini.braintrain;

import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.CountDownTimer;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Random;

import static android.R.color.black;
import static android.R.color.holo_blue_bright;
import static android.R.color.holo_blue_dark;
import static android.R.color.holo_blue_light;
import static android.R.color.holo_green_light;



public class MainActivity extends AppCompatActivity {

Random rnd = new Random();
boolean gameisActive = false;
int count = 0;
CountDownTimer cd;
int var1,var2;
ArrayList<Button> options;




@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    cd = new CountDownTimer(30000, 1000) {
        @Override
        public void onTick(long l) {
            Log.i("Time Left:", Long.toString(l / 1000));
            TextView timer = (TextView) findViewById(R.id.timer);
            timer.setText("0:" + String.format("%02d", (l / 1000)));

        }

        @Override
        public void onFinish() {
            TextView score = (TextView) findViewById(R.id.Score);
            LinearLayout onFinishLayout = (LinearLayout) findViewById(R.id.onFinishLayout);
            /*score.setText( "You got " + getScore() + "right!");
            */

        }
    };
    options = new ArrayList<>();
    options.add((Button) findViewById(R.id.option2));
    options.add((Button) findViewById(R.id.option1));
    options.add((Button) findViewById(R.id.option3));
    options.add((Button) findViewById(R.id.option4));
}

public void start(View view) {



    cd.start();

    Button start = (Button) findViewById(R.id.start);
    updateQuestion();
    updateAnswers(options);

    start.setText("Replay");

}

public void optionPressed(View view){

    ColorDrawable blue_d = new ColorDrawable(getResources().getColor(R.color.blue_b));
    ColorDrawable blue_l = new ColorDrawable(getResources().getColor(R.color.blue_l));
    ColorDrawable blue_b = new ColorDrawable(getResources().getColor(R.color.blue_b));
    ColorDrawable green = new ColorDrawable(getResources().getColor(R.color.green));

    Drawable color = blue_b;
    while(options.size() > 0) {
        int index = rnd.nextInt(options.size());
        Button b = options.get(index);

        if (color == blue_b){
            color = blue_d;
            b.setBackground(color);
        }
        else if (color == blue_d){
            color = green;
            b.setBackground(color);

        }
        else if (color == green){
            color = blue_l;
            b.setBackground(color);

        }
        else if (color == blue_l)
        {
            color = blue_b;
            b.setBackground(color);
        }
        options.remove(index);
    }

    updateQuestion();
    updateScore();
    updateAnswers(options);

}

public void updateQuestion(){
    var1 = 5 + (int)(Math.random()*20);
    var2 = 5 + (int)(Math.random()*20);
    TextView question = (TextView) findViewById(R.id.question);
    question.setText(Integer.toString(var1) +" + " + Integer.toString(var2) + " = ");
    question.setPadding(0,50,0,0);
}

public void updateScore(){

    count++;
    int correct = 0;
    TextView score = (TextView) findViewById(R.id.points);
    score.setText(Integer.toString(correct) + "/" + Integer.toString(count));
}

public void updateAnswers(ArrayList<Button> arrayList ){

    Button b;
    int answer = var1 + var2;
    int indexAtWhichRealAnswerGoes = 1+ (int) (Math.random()*3);
    int id ;
    Log.i("arraylist size",Integer.toString(options.size()));

    b = arrayList.get(indexAtWhichRealAnswerGoes);
    b.setText(Integer.toString(answer));
    id = b.getId();
    arrayList.remove(indexAtWhichRealAnswerGoes);
    for (int i = 0; i < arrayList.size(); i++) {
        int randomanswer = (answer-7) + (int)(Math.random()*(answer+7));
        b = arrayList.get(i);
        b.setText(Integer.toString(randomanswer));

    }
    arrayList.add((Button) findViewById(id));
    Log.i("arraylist size",Integer.toString(arrayList.size()));

}
}

So, you call updateAnswers(options); using the list that you previously emptied

while(options.size() > 0) {
    int index = rnd.nextInt(options.size());
    ...
    options.remove(index);
}
...
updateAnswers(options);

At that point, the list is empty.

In the method, you safely used for (int i = 0; i < arrayList.size(); i++) { to prevent any error but before that we see

int indexAtWhichRealAnswerGoes = 1+ (int) (Math.random()*3);
...
b = arrayList.get(indexAtWhichRealAnswerGoes);

You get that random index without checking the size of the list. ( List that is empty at that point).


If you want to keep the list with its value, but the logic can't be change so the remove is necessary, you need to do a copy of the list to work on that one, and pass the original to the method updateAnswers .

List<Button> copyOptions = new ArrayList<>(options);

It will share the same instance, but you can update the list copyOptions without having any impact on options

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM