lundi 25 avril 2016

Why do I get IndexOutOfBoundsException after installing my app to another devices?

Why do I get this error?

Caused by: java.lang.IndexOutOfBoundsException: Invalid index 1, size is 0
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)                                                                                   
at java.util.ArrayList.get(ArrayList.java:308)
at com.example.muhammad.exquizme.PlayQuizActivity.displayQuestion(PlayQuizActivity.java:109)
at com.example.muhammad.exquizme.PlayQuizActivity.onCreate(PlayQuizActivity.java:62)
at android.app.Activity.performCreate(Activity.java:6092)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1112)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2481)
 at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2608) 
 at android.app.ActivityThread.access$800(ActivityThread.java:178) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1470) 
at android.os.Handler.dispatchMessage(Handler.java:111) 
at android.os.Looper.loop(Looper.java:194) 
at android.app.ActivityThread.main(ActivityThread.java:5637) 
 at java.lang.reflect.Method.invoke(Native Method) 
 at java.lang.reflect.Method.invoke(Method.java:372) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:959) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:754) 

This error appeared already in my phone and it has been fixed already. Then I tried installing my app in my tablet device and run it. When I pressed on a button to navigate to the PlayQuizActivity, it crashes and it says that it Caused by: java.lang.IndexOutOfBoundsException: Invalid index 1, size is 0.

This is the code for PlayQuizActivity.java:

public class PlayQuizActivity extends AppCompatActivity {

private static final String QUESTION_MANAGER_URL = "http://ift.tt/1SClXQL";
private int randomIndex, questionIndex = 1;
private SQLiteDatabaseHelper questionDatabase;
private RadioButton choiceBtnA, choiceBtnB, choiceBtnC, choiceBtnD;
private TextView questionTextView, qIndexView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_play_quiz);
    //questionDatabase = new SQLiteDatabaseHelper(this);

    qIndexView = (TextView) findViewById(R.id.currentNumber);
    questionTextView = (TextView) findViewById(R.id.questionTextView);
    choiceBtnA = (RadioButton) findViewById(R.id.choiceA);
    choiceBtnB = (RadioButton) findViewById(R.id.choiceB);
    choiceBtnC = (RadioButton) findViewById(R.id.choiceC);
    choiceBtnD = (RadioButton) findViewById(R.id.choiceD);

    //Get Network State
    ConnectivityManager connectivity = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
    boolean isConnected = false;
    if (connectivity != null) {
        NetworkInfo info = connectivity.getActiveNetworkInfo();
        if (info != null && info.isConnected()) {
            isConnected = true;
        }
    }

    if (isConnected) {
        getJSONFromURL();
        displayQuestion();
    } else {
        displayQuestion();
    }


    choiceBtnA.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            checkAnswers(0);
        }
    });

    choiceBtnB.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            checkAnswers(1);
        }
    });

    choiceBtnC.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            checkAnswers(2);
        }
    });

    choiceBtnD.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            checkAnswers(3);
        }
    });
}

private void displayQuestion() {

    qIndexView.setText("QUESTION " + questionIndex++ + " /10");
    randomIndex = new Random().nextInt(10) + 1;
    questionDatabase = new SQLiteDatabaseHelper(this);

    //Uncheck button
    choiceBtnA.setChecked(false);
    choiceBtnB.setChecked(false);
    choiceBtnC.setChecked(false);
    choiceBtnD.setChecked(false);
    if (questionIndex <= 10) {
        String question = questionDatabase.getQuestions().get(randomIndex).question; //this causes the error
        String[] choices = new String[4];
        choices[0] = questionDatabase.getQuestions().get(randomIndex).choices[0];
        choices[1] = questionDatabase.getQuestions().get(randomIndex).choices[1];
        choices[2] = questionDatabase.getQuestions().get(randomIndex).choices[2];
        choices[3] = questionDatabase.getQuestions().get(randomIndex).choices[3];
        questionTextView.setText(question);
        choiceBtnA.setText(choices[0]);
        choiceBtnB.setText(choices[1]);
        choiceBtnC.setText(choices[2]);
        choiceBtnD.setText(choices[3]);
    }
}

private void checkAnswers(int index) {
    String answer = questionDatabase.getQuestions().get(randomIndex).choices[index], correctAnswer = questionDatabase.getQuestions().get(randomIndex).answer;
    if (answer.equals(correctAnswer)) {
        Toast.makeText(PlayQuizActivity.this, "Correct", Toast.LENGTH_SHORT).show();
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                displayQuestion();
            }
        }, 2000);
        //Log.d("Is it correct?", "Correct");
    } else {
        Toast.makeText(PlayQuizActivity.this, "Incorrect", Toast.LENGTH_SHORT).show();
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                displayQuestion();
            }
        }, 2000);
        //Log.d("Is it correct?", "Incorrect");
    }
}

private void getJSONFromURL() {
    class QuestionExtractorTask extends AsyncTask<Void, Void, String> {
        ProgressDialog loading;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            loading = ProgressDialog.show(PlayQuizActivity.this, "Loading questions...", null, true, true);
        }

        @Override
        protected String doInBackground(Void... params) {

            BufferedReader bufferedReader;
            try {
                URL url = new URL(QUESTION_MANAGER_URL);
                HttpURLConnection con = (HttpURLConnection) url.openConnection();
                StringBuilder sb = new StringBuilder();

                bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream()));

                String json;
                while ((json = bufferedReader.readLine()) != null) {
                    sb.append(json + "\n");
                }
                json = sb.toString().trim();

                return json;

            } catch (Exception e) {
                return null;
            }

        }

        @Override
        protected void onPostExecute(String jsonData) {
            super.onPostExecute(jsonData);
            loading.dismiss();
            QuestionJSONParser questionJsonParser = new QuestionJSONParser();
            questionJsonParser.extractJSON(jsonData);
        }
    }
    QuestionExtractorTask questionExtractorTask = new QuestionExtractorTask();
    questionExtractorTask.execute();
}


class QuestionJSONParser {
    private static final String ROOT_OBJECT = "questions", QUESTION = "question", CHOICES = "choices", CATEGORY = "category";

    public void extractJSON(String jsonData) {
        try {
            //Get the questions object
            JSONObject questions = new JSONObject(jsonData).getJSONObject(ROOT_OBJECT);
            //Get the questions' objects
            Collections.shuffle(uniqueRandomNumber(questions.length()));
            for (int counter = 0; counter < 10; counter++) {
                String[] choices = new String[4];


                System.out.println(uniqueRandomNumber(questions.length()));

                JSONObject theQuestionObject = questions.getJSONObject(uniqueRandomNumber(questions.length()).get(counter) + "");
                String question = theQuestionObject.getString(QUESTION), category = theQuestionObject.getString(CATEGORY), correctAnswer = "";

                //Log.d("question", question);
                JSONArray theChoicesArray = theQuestionObject.getJSONArray(CHOICES);

                //Get choice object from the choices object
                for (int i = 0; i < theChoicesArray.length(); i++) {
                    JSONObject choiceObject = theChoicesArray.getJSONObject(i);
                    choices[i] = choiceObject.optString("choice");
                    if (choiceObject.getInt("is_correct_choice") == 1) {
                        correctAnswer = choices[i];
                    }
                }
                //add in SQLite Database
                questionDatabase = new SQLiteDatabaseHelper(getApplicationContext());
                questionDatabase.addQuestion(new QuizQuestion(question, choices, correctAnswer, category));
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public List uniqueRandomNumber(int length) {

        if (length != 0) {
            Integer[] arr = new Integer[length];
            for (int i = 0; i < arr.length; i++) {
                arr[i] = i + 1;
            }
            return Arrays.asList(arr);
        }
        return null;
    }

}

}

I am trying to find out how to fixed this. I have thought about some possibilities thats causes the error. I guess when extracting json from an url and then parsing it, maybe it doesn't save those data to my sqlite database but this problem was fixed already so I have no idea how this is happening. It always say that the size is 0. Does this mean that I need to stick to my my phone. I think this is not about the sdk version, isn't it?

Here's my SQLiteDatabaseHelper.class:

class SQLiteDatabaseHelper extends SQLiteOpenHelper {

private static final String[] TABLES = new String[]{"question", "question_choices", "stats"};

public SQLiteDatabaseHelper(Context context) {
    super(context, "QUESTION_DATABASE", null, 1);
}

@Override
public void onCreate(SQLiteDatabase db) {

    //Create Questions Table
    String CREATE_QUESTIONS_TABLE = "CREATE TABLE " + TABLES[0] + " (\n" +
            "  quiz_question_id INT  PRIMARY KEY,\n" +
            "  question TEXT ,\n" +
            "  choice_a TEXT,\n" +
            "  choice_b TEXT ,\n" +
            "  choice_c TEXT ,\n" +
            "  choice_d TEXT ,\n" +
            "  answer TEXT ,\n" +
            "   category TEXT)";
    db.execSQL(CREATE_QUESTIONS_TABLE);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("DROP TABLE IF EXISTS" + TABLES[0]);
    db.execSQL("DROP TABLE IF EXISTS" + TABLES[2]);
}

//Managing question for the quiz
public void addQuestion(QuizQuestion questions) {
    SQLiteDatabase db = this.getWritableDatabase();

    //Insert in question table
    ContentValues values = new ContentValues();
    values.put("question", questions.question);
    values.put("choice_a", questions.choices[0]);
    values.put("choice_b", questions.choices[1]);
    values.put("choice_c", questions.choices[2]);
    values.put("choice_d", questions.choices[3]);
    values.put("answer", questions.answer);
    values.put("category", questions.category);

    // Inserting Row
    db.insert(TABLES[0], null, values);
    db.close(); // Closing database connection
}

//Managing best scores and best category for stats

public List<QuizQuestion> getQuestions() {
    List<QuizQuestion> quizQuestionArrayList = new ArrayList<>();
    String selectQuery = "SELECT * FROM " + TABLES[0];
    SQLiteDatabase db = this.getReadableDatabase();
    Cursor cursor = db.rawQuery(selectQuery, null);
    if (!cursor.isLast()) {
        while (cursor.moveToNext()) {
            //Log.d("cursor.getString(1)", cursor.getString(1));
            String[] choices = {cursor.getString(2), cursor.getString(3), cursor.getString(4), cursor.getString(5)};
            quizQuestionArrayList.add(new QuizQuestion(cursor.getString(1), choices, cursor.getString(6), cursor.getString(7)));
        }
    }

    db.close();
    return quizQuestionArrayList;
}

}

The code above handles the sqlite database. What I'm basically trying to accomplish here if I'm connected to the internet, it will download the data to my sqlite database so when it's offline, it can be accessed. This happens already with my phone but with my tablet, it didn't work as it should as shown on the error above. Please if you need further details just let me know. Any help is appreciated. Thank you.

Aucun commentaire:

Enregistrer un commentaire