У меня есть игра, чья main
деятельность вызывает три других мероприятий с использованием startActivityForResult
- первый (SignInActivity
) возвращает имя пользователя, или позволяет создавать новый; второй (LevelChooser
) использует getSharedPreferences
, чтобы найти файл настроек с этим именем пользователя или создает новый, пока покажет прогресс пользователя (уровни разблокированы, заработанные звезды) и позволяет пользователю выбирать любой разблокированный уровень; третий (GameActivity
) обновляет файл настроек пользователя, если уровень завершен успешно, прежде чем вернуться (через main
) в LevelChooser
. В LevelChooser
я переопределил onBackPressed
, чтобы вернуть вас в SignInActivity; в GameActivity
это onFinish
, которое переопределено, так что вы возвращаетесь к LevelChooser
независимо от того, как это происходит.Android getSharedPreferences startActivityForResult прерывистого ошибка
Теперь, девять раз из десяти, все работает точно так, как предполагалось, но иногда это не так: иногда вместо того, чтобы видеть фактические звезды и уровни пользователя, LevelChooser
показывает набор неправильных и теоретически невозможных значений (например, один уровень, показанный как заблокированный, но завершенный тремя звездами). Это часто (но не всегда) происходит, если вы выбираете уровень, а затем возвращаетесь из него, когда вы впервые открываете игру: он позволит вам играть на любом уровне, показанном как разблокированное, но GameActivity
не сможет сохранить ваш результат, если вы закончите уровень и те же самые неправильные уровни отображаются, когда вы возвращаетесь к LevelChooser
; альтернативно, если вы вернетесь из LevelChooser
и переименуете одно и то же имя пользователя, оно вернется к поведению, как ожидалось. Я также сумел воспроизвести ошибку, повторно запустив уровни и отступив от них - если вы попробуете достаточно времени, это в конечном итоге пойдет не так. Для моего собственного имени пользователя (и I думаю, для всех пользователей) неверная информация всегда одна и та же, то есть проблема прерывистая, но, когда это происходит, не является случайным.
Я пробовал отладку, но по какой-то причине (а) проблема возникает только на моем телефоне, а не на эмуляторе, и (б) при отладке (в отличие от работы) на моем телефоне он работает правильно или иначе, если он пойдет не так, просто прекратится (AFAIR, даже не в диалоговом окне «Х остановился») вместо отображения экрана неправильного уровня. Единственное, что мне удалось обнаружить при отладке, - это то, что onCreate
активности LevelChooser
иногда выполняется несколько раз.
Поскольку проблема прерывистая, а не просто воспроизводимая, мне интересно, невольно ли я предположил, что какой-то асинхронный процесс будет/будет завершен своевременно, линейно и что он обычно (но не всегда) обязывает; или иначе, я думаю, что мне не удалось понять что-то значимое и значимое в жизненном цикле активности. В противном случае я в тупике и угадывании.
main Activity
:
public class MainActivity extends AppCompatActivity {
public ImageView splash;
private int GET_USER_NAME_CODE = 0;
private int GET_LEVEL_CODE = 1;
private int PLAY_GAME_CODE = 2;
private String user;
private int level;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// remove title
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_splash_screen);
splash = (ImageView) findViewById(R.id.splashView);
splash.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent sign_intent = new Intent(MainActivity.this, SignInActivity.class);
startActivityForResult(sign_intent, GET_USER_NAME_CODE);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
// check if the request code is same as what is passed
if(requestCode==GET_USER_NAME_CODE)
{
user=data.getStringExtra("USER");
Intent intent = new Intent(MainActivity.this, LevelChooser.class);
intent.putExtra("user", user);
startActivityForResult(intent, GET_LEVEL_CODE);
}
else {
if(requestCode==GET_LEVEL_CODE) {
level=data.getIntExtra("LEVEL", 0);
if(level==-1) {
Intent sign_intent = new Intent(MainActivity.this, SignInActivity.class);
startActivityForResult(sign_intent, GET_USER_NAME_CODE);
}
else {
Intent intent = new Intent(MainActivity.this, GameActivity.class);
intent.putExtra("user", user);
intent.putExtra("level", level);
startActivityForResult(intent, PLAY_GAME_CODE);
}
}
else {
if(requestCode==PLAY_GAME_CODE) {
user=data.getStringExtra("user");
Intent intent = new Intent(MainActivity.this, LevelChooser.class);
intent.putExtra("user", user);
startActivityForResult(intent, GET_LEVEL_CODE);
}
}
}
}
LevelChooser
:
public class LevelChooser extends AppCompatActivity {
private String user;
private ImageView[] level;
private Boolean[] locked;
private int[] stars;
private SharedPreferences userprefs;
private SharedPreferences.Editor prefseditor;
private Boolean createNewPrefsFile = false;
private int tempResIdVisible;
private int tempResIdInvisible;
private ImageView tempView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.levelchooser);
}
@Override
protected void onStart() {
super.onStart();
level = new ImageView[21];
locked = new Boolean[21];
stars = new int[21];
user = getIntent().getStringExtra("user");
userprefs = getSharedPreferences(user, MODE_PRIVATE);
prefseditor = userprefs.edit();
//level numbers for views etc start from 1 to match images etc
level[0] = null;
locked[0] = null;
stars[0] = 0;
locked[1] = false;
level[1] = (ImageView) findViewById(R.id.level1);
level[1].setOnClickListener(new LevelClickListener(level[1], 1));
if (!userprefs.contains("stars1")) {
createNewPrefsFile = true;
}
stars[1] = userprefs.getInt("stars1", 0);
if (stars[1] != 0) {
for (int j = 1; j < 4; j++) {
tempResIdInvisible = getResources().getIdentifier("stars" + j + "_1", "id", getPackageName());
tempView = (ImageView) findViewById(tempResIdInvisible);
tempView.setVisibility(View.INVISIBLE);
}
tempResIdVisible = getResources().getIdentifier("stars" + stars[1] + "_1", "id", getPackageName());
tempView = (ImageView) findViewById(tempResIdVisible);
tempView.setVisibility(View.VISIBLE);
}
for (int i = 2; i < 21; i++) {
locked[i] = userprefs.getBoolean("locked" + i, true);
if (locked[i]) {
tempResIdVisible = getResources().getIdentifier("padlock" + i, "id", getPackageName());
tempResIdInvisible = getResources().getIdentifier("level" + i, "id", getPackageName());
} else {
tempResIdVisible = getResources().getIdentifier("level" + i, "id", getPackageName());
tempResIdInvisible = getResources().getIdentifier("padlock" + i, "id", getPackageName());
level[i] = (ImageView) findViewById(tempResIdVisible);
level[i].setOnClickListener(new LevelClickListener(level[i], i));
}
tempView = (ImageView) findViewById(tempResIdVisible);
tempView.setVisibility(View.VISIBLE);
tempView = (ImageView) findViewById(tempResIdInvisible);
tempView.setVisibility(View.INVISIBLE);
stars[i] = userprefs.getInt("stars" + i, 0);
if (stars[i] != 0) {
for (int j = 1; j < 4; j++) {
tempResIdInvisible = getResources().getIdentifier("stars" + j + "_" + i, "id", getPackageName());
tempView = (ImageView) findViewById(tempResIdInvisible);
tempView.setVisibility(View.INVISIBLE);
}
tempResIdVisible = getResources().getIdentifier("stars" + stars[i] + "_" + i, "id", getPackageName());
tempView = (ImageView) findViewById(tempResIdVisible);
tempView.setVisibility(View.VISIBLE);
}
}
if (createNewPrefsFile) {
for (int i = 1; i < 21; i++) {
prefseditor.putBoolean("locked" + i, locked[i]);
prefseditor.putInt("stars" + i, stars[i]);
prefseditor.commit();
}
}
}
GameActivity
:
public class GameActivity extends AppCompatActivity implements TextToSpeech.OnInitListener {
//TTS Object
private TextToSpeech myTTS;
//TTS status check code
private int MY_DATA_CHECK_CODE = 0;
private int level;
private String user;
private PhonemeGroup levelGroup;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
level = getIntent().getIntExtra("level", 0);
user = getIntent().getStringExtra("user");
levelGroup = initializeLevels(level);
Intent checkTTSIntent = new Intent();
checkTTSIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(checkTTSIntent, MY_DATA_CHECK_CODE);
}
@Override
public void finish() {
Intent intent = new Intent();
intent.putExtra("user", user);
setResult(2, intent);
super.finish();
}
@Override
public void onStop() {
if (myTTS != null) {
myTTS.stop();
}
super.onStop();
}
@Override
public void onDestroy() {
if (myTTS != null) {
myTTS.shutdown();
}
Button ok_button = (Button) findViewById(R.id.button);
ok_button.setOnClickListener(null);
ImageView tickImageView = (ImageView) findViewById(R.id.tickImageView);
tickImageView.setOnClickListener(null);
ImageView starsView = (ImageView) findViewById(R.id.starsImageView);
starsView.setOnClickListener(null);
super.onDestroy();
unbindDrawables(findViewById(R.id.GameParentView));
System.gc();
}
Скриншот корректного отображения:
Скриншот после выбора 1-го уровня выше, а затем поддержку из: