Android应用程序将高分值存储为共享引用中的int.如果得分超过100,该应用程序将抛出界外异常



我有一款Android游戏,它使用SharedPreferences将游戏的高分存储在设备上。这非常有效,直到设备上的高分超过100分,此时它会导致应用程序在下次从SharedPreferences获取int时崩溃。以下是与从SharedPreferences存储和检索分数相关的代码。

public void setHighScore(int score) {
    SharedPreferences.Editor settingsEditor = prefs.edit();
    settingsEditor.putInt(Constants.KEY_HIGHSCORE, score);
    settingsEditor.commit();
    }
public int getHighScore() {
    return prefs.getInt(Constants.KEY_HIGHSCORE, 0);
}  

if (score > activity.getHighScore()) {
    activity.setHighScore(score);
}
        yourScoreText.setText("Your Score: " + score);
        yourScoreText.setColor(Color.GREEN);
        yourScoreText.setVisible(true);
        highScoreText.setText("High Score: " + activity.getHighScore());
        highScoreText.setColor(Color.RED);
        highScoreText.setVisible(true);

Logcat

09-19 22:00:13.612: W/dalvikvm(26458): threadid=12: thread exiting with uncaught exception (group=0x417a9898)
09-19 22:00:13.622: E/AndroidRuntime(26458): FATAL EXCEPTION: UpdateThread
09-19 22:00:13.622: E/AndroidRuntime(26458): java.lang.ArrayIndexOutOfBoundsException: length=360; index=360
09-19 22:00:13.622: E/AndroidRuntime(26458):    at org.andengine.entity.text.vbo.HighPerformanceTextVertexBufferObject.onUpdateVertices(HighPerformanceTextVertexBufferObject.java:124)
09-19 22:00:13.622: E/AndroidRuntime(26458):    at org.andengine.entity.text.Text.onUpdateVertices(Text.java:333)
09-19 22:00:13.622: E/AndroidRuntime(26458):    at org.andengine.entity.shape.Shape.setSize(Shape.java:146)
09-19 22:00:13.622: E/AndroidRuntime(26458):    at org.andengine.entity.text.Text.setText(Text.java:221)
09-19 22:00:13.622: E/AndroidRuntime(26458):    at hungryfish.scene.GameScene.reset(GameScene.java:246)
09-19 22:00:13.622: E/AndroidRuntime(26458):    at hungryfish.scene.GameScene.onSceneTouchEvent(GameScene.java:308)
09-19 22:00:13.622: E/AndroidRuntime(26458):    at org.andengine.entity.scene.Scene.onSceneTouchEvent(Scene.java:387)
09-19 22:00:13.622: E/AndroidRuntime(26458):    at org.andengine.engine.Engine.onTouchScene(Engine.java:470)
09-19 22:00:13.622: E/AndroidRuntime(26458):    at org.andengine.engine.Engine.onTouchEvent(Engine.java:456)
09-19 22:00:13.622: E/AndroidRuntime(26458):    at org.andengine.input.touch.controller.BaseTouchController$TouchEventRunnablePoolItem.run(BaseTouchController.java:102)
09-19 22:00:13.622: E/AndroidRuntime(26458):    at org.andengine.util.adt.pool.RunnablePoolUpdateHandler.onHandlePoolItem(RunnablePoolUpdateHandler.java:54)
09-19 22:00:13.622: E/AndroidRuntime(26458):    at org.andengine.util.adt.pool.RunnablePoolUpdateHandler.onHandlePoolItem(RunnablePoolUpdateHandler.java:1)
09-19 22:00:13.622: E/AndroidRuntime(26458):    at org.andengine.util.adt.pool.PoolUpdateHandler.onUpdate(PoolUpdateHandler.java:88)
09-19 22:00:13.622: E/AndroidRuntime(26458):    at org.andengine.input.touch.controller.BaseTouchController.onUpdate(BaseTouchController.java:62)
09-19 22:00:13.622: E/AndroidRuntime(26458):    at org.andengine.engine.Engine.onUpdate(Engine.java:604)
09-19 22:00:13.622: E/AndroidRuntime(26458):    at org.andengine.engine.LimitedFPSEngine.onUpdate(LimitedFPSEngine.java:57)
09-19 22:00:13.622: E/AndroidRuntime(26458):    at org.andengine.engine.Engine.onTickUpdate(Engine.java:568)
09-19 22:00:13.622: E/AndroidRuntime(26458):    at org.andengine.engine.Engine$UpdateThread.run(Engine.java:858)

我会对此发表评论,但由于我的分数不到50分,我不能。。一个简单的解决方案是将值存储在String中。像这样:

SharedPreferences sp = getSharedPreferences(1);
sp.edit().putString("highScore", String.valueOf(highScore)).apply

当你从共享偏好中获得它时,只需进行

int score = Integer.valueOf(sp.getString("highScore", "0"));

就我个人而言,我不太喜欢共享偏好,而是选择了sqlite数据库。使用数据库时,读/写序列要快得多。。

你可以尝试使用.apply而不是.commit-.apply在后台运行。。

正如你所要求的,我提供了一些我写的代码来帮助你使用数据库。我只是写了它并尝试了一下,这样我就知道它有效,或者至少在我的GS3(4.4.4)和我的OnePlus one上有效。

我会在单独的文件中创建类,但这取决于您。例如,我只是在默认活动中使用了它们,并在onCreate中运行了一些set/get分数代码。

 public class DatabaseHelper extends SQLiteOpenHelper{
     //final static stuff because you'll want to access it(the data) in other classes.
     public static final String DB_NAME = "scores.db";
     public static final String SCORE_TABLE = "scores";
     public static final int VERSION = 3;
     private Context context;
     public DatabaseHelper(Context context){
         super(context, DB_NAME, null, VERSION);
         this.context = context;
     }
     public SQLiteDatabase getDatabase(){
         return getWritableDatabase();
     }
     @Override
     public void onCreate(SQLiteDatabase db) {
         //our code for creating the ScoreTable..
         db.execSQL("CREATE TABLE "
                 + SCORE_TABLE +
                 "(" +
                 "ID INT NOT NULL, " +
                 "Score INT);");
         //now we create one row of data.
         db.execSQL("INSERT INTO " + DatabaseHelper.SCORE_TABLE + " (ID, Score) VALUES (1, 0);");
     }
     @Override
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
         //if the version is greater than the previous one, we re-create it.
         if(newVersion > oldVersion) {
             db.execSQL("DROP TABLE IF EXISTS " + SCORE_TABLE);
             onCreate(db);
         }
     }
 }
public class DataSource{
    //this is a link between your app and the database. you don't have to use this.
    private SQLiteDatabase database;
    private Context context;
    private DatabaseHelper helper;
    public DataSource(Context context){
        //initiate our objects.
        this.helper = new DatabaseHelper(context);
        this.database = helper.getWritableDatabase();
        this.context = context;
    }
    public void setScore(int score){
        //we update the Score column where the ID is 1
            database.execSQL("UPDATE " + DatabaseHelper.SCORE_TABLE + " SET Score = " + score + " WHERE ID = 1;");
    }
    public int getScore(){
        //we get all of the columns that have a ID of one. There should only be one column.
        Cursor score = database.rawQuery("SELECT * FROM " + DatabaseHelper.SCORE_TABLE + " WHERE ID = 1", null);
        //this isn't especially needed, but i found that adding checks and balances keeps crashes down.
        if(score.getColumnCount() < 1){
            return 0;
        } else {
            //this is important! You have to move the cursor to the first row.
            score.moveToFirst();
            //now we get the data on row 1 (actually 2 if you look at it from a 1 based number system..)
            int mscore = score.getInt(1);
            //close the cursor
            score.close();
            //and finally return the score.
            return mscore;
        }
    }
}

要使用上面的代码,只需创建一个DataSource对象并调用setScore和getScore方法。

相关内容

最新更新