繁体   English   中英

Android应用程序将高分值存储为共享首选项中的int。 如果得分超过100,则应用会引发出站异常

[英]Android app stores high score value as int in sharedpreferences. The app throws an outofbounds exception if a score over 100 is reached

我有一个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(4.4.4)上正常工作或至少可以工作。

我将在单独的文件中创建类,但是由您自己决定。 例如,我只是在默认活动中使用了它们,并在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方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM