質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.03%

SQLiteを使用するタイピングゲームが強制終了します。

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 1,234

score 18


前提・実現したいこと

Androidアプリの開発勉強として、eclipseで以下の流れになるタイピングゲームを作成しています。

前提:SQLiteを使用し、問題にCLEAR = 0を持たせる
1.CLEAR=0の問題だけ画面に1問ずつ表示させ、ユーザーに答えを入力してもらう。
2.1問答えたら正誤判定し、回答したら正誤に関わらずCLEARを 0 → 1 に変更する。
3.正誤に関わらず、次の問題を表示させる
4.以降、「2→3」を繰り返す。全5問。

発生している問題・エラーメッセージ

・「2」で、正誤に関わらず5問全てのCLEARが 0→1 に変更されてしまいます。
・1問回答するとアプリが強制終了し、その後アプリを再起動しても出題画面で
強制終了します。
なお、CLEARを0→1に変更する処理をコメントアウトすると強制終了は発生しません。
出題内容の重複はあるものの次の問題に進むことができます。

ソースコード

package com.at.kanji;

import android.app.Activity;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.text.SpannableStringBuilder;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class Test extends Activity implements OnClickListener {

    Button buttonToNextQuestions;
    Button buttonTrueOrFalse;
    Cursor c;
    EditText edited;
    int clear;
    int ret;
    int questionID;
    String mondai;
    String kotae;
    String sql;
    String answer;
    String TAG = "TTT";
    TextView tv1;
    TextView tv2;
    TextView tv3;    
    Questions questions;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_Test);

        QuestionsTable(this);
        tv1  = (TextView)findViewById(R.id.textView1);
        tv2  = (TextView)findViewById(R.id.textView2);
        tv3  = (TextView)findViewById(R.id.textView3);
        buttonToNextQuestions  = (Button)findViewById(R.id.button10);
        buttonToNextQuestions.setOnClickListener(this);
        // buttonTrueOrFalse      = (Button)findViewById(R.id.button11);
    }


    /************************************
     *    問題を表示させる処理     *
     ************************************/
    public void QuestionsTable (Test test) {

        questions = new Questions(this);
        SQLiteDatabase db   = questions.getReadableDatabase();

        // CLEARの値を取得して clearFlagに入れる処理
        sql = "SELECT CLEAR FROM QuestionsTable";

        c = db.rawQuery(sql,null);
        c.moveToFirst();

        clear = c.getInt(c.getColumnIndex("CLEAR"));
        Log.d(TAG,Integer.toString(clear));

        int[] clearFlag = new int[c.getCount()];

        // ここで問題の数だけ入れる
        for (int i = 0; i < c.getCount(); i++) {
            clearFlag[0] = c.getInt(0);
            c.moveToNext();
            Log.d(TAG,Integer.toString(clear));
        }

        // CLEARが0の問題だけを選んで画面に出力する
        sql = "SELECT KANJI,KOTAE,_id FROM QuestionsTable WHERE (CLEAR = 0) AND KANJIno == KOTAEno ORDER BY random() limit 1 ";

        c = db.rawQuery(sql.toString(),null);
        c.moveToFirst();

        mondai = c.getString(c.getColumnIndex("KANJI"));
        kotae  = c.getString(c.getColumnIndex("KOTAE"));
        questionID = c.getInt(c.getColumnIndex("_id"));

        Log.d("TTTQuestionID",Integer.toString(questionID));

        c.close();
        db.close();

        edited = (EditText)findViewById(R.id.editText1);
        tv1 = (TextView)findViewById(R.id.textView1);
        tv1.setText(mondai);
    }


    /************************************
     *    入力された文字を取得    *
     ************************************/
    public String message() {
        edited.getText();
        SpannableStringBuilder sb = (SpannableStringBuilder)edited.getText();
        answer = sb.toString();
        return answer;
    }


    /**************************************
     *       正誤判定        *
     **************************************/
    public void TrueOrFalse() {
        answer = message();
        if (answer.equals(kotae)){
            Toast.makeText(this, "正解!", Toast.LENGTH_SHORT).show();
        }else{
            Toast.makeText(this, "残念!", Toast.LENGTH_SHORT).show();
        }
        changeValueOfClear(); //★ここでアプリが強制終了する★
    }


    /************************************
     * 「次の問題へ」ボタンが押されたときの処理  *
     ************************************/
    public void onClick (View v) {
        TrueOrFalse();
        edited.getText().clear();
        edited = (EditText)findViewById(R.id.editText1);
        QuestionsTable(this);
    }


    /************************************
     *  DBのCLEARの値を変更する処理   *
     ************************************/
    public void changeValueOfClear() {

        Questions questions = new Questions(this);
        SQLiteDatabase db   = questions.getWritableDatabase();

        c = db.rawQuery(sql.toString(),null);
        c.moveToFirst();
        
        questionID = c.getInt(c.getColumnIndex("_id"));
        
        ContentValues values = new ContentValues();
        values.put("CLEAR",1);
        
        try{
            ret = db.update("QuestionsTable",values,"_id = questionID",null);
        }finally{
            c.close();
            db.close();
        }

        // CLEARの値の変更に失敗
        if (ret == -1) {
            Toast.makeText(this, "終了します。", Toast.LENGTH_SHORT).show();
        }else{
            
        }
    }
}

★SQLiteのテーブル
public Questions(Context context) {
        /* ここで任意のデータベースファイル名と、バージョンを指定する。
         * データベースファイル名 = QuestionsTable.db
         * バージョン = 1
         */

        super(context,"QuestionsTable.db",null,1);

    }

    @Override
    public void onCreate(SQLiteDatabase db) {

        db.execSQL("CREATE TABLE QuestionsTable" +
                "(" +
                "_id INTEGER PRIMARY KEY AUTOINCREMENT" +
                ",QuestionID" +
                ", KANJI TEXT" +
                ", KOTAE TEXT" +
                ", KANJIno INTEGER" +
                ", KOTAEno INTEGER" +
                ", CLEAR INTEGER" +
                ")");

        // 初期データ投入
        db.execSQL("INSERT INTO QuestionsTable(QuestionID,KANJI,KOTAE,KANJIno,KOTAEno,CLEAR) values (1,'山','やま',1,1,0);");
        db.execSQL("INSERT INTO QuestionsTable(QuestionID,KANJI,KOTAE,KANJIno,KOTAEno,CLEAR) values (2,'川','かわ',2,2,0);");
        db.execSQL("INSERT INTO QuestionsTable(QuestionID,KANJI,KOTAE,KANJIno,KOTAEno,CLEAR) values (3,'木','き',3,3,0);");
        db.execSQL("INSERT INTO QuestionsTable(QuestionID,KANJI,KOTAE,KANJIno,KOTAEno,CLEAR) values (4,'林','はやし',4,4,0);");
        db.execSQL("INSERT INTO QuestionsTable(QuestionID,KANJI,KOTAE,KANJIno,KOTAEno,CLEAR) values (5,'森','もり',5,5,0);");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

★AndroidManifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.at.kanji"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="20" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".Test"
            android:label="@string/title_activity_Test" >
        </activity>
        <activity
            android:name=".Questions"
            android:label="@string/title_activity_questions" >
        </activity>
    </application>

</manifest>

★logcat
10-03 12:37:18.879  9477  9477 E AndroidRuntime: FATAL EXCEPTION: main
10-03 12:37:18.879  9477  9477 E AndroidRuntime: android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0

補足情報(言語/FW/ツール等のバージョンなど)

Android4.4向け
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

以下、気が付いた点です。
1. db create での QuestionIDの型が指定されていない。
  ",QuestionID" + -> ",QuestionID INTEGER" +
2. clearが0の問題だけを選ぶためのSQLのKANJInoとKOTAEnoの比較が"=="になっている。
  "SELECT ... AND KANJIno == KOTAEno ..."
    -> "SELECT ... AND KANJIno = KOTAEno ..."
3. 上記のsqlにrandomを指定しているが、これだと読込んで表示する問題と、更新するときのレコードが違ってくる。
  -> randomの指定をやめるか、読みだしたときの"_id"を保存しておき、その"_id"で更新する。
4. changeValueOfClearメソッド内のdb.updateでquestionIDが指定されていない。
   db.update("QuestionsTable",values,"_id = questionID",null);
    -> db.update("QuestionsTable",values,"_id = " + questionID /*ここ★★*/,null);
5. Queryを行ったとき、クエリの結果が0件の場合を考慮していない。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/10/04 14:10 編集

    akiruno-oneone様
    ご指摘いただきありがとうございます!

    1,2,4の内容に修正したところ強制終了がなくなりました!
    *5に対応していないので、そのせいの強制終了はありますが・・・今はまずランダムに出題したいので、こちらの対応は後回しとさせてください。

    3についてはいただいた内容で考え直します。また進展なければ別途質問させていただきますので、もしよろしければまたご指導いただけますと幸いです。

    本当にありがとうございました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.03%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る