【问题标题】:Index 0 requested, with a size of 0请求索引 0,大小为 0
【发布时间】:2013-08-02 10:22:39
【问题描述】:

我正在尝试编写一个简单的随机发生器应用程序。我让随机器按钮工作,但后来我更改了一些代码(我认为这些代码与随机器按钮无关),它开始崩溃并收到“请求的 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;
    }

}

【问题讨论】:

    标签: java android indexing cursor indexoutofboundsexception


    【解决方案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.";
        }
    

    【讨论】:

    • 不幸的是,这不起作用。它说 getRandomEntry 需要一个返回语句
    • 哦,对了。好吧,你不能使用return cursor.getString(0)。我编辑了替换建议。
    • 代替您的第二个 return 声明。我会编辑答案给你看。
    • 好消息:它已编译。坏消息:“数据库中没有可供选择的游戏。”出现了
    • 是的,我意识到在看到您的其他评论后,ListView 显示了游戏列表。尝试使用return Integer.toString(getAllEntries());。这将打印出总共有多少场比赛......但是没有......如果有 0 场比赛,random.nextInt() 会抛出异常。这意味着getAllEntries() 知道至少有一款游戏,但您的查询没有找到该游戏。我承认,我暂时被困在这里。我会继续寻找,但我只能确定 something 在查询中出错了。
    【解决方案2】:

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

    if (cursor.getColumnCount() > 0)
    return cursor.getString(0); 
    else return "no items";
    

    【讨论】:

    • 好吧,所以我不知道如何将代码格式化为注释,但我只是将代码从“if(cursor.moveToFirst()”替换为您所说的第二个 return 语句。是这个意思吗?
    【解决方案3】:

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

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

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

    【讨论】:

    • 我实际上确实在另一个活动/类中运行了 fetchAllGames 方法,该活动/类将数据库作为 ListView 显示,它工作得很好。就像一切都出现了一样。
    • 对不起,一切都指向一个不知何故为空的数据库,或者查询可能不正确?也许 rand 不知何故超出了界限,而你基本上得到了一个空洞的回应?你能通过硬编码一个你知道是正确的 _id 值来测试它吗?
    猜你喜欢
    • 2016-02-09
    • 2012-05-01
    • 1970-01-01
    • 2012-06-30
    • 1970-01-01
    • 2013-01-10
    • 2014-09-07
    • 1970-01-01
    相关资源
    最近更新 更多