0

我正在尝试编写一个简单的随机化器应用程序。我让随机器按钮工作,但后来我更改了一些代码(我认为这与随机器按钮无关),它开始崩溃并收到“请求的 CursorIndexOutOfBoundsException 索引 0,大小为 0”错误。我找不到适用于我的代码的任何修复程序。谁能帮我解决这个问题?

这是我带按钮的主要课程:

package com.example.randomgamechooser;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.TextView;

public class MainScreen extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_screen);


    }

    public void chooseGame (View view) {
        GameList dbUtil = new GameList(this);
        dbUtil.open();
        String string = dbUtil.getRandomEntry();
        //TextView textView = new TextView(this);
        TextView textView = (TextView) findViewById(R.id.chosenbox);
        textView.setTextSize(40);
        textView.setText(string);
        //setContentView (textView);
        dbUtil.close();
    }



    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main_screen, menu);
        return true;
    }
    //starts the Game Selection activity
    public void openGames (View view) {
        Intent intent = new Intent(this, GameSelction.class);
        startActivity(intent);
    }

}

这是 GameList 类:

package com.example.randomgamechooser;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

import java.util.Random;

public class GameList {

    private static final String TAG = "GameList";

    //database name
    private static final String DATABASE_NAME = "game_list";

    //database version
    private static final int DATABASE_VERSION = 1;

    //table name
    private static final String DATABASE_TABLE = "game_list";

    //table columns
    public static final String KEY_NAME = "name";
    public static final String KEY_GENRE = "genre";
    public static final String KEY_ROWID = "_id";

    //database creation sql statement
    private static final String CREATE_GAME_TABLE =
        "create table " + DATABASE_TABLE + " (" + KEY_ROWID + " integer primary key autoincrement, "
        + KEY_NAME +" text not null, " + KEY_GENRE + " text not null);";

    //Context
    private final Context mCtx;
    private DatabaseHelper mDbHelper;
    private static SQLiteDatabase mDb;


     //Inner private class. Database Helper class for creating and updating database.

    private static class DatabaseHelper extends SQLiteOpenHelper {
        DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

         // onCreate method is called for the 1st time when database doesn't exists.
        @Override
        public void onCreate(SQLiteDatabase db) {
            Log.i(TAG, "Creating DataBase: " + CREATE_GAME_TABLE);
            db.execSQL(CREATE_GAME_TABLE);
        }

         //onUpgrade method is called when database version changes.
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
                    + newVersion);
        }
    }

     //Constructor - takes the context to allow the database to be opened/created
     //@param ctx the Context within which to work
    public GameList(Context ctx) {
        this.mCtx = ctx;
    }

     //This method is used for creating/opening connection
     //@return instance of GameList
     //@throws SQLException
    public GameList open() throws SQLException {
        mDbHelper = new DatabaseHelper(mCtx);
        mDb = mDbHelper.getWritableDatabase();
        return this;
    }

     //This method is used for closing the connection.
    public void close() {
        mDbHelper.close();
    }


     //This method is used to create/insert new game.
     //@param name
     // @param genre
     // @return long
    public long createGame(String name, String genre) {
        ContentValues initialValues = new ContentValues();
        initialValues.put(KEY_NAME, name);
        initialValues.put(KEY_GENRE, genre);
        return mDb.insert(DATABASE_TABLE, null, initialValues);
    }

     // This method will delete game.
     // @param rowId
     // @return boolean
    public static boolean deleteGame(long rowId) {
        return mDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;
    }


     // This method will return Cursor holding all the games.
     // @return Cursor
    public Cursor fetchAllGames() {
        return mDb.query(DATABASE_TABLE, new String[] {KEY_ROWID, KEY_NAME,
                KEY_GENRE}, null, null, null, null, null);

    }


     // This method will return Cursor holding the specific game.
     // @param id
     // @return Cursor
     // @throws SQLException
    public Cursor fetchGame(long id) throws SQLException {
        Cursor mCursor =
            mDb.query(true, DATABASE_TABLE, new String[] {KEY_ROWID,
                    KEY_NAME, KEY_GENRE}, KEY_ROWID + "=" + id, null,
                    null, null, null, null);
        if (mCursor != null) {
            mCursor.moveToFirst();
        }

        return mCursor;
    }

    public int getAllEntries()
    {
        Cursor cursor = mDb.rawQuery(
                    "SELECT COUNT(name) FROM game_list", null);
                if(cursor.moveToFirst()) {
                    return cursor.getInt(0);
                }
                return cursor.getInt(0);

    }  

    public String getRandomEntry()
    {

        //id = getAllEntries();
        Random random = new Random();
        int rand = random.nextInt(getAllEntries());
        if(rand == 0)
            ++rand;
        Cursor cursor = mDb.rawQuery(
                    "SELECT name FROM game_list WHERE _id = " + rand, null);
                if(cursor.moveToFirst()) {
                    return cursor.getString(0);
                }
                return cursor.getString(0);

    }


     // This method will update game.
     // @param id
     // @param name
     // @param standard
     // @return boolean
    public boolean updateGame(int id, String name, String standard) {
        ContentValues args = new ContentValues();
        args.put(KEY_NAME, name);
        args.put(KEY_GENRE, standard);
        return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + id, null) > 0;
    }
}

这是错误日志的原因部分:

08-01 13:03:38.325: E/AndroidRuntime(278): Caused by: android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
08-01 13:03:38.325: E/AndroidRuntime(278):  at android.database.AbstractCursor.checkPosition(AbstractCursor.java:580)
08-01 13:03:38.325: E/AndroidRuntime(278):  at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:214)
08-01 13:03:38.325: E/AndroidRuntime(278):  at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:41)
08-01 13:03:38.325: E/AndroidRuntime(278):  at com.example.randomgamechooser.GameList.getRandomEntry(GameList.java:153)

编辑:这是 ListView 类:

public class GameSelction extends Activity 
{
    GameList dbUtil = new GameList(this);
    private SimpleCursorAdapter dataAdapter;
    //@SuppressWarnings("deprecation")
    @SuppressLint("NewApi")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_game_selction);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
            getActionBar() .setDisplayHomeAsUpEnabled(true);
        }
       displayListView();

        }
    private void displayListView() {
        dbUtil.open();
        Cursor cursor = dbUtil.fetchAllGames();

        // The desired columns to be bound
        String[] columns = new String[] {
          GameList.KEY_NAME,
          GameList.KEY_GENRE,

        };

        // the XML defined views which the data will be bound to
        int[] to = new int[] { 
          R.id.name,
          R.id.genre,

        };

        // create the adapter using the cursor pointing to the desired data 
        //as well as the layout information
        dataAdapter = new SimpleCursorAdapter(
          this, R.layout.game_info, 
          cursor, 
          columns, 
          to,
          0);

        ListView listView = (ListView) findViewById(R.id.listView1);
        // Assign adapter to ListView
        listView.setAdapter(dataAdapter);
        listView.setOnItemClickListener(new OnItemClickListener() {



            @Override
            public void onItemClick(AdapterView<?> listView, View view, 
              int position, long rowId) {

            // Get the cursor, positioned to the corresponding row in the result set
            //Cursor cursor = (Cursor) listView.getItemAtPosition(position);
            GameList.deleteGame(rowId);




            }

        });

       }



    /**
     * Set up the {@link android.app.ActionBar}, if the API is available.
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void setupActionBar() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            getActionBar().setDisplayHomeAsUpEnabled(true);
        }
    }
        //opens the AddGame activity
    public void openAddgame (View view) {
    Intent intent = new Intent(this, AddGame.class);
    startActivity(intent);
}
    public void buttonBackMain (View view) {
        Intent intent = new Intent(this, MainScreen.class);
        startActivity(intent);
    }

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

}
4

3 回答 3

1

问题出在这段代码中:

public String getRandomEntry()
    {
        //...
        Cursor cursor = mDb.rawQuery(
                    "SELECT name FROM game_list WHERE _id = " + rand, null);
        if(cursor.moveToFirst()) {
            return cursor.getString(0);
        }
        return cursor.getString(0);
    }

你最终做的是说return cursor.getString(0);光标中是否有结果。所以删除第二次出现,它应该可以工作。

编辑: 扫描代码后,您使用此方法的唯一地方似乎是填充 TextView。在这种情况下,您可以借此机会向您自己或您的用户传达视觉错误消息,或者使用它做任何您想做的事情。所以我建议使用一些东西来达到

public String getRandomEntry()
    {
         //EDIT: This will make your random generator less biased toward 1.
        Random random = new Random();
        int rand = random.nextInt(getAllEntries()) + 1;
        /* Assuming your _id starts at 1 and auto-increments, this will
         * start the random digits at 1 and go as high as your highest _id */

        Cursor cursor = mDb.rawQuery(
                    "SELECT name FROM game_list WHERE _id = " + rand, null);
        if(cursor.moveToFirst()) {
            return cursor.getString(0);
        }
        return "There were no games in the database to choose from.";
    }

编辑: 尝试使用它。请注意,此代码使用mDb.query(),您在其他地方使用过。我不确定为什么rawQuery()会拒绝工作,但也许这会做到。

 public String getRandomEntry()
    {
        Random random = new Random();
        int rand = random.nextInt(getAllEntries()) + 1;

        Cursor cursor = mDb.query(true, DATABASE_TABLE, new String[] {KEY_NAME}, 
                KEY_ROWID + "=" + rand, null, null, null, null, null);
        if(cursor.moveToFirst()) {
            return cursor.getString(0);
        }
        return "There were no games in the database to choose from.";
    }
于 2013-08-01T13:25:19.493 回答
0

没有阅读整个代码,但我想问题是,您正试图从空数据库中获取第一个元素。在获取元素之前,只需检查光标的大小是否大于 0。

if (cursor.getColumnCount() > 0)
return cursor.getString(0); 
else return "no items";
于 2013-08-01T13:36:25.400 回答
0

根据最初的外观,由SQLiteDatabase表示的对象mDB似乎是空的,因为这就是引发错误的原因。

错误的意思是您的代码正在请求索引 0 处的项目(基本上是第一项),但索引的大小为 0(基本上,索引中没有项目)。

在某个地方,您的数据库对象要么被清空,要么未被填充。要对此进行测试,请运行您的fetchAllGames方法并验证索引的内容。

于 2013-08-01T13:23:20.187 回答