【问题标题】:Android getSharedPreferences startActivityForResult intermittent errorAndroid getSharedPreferences startActivityForResult 间歇性错误
【发布时间】:2016-07-05 23:17:23
【问题描述】:

我有一个游戏,其main 活动使用startActivityForResult 调用其他三个活动——第一个 (SignInActivity) 返回用户名,或允许创建新用户名;第二个 (LevelChooser) 使用 getSharedPreferences 查找具有该用户名的首选项文件,或创建一个新的,显示用户到目前为止的进度(已解锁的级别,获得的星星),并允许用户选择播放任何解锁级别;第三个(GameActivity)在返回(通过main)到LevelChooser之前,如果成功完成关卡,则更新用户的首选项文件。在LevelChooser 中,我已覆盖onBackPressed 以将您返回到SignInActivity;在 GameActivity 中,onFinish 被覆盖,因此无论发生什么情况,您都可以返回到 LevelChooser

现在,十分之九这一切都完全按照预期工作,但有时却并非如此:有时,LevelChooser 没有看到用户的实际星星和等级,而是显示一组不正确且理论上不可能的值(例如,一个级别显示为锁定,但以三颗星完成)。如果您选择一个关卡然后在您第一次打开游戏时退出该关卡,这通常(但并非总是)会发生:然后它将允许您玩显示为解锁的任何关卡,但GameActivity 无法保存您的结果,如果你完成了关卡,当你回到LevelChooser时显示同样的错误关卡;或者,如果您退出 LevelChooser 并重新选择相同的用户名,它会恢复到预期的行为。我还设法通过反复启动关卡并退出关卡来重现错误——如果你尝试了足够多的时间,它最终会出错。对于我自己的用户名(我认为,对于所有用户),错误信息总是相同的,即问题是间歇性的,但当它发生时,不是随机的。

我尝试过调试,但由于某种原因,(a) 问题只发生在我的手机上,而不是模拟器上,并且 (b) 在我的手机上调试(而不是运行)时,它要么正常工作,要么,如果出错,则简单地终止(AFAIR 甚至没有“X 已停止”对话框),而不是显示错误的关卡屏幕。我在调试中唯一看到的是LevelChooser 活动的onCreate 有时会执行多次。

因为问题是间歇性的,并且不能直接重现,我想知道我是否无意中假设某些异步过程已经/将会以及时、线性的方式完成,并且它通常(但不总是)有义务;否则,我认为我未能理解与 Activity 生命周期相关且重要的内容。否则,我很难过和猜测。

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();
}

正确显示截图:

上面选择Level 1然后退出后的截图:

【问题讨论】:

    标签: android-intent sharedpreferences extras intermittent startactivityforresult


    【解决方案1】:

    事实证明,问题不在于getSharedPreferences() 本身,而是getIntent().getStringExtra() 返回的变量user 有时——在我发现难以确定或可靠再现的情况下——@ 987654325@,如this question。然后将该字符串用作getSharedPreferences() 的参数,从而为用户null 生成一组保存的结果。然后,每次问题再次出现时,都会显示这些结果(显示在问题的第二张图片中)。

    解决方案——尽管它仍然没有解释为什么 getStringExtra() 应该返回 null——是通过将以下代码放入需要有效的两个活动的 onCreate用户:

    if(getIntent().getExtras()==null || getIntent().getStringExtra("user")==null) {
        Intent intent = new Intent();
        setResult(0, intent);
        finish();
        }
    

    如果在加载新活动的布局之前执行此操作,它会返回主活动并再次尝试(可以这么说),而用户不会看到任何问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-20
      • 1970-01-01
      • 2023-03-07
      • 1970-01-01
      • 1970-01-01
      • 2012-08-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多