我有一款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方法。