简体   繁体   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

I have an Android game that uses the SharedPreferences to store the high score for the game on the device. 我有一个Android游戏,该游戏使用SharedPreferences在设备上存储游戏的高分。 This works perfectly well until the high score on the device exceeds 100 points at which time it causes the app to crash the next time it gets the int from the SharedPreferences. 在设备上的高分超过100分之前,这将非常有效,这将导致应用程序在下次从SharedPreferences获取int时崩溃。 Here is the code related to storing and retrieving the score from SharedPreferences. 这是与从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 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)

I would comment this but since i'm under 50 in score i cant.. A simple solution would be to just store the value in a String. 我会对此发表评论,但是由于我的得分低于50,所以我不能。.一个简单的解决方案是将值存储在String中。 Like this: 像这样:

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

and when you get it out of the shared preference just do 而当您从共享首选项中删除它时,只需执行

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

Personally i'm not a huge fan of shared preferences and instead opt for a sqlite database. 我个人不是共享首选项的忠实拥护者,而是选择sqlite数据库。 The read / write sequences are so much faster when using a database.. 使用数据库时,读/写序列非常快。

One thing you might try is using .apply instead of .commit - .apply runs in the background.. 您可能要尝试的一件事是使用.apply而不是.commit-.apply在后台运行。

As you asked, i'm providing some code i wrote to help you with your database. 如您所问,我正在提供一些我编写的代码来帮助您使用数据库。 I just wrote it and tried it so i know that it works or at least worked on my GS3 (4.4.4) and my OnePlus one (4.4.4). 我只是编写并尝试使用它,所以我知道它可以在我的GS3(4.4.4)和OnePlus One(4.4.4)上正常工作或至少可以工作。

I would create the classes in separate files but its up-to you. 我将在单独的文件中创建类,但是由您自己决定。 For the example i just used them in my default activity and ran some set / get score code in the onCreate. 例如,我只是在默认活动中使用了它们,并在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;
        }
    }

}

To use the above code just Create a DataSource object and call the setScore and getScore methods. 要使用上面的代码,只需创建一个DataSource对象并调用setScore和getScore方法。

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

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