【问题标题】:Saving UI state when moving between screens/activities Android app在屏幕/活动 Android 应用程序之间移动时保存 UI 状态
【发布时间】:2023-03-18 07:48:01
【问题描述】:

我正在做一个多屏测验应用程序。对于每个问题,我都有一个单独的活动/屏幕。在每个屏幕的底部都有下一个/上一个“按钮”,可以导航到下一个/上一个屏幕。请查看带有问题的屏幕的 UI 示例:

我有一个问题。假设用户选择问题 2 的答案,然后单击“上一个”,选择问题 1 中的答案并点击“下一个”。

我想保存问题 2 的 UI 状态,因此如果用户通过单击上一个或下一个返回问题,所选答案将保留。

我设法完成的一件事是,当用户单击 UI 停留的“上一个”时,我在清单文件中使用了以下代码:

android:launchMode="singleTask"

但是,当用户通过“下一步”回答问题时,我无法保存它。这是我的问题 2 活动代码:

package com.example.justynagolawska.quizappiteration2;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;

public class Question2Activity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_question2);

        ActionBar actionbar = getSupportActionBar();

        // Applies the custom action bar style
        getSupportActionBar().setDisplayOptions(actionbar.DISPLAY_SHOW_CUSTOM);
        getSupportActionBar().setCustomView(R.layout.action_bar);

        // Changes the action bar title
        TextView title = (TextView) getSupportActionBar().getCustomView().findViewById(R.id.action_bar_title);
        title.setText(R.string.q2_name);

        //Getting the intent with score for question 1
        Intent question2Intent = getIntent();
        final int resultQ1 = question2Intent.getIntExtra("q1result", 0);

        // Find the View that shows the next TextView
        TextView nextQuestion = (TextView) findViewById(R.id.next);

        // Set a click listener on that View
        nextQuestion.setOnClickListener(new View.OnClickListener() {
            // The code in this method will be executed when next View is clicked on.
            @Override
            public void onClick(View view) {
                //Getting the answer to question 2 checkbox 1
                CheckBox checkBox1Q2 = (CheckBox) findViewById(R.id.checkbox1Q2);
                boolean isCheckBox1Q2 = checkBox1Q2.isChecked();

                //Getting the answer to question 2 checkbox 2
                CheckBox checkBox2Q2 = (CheckBox) findViewById(R.id.checkbox2Q2);
                boolean isCheckBox2Q2 = checkBox2Q2.isChecked();

                //Getting the answer to question 2 checkbox 3
                CheckBox checkBox3Q2 = (CheckBox) findViewById(R.id.checkbox3Q2);
                boolean isCheckBox3Q2 = checkBox3Q2.isChecked();

                //Calculate Question 2 score
                int resultQ2 = calculateResultQ2(isCheckBox1Q2, isCheckBox2Q2, isCheckBox3Q2);

                Intent question3Intent = new Intent(Question2Activity.this, Question3Activity.class);
                question3Intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

                question3Intent.putExtra ("q1result", resultQ1);
                question3Intent.putExtra ("q2result", resultQ2);
                startActivity(question3Intent);
            }
        });

        // Find the View that shows the next TextView
        TextView previousQuestion = (TextView) findViewById(R.id.previous);

        // Set a click listener on that View
        previousQuestion.setOnClickListener(new View.OnClickListener() {
            // The code in this method will be executed when next View is clicked on.
            @Override
            public void onClick(View view) {
                Intent question1Intent = new Intent(Question2Activity.this, Question1Activity.class);
                startActivity(question1Intent);
            }
        });
    }

    /**
     * Check which checkbox was selected in the question 2
     *
     * @param checkBox1 is whether or not the user checked the checkbox1
     * @param checkBox2 is whether or not the user checked the checkbox2
     * @param checkBox3 is whether or not the user checked the checkbox3
     * @return the score the user got for question 2
     */
    private int calculateResultQ2(boolean checkBox1, boolean checkBox2, boolean checkBox3) {
        int result = 0;
        if (checkBox1 && checkBox2 && checkBox3) {
            result = 1;
        }
        return result;
    }

如果有人能帮助我,我将不胜感激。谢谢!

编辑:下面是我使用 sharedPreferences 的工作代码,@tahsinRupam 提出的解决方案

package com.example.justynagolawska.quizappiteration2;

import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;

public class Question2Activity extends AppCompatActivity {

SharedPreferences mypref;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_question2);

    final CheckBox checkBox1Q2 = (CheckBox) findViewById(R.id.checkbox1Q2);
    final CheckBox checkBox2Q2 = (CheckBox) findViewById(R.id.checkbox2Q2);
    final CheckBox checkBox3Q2 = (CheckBox) findViewById(R.id.checkbox3Q2);

    mypref = PreferenceManager.getDefaultSharedPreferences(this);

    ActionBar actionbar = getSupportActionBar();

    // Applies the custom action bar style
    getSupportActionBar().setDisplayOptions(actionbar.DISPLAY_SHOW_CUSTOM);
    getSupportActionBar().setCustomView(R.layout.action_bar);

    // Changes the action bar title
    TextView title = (TextView) getSupportActionBar().getCustomView().findViewById(R.id.action_bar_title);
    title.setText(R.string.q2_name);

    //Getting the intent with score for question 1
    Intent question2Intent = getIntent();


    final int resultQ1 = question2Intent.getIntExtra("q1result", 0);

    // Find the View that shows the next TextView
    TextView nextQuestion = (TextView) findViewById(R.id.next);

    // Set a click listener on that View
    nextQuestion.setOnClickListener(new View.OnClickListener() {
        // The code in this method will be executed when next View is clicked on.
        @Override
        public void onClick(View view) {


            //Getting the answer to question 2 checkbox 1
            boolean isCheckBox1Q2 = checkBox1Q2.isChecked();

            //Getting the answer to question 2 checkbox 2
            boolean isCheckBox2Q2 = checkBox2Q2.isChecked();

            //Getting the answer to question 2 checkbox 3
            boolean isCheckBox3Q2 = checkBox3Q2.isChecked();

            //Calculate Question 2 score
            int resultQ2 = calculateResultQ2(isCheckBox1Q2, isCheckBox2Q2, isCheckBox3Q2);

            Intent question3Intent = new Intent(Question2Activity.this, Question3Activity.class);
            question3Intent.putExtra ("q1result", resultQ1);
            question3Intent.putExtra ("q2result", resultQ2);
            startActivity(question3Intent);
        }
    });

    // Find the View that shows the next TextView
    TextView previousQuestion = (TextView) findViewById(R.id.previous);

    // Set a click listener on that View
    previousQuestion.setOnClickListener(new View.OnClickListener() {
        // The code in this method will be executed when next View is clicked on.
        @Override
        public void onClick(View view) {
            Intent question1Intent = new Intent(Question2Activity.this, Question1Activity.class);
            startActivity(question1Intent);
        }
    });
}

/**
 * Check which checkbox was selected in the question 2
 *
 * @param checkBox1 is whether or not the user checked the checkbox1
 * @param checkBox2 is whether or not the user checked the checkbox2
 * @param checkBox3 is whether or not the user checked the checkbox3
 * @return the score the user got for question 2
 */
private int calculateResultQ2(boolean checkBox1, boolean checkBox2, boolean checkBox3) {
    int result = 0;
    if (checkBox1 && checkBox2 && checkBox3) {
        result = 1;
    }
    return result;
}

@Override
protected void onPause() {
    super.onPause();

    //Getting the answer to question 2 checkbox 1
    CheckBox checkBox1Q2 = (CheckBox) findViewById(R.id.checkbox1Q2);
    boolean isCheckBox1Q2 = checkBox1Q2.isChecked();

    //Getting the answer to question 2 checkbox 2
    CheckBox checkBox2Q2 = (CheckBox) findViewById(R.id.checkbox2Q2);
    boolean isCheckBox2Q2 = checkBox2Q2.isChecked();

    //Getting the answer to question 2 checkbox 3
    CheckBox checkBox3Q2 = (CheckBox) findViewById(R.id.checkbox3Q2);
    boolean isCheckBox3Q2 = checkBox3Q2.isChecked();

    if(isCheckBox1Q2 == true){
        mypref.edit().putBoolean("Iscb1Checked", true).apply();
    }
    else if(isCheckBox1Q2 == false){
        mypref.edit().putBoolean("Iscb1Checked", false).apply();
    }

    if(isCheckBox2Q2 == true){
        mypref.edit().putBoolean("Iscb2Checked", true).apply();
    }
    else if(isCheckBox2Q2 == false){
        mypref.edit().putBoolean("Iscb2Checked", false).apply();
    }

    if(isCheckBox3Q2 == true){
        mypref.edit().putBoolean("Iscb3Checked", true).apply();
    }
    else if(isCheckBox3Q2 == false){
        mypref.edit().putBoolean("Iscb3Checked", false).apply();
    }

}

@Override
protected void onResume() {
    super.onResume();

    //Getting the answer to question 2 checkbox 1
    CheckBox checkBox1Q2 = (CheckBox) findViewById(R.id.checkbox1Q2);

    //Getting the answer to question 2 checkbox 2
    CheckBox checkBox2Q2 = (CheckBox) findViewById(R.id.checkbox2Q2);

    //Getting the answer to question 2 checkbox 3
    CheckBox checkBox3Q2 = (CheckBox) findViewById(R.id.checkbox3Q2);

    if(mypref.contains("Iscb1Checked")){
        if(mypref.getBoolean("Iscb1Checked",false)){
            checkBox1Q2.setChecked(true);
        }
    }

    if(mypref.contains("Iscb2Checked")){
        if(mypref.getBoolean("Iscb2Checked",false)){
            checkBox2Q2.setChecked(true);
        }
    }

    if(mypref.contains("Iscb3Checked")){
        if(mypref.getBoolean("Iscb3Checked",false)){
            checkBox3Q2.setChecked(true);
        }
    }
}

}

请注意,我在 onPause(); 中替换了以下内容;方法,因为我得到空异常:

checkBox1Q2.isChecked()
!checkBox1Q2.isChecked()

isCheckBox1Q2 == true
isCheckBox1Q2 == false

【问题讨论】:

  • 你为什么用android:launchMode="singleTask"
  • 保存用户点击“上一个”时的 UI 状态。它完成了我需要做的一半工作,但当然不是我想要实现的。如果我找到上述问题的有效解决方案,我根本不必使用它。
  • 我认为如果您使用 viewpager,那将解决您的问题,它将保存用户 UI 更改直到销毁
  • 您可以使用 saveInstanceState 或 SharedPreference 来满足您的要求。
  • 嗨@tahsinRupam。谢谢您的建议。您能否详细说明我应该如何应用 saveInstanceState?我试图这样做,但我猜它只是在我旋转屏幕时保存 UI 状态?

标签: android savestate multiscreen


【解决方案1】:

您可以使用 SharedPreference 来存储您的值。

1) 公开声明 checkbox 和 SharedPreference:

 CheckBox checkBox1Q2;
 CheckBox checkBox2Q2;
 CheckBox checkBox3Q2;
 SharedPreferences mypref;

2) 在你的 onCreate() 中初始化 SharedPreference:

 mypref = PreferenceManager.getDefaultSharedPreferences(this);

3) 在 onPause() 中保存 Checkbox 状态(因为按下后退按钮时会调用 onPause())。你也可以在 onStop() 或 onDestroy() 中声明。

  @Override
protected void onPause() {
    super.onPause();
    if(checkBox1Q2.isChecked()){
        mypref.edit().putBoolean("Iscb1Checked", true).apply();
    }
    else if(!checkBox1Q2.isChecked()){
        mypref.edit().putBoolean("Iscb1Checked", false).apply();
    }

    if(checkBox2Q2.isChecked()){
        mypref.edit().putBoolean("Iscb2Checked", true).apply();
    }
    else if(!checkBox2Q2.isChecked()){
        mypref.edit().putBoolean("Iscb2Checked", false).apply();
    }

    if(checkBox3Q2.isChecked()){
        mypref.edit().putBoolean("Iscb3Checked", true).apply();
    }
    else if(!checkBox3Q2.isChecked()){
        mypref.edit().putBoolean("Iscb3Checked", false).apply();
    }


}

4) 在 onResume() 方法中获取 CheckBox 状态:

@Override
protected void onResume() {
    super.onResume();
        if(mypref.contains("Iscb1Checked")){
            if(mypref.getBoolean("Iscb1Checked",false)){
                checkBox1Q2.setChecked(true);
            }
        }

        if(mypref.contains("Iscb2Checked")){
            if(mypref.getBoolean("Iscb2Checked",false)){
                checkBox2Q2.setChecked(true);
            }
        }

        if(mypref.contains("Iscb3Checked")){
             if(mypref.getBoolean("Iscb3Checked",false)){
                checkBox3Q2.setChecked(true);
             }
         }
}

您现在在 onClick 中获得了 Checkbox 视图。尽量避免这种情况。始终在 onCreate 的初始部分(setContentView 之后)获取视图(findViewById)。

【讨论】:

  • 嗨@tahsinRupam,由于某种原因它对我不起作用。我在 onCreate(); 之前应用了完全相同的代码;方法。你能告诉我有什么问题吗?我还看到了这篇文章:stackoverflow.com/questions/151777/…,声称 savedInstanceState 仅适用于您处于同一活动中时,例如屏幕旋转?也许 sharedPrefrences 会是一个更好的主意,你怎么看?
  • 是的,你完全正确!读了各种意见,我感到很困惑。当系统出于资源目的或屏幕旋转而终止活动时,捆绑数据很有用。但是,当一个活动由于应用程序行为(如后退按钮按下)而被终止时,活动实例将永久消失。所以 saveInstanceState 在这里不起作用。在这个问题上使用 SharedPreference 是明智的。
  • 如果您愿意,我将编辑我的答案以使用 SharedPreference 解决问题。
  • 那太好了!谢谢!
  • Stackoverflow 会因为这个广泛的评论块而杀了我;)但要感谢您为这个问题付出的努力和时间!
猜你喜欢
  • 2012-05-30
  • 1970-01-01
  • 2011-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-26
  • 1970-01-01
相关资源
最近更新 更多