Android视图 - 活动中自动保存和恢复的内容

时间:2017-07-25 22:03:31

标签: android activity-lifecycle android-savedstate

我是Android的初学者。

在Android中,可以在nnoremap <buffer><silent> <C-]> :<C-U>exe v:count1."tag <Plug><cword>"<CR> nnoremap <buffer><silent> g] :<C-U>tselect <Plug><cword><CR> nnoremap <buffer><silent> g<C-]> :<C-U>tjump <Plug><cword><CR> / onSaveInstanceState中自动保存/恢复某些通用元素。

例如,onRestoreInstanceState保存/恢复EditText属性,Text保存/恢复RatingBar属性...

我从一些测试中看到,但我在文档中找不到任何相关内容。

如果没有我的干预,我如何能够隐含地知道保存/恢复的内容?

例如,我可以在哪里找到Rating自动保存/恢复?

我特别不想测试所有属性。

从JRG回复编辑:

https://developer.android.com/guide/components/activities/activity-lifecycle.html

  

保存您的活动状态当您的活动开始停止时,系统   调用onSaveInstanceState()方法&lt; ...&gt;默认实现   这种方法可以保存关于状态的瞬态信息   activity的视图层次结构,例如EditText小部件中的文本或   ListView小部件的滚动位置。

我怎么知道保存/恢复的默认实现是什么?

重读JRG回答后的第二次编辑:

  

默认情况下,系统使用Bundle实例状态来保存有关&gt;活动布局中每个View对象的信息(例如输入&gt; EditText小部件的文本值)。

默认实现保存/恢复元素视图的所有状态。

2 个答案:

答案 0 :(得分:7)

解释有关保存状态的Android文档以及关于在活动和片段中保存状态的非常好的文章。

  

保存和恢复活动状态在某些情况下,您的活动会因应用程序的正常行为而被销毁,例如当用户按下“返回”按钮或您的活动通过调用发出自己的销毁信号时finish()方法。如果活动处于“已停止”状态且未长时间使用,或者前台活动需要更多资源,系统还可能会破坏包含您的活动的进程以恢复内存。

     

当您的活动因用户按下Back或活动自行完成而被销毁时,该Activity实例的系统概念将永远消失,因为该行为表明不再需要该活动。但是,如果系统由于系统约束(而不是正常的应用程序行为)而破坏活动,那么虽然实际的Activity实例已经消失,但系统会记住它存在,如果用户导航回它,系统会创建一个新的活动的实例,使用一组保存的数据来描述销毁时的活动状态。系统用于恢复先前状态的已保存数据称为实例状态,是存储在Bundle对象中的键值对的集合。

     

默认情况下,系统使用Bundle实例状态来保存活动布局中每个View对象的信息(例如输入EditText小部件的文本值)。 因此,如果您的活动实例被销毁并重新创建,布局的状态将恢复到之前的状态,而您无需代码。但是,您的活动可能包含您要恢复的更多状态信息,例如跟踪用户在活动中的进度的成员变量。

     

保存您的活动状态   当您的活动开始停止时,系统会调用onSaveInstanceState()方法,以便您的活动可以使用一组键值对来保存状态信息。此方法的默认实现保存有关活动视图层次结构状态的瞬态信息,例如EditText小部件中的文本或ListView小部件的滚动位置。您的应用应该在onPause()方法之后和onStop()之前实现onSaveInstanceState()回调。不要在onPause()中实现此回调。

     

警告:必须始终调用onSaveInstanceState()的超类实现,以便默认实现可以保存视图层次结构的状态。

     

要保存活动的其他状态信息,必须覆盖onSaveInstanceState()并将键值对添加到Bundle对象中,该对象在您的活动意外销毁时保存。例如:

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...


@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state
    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
    savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);


    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}
  

注意:为了让Android系统恢复活动中的视图状态,每个视图必须具有唯一的ID,由android:id属性提供。

     

要保存持久性数据(例如用户首选项或数据库的数据),您应该在活动位于前台时采取适当的机会。如果没有这样的机会,您应该在onStop()方法中保存这些数据。

     

恢复您的活动状态   在先前销毁活动后重新创建活动时,可以从系统传递给活动的Bundle中恢复已保存的状态。 onCreate()和onRestoreInstanceState()回调方法都接收包含实例状态信息的相同Bundle。

     

因为无论系统是创建活动的新实例还是重新创建前一个实例,都会调用onCreate()方法,因此在尝试读取之前必须检查状态Bundle是否为null。如果它为null,则系统正在创建活动的新实例,而不是恢复之前被销毁的实例。

     

例如,以下代码段显示了如何在onCreate()中恢复某些状态数据:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Always call the superclass first


    // Check whether we're recreating a previously destroyed instance
    if (savedInstanceState != null) {
        // Restore value of members from saved state
        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // Probably initialize members with default values for a new instance
    }
    ...
}
  

您可以选择实现onRestoreInstanceState(),系统在onStart()方法之后调用,而不是在onCreate()期间恢复状态。仅当存在要恢复的已保存状态时,系统才会调用onRestoreInstanceState(),因此您无需检查Bundle是否为null:

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);


    // Restore state members from saved instance
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}
  

警告:始终调用onRestoreInstanceState()的超类实现,以便默认实现可以恢复视图层次结构的状态。

答案 1 :(得分:2)

这是一个向你解释的例子......

  • 默认保存什么以及如何保存?
  • 您需要添加哪些数据才能保存代码?

我创建了一个简单的android项目,它总共有4个数据点,在应用程序生命周期的某个时刻会有一些价值。

  1. 活动内部变量saveMe
  2. 活动内部变量saveMeNot
  3. 查看EditText withid(有android:id)
  4. 查看的EditText(没有android:id)
  5. 根据屏幕截图,这是一系列事件。

    1. 启动Android应用
    2. 点击SAVE按钮设置内部变量saveMesaveMeNot的值。将显示Toast,它保存了两个变量的值。
    3. 在Hello和Hi等编辑文本中键入一些文本。这将在编辑文本中设置文本。
    4. 旋转屏幕,即方向改变。以下将发生....
      • Android会保存android:id中定义activity_main.xml的所有观看次数的值。这里只有Hello将被保存为EditText,其中键入的Hello具有android:id=@+id/withId。另一个包含文字Hi的EditText不会被Android自动保存,因为它没有任何android:id。这是您免费获得的(前提是您的所有视图都已定义android:id)。如果您具有扩展View的自定义视图,那么它们也会定义android:id
      • Android还调用onSaveInstanceState和onRestoreInstanceState,它使您能够存储活动的所有内部变量的状态,即saveMesaveMeNot。你必须为它编码,否则状态就会丢失。就像在我的例子中一样,我保存了saveMe的状态而不是saveMeNot。这是你不能免费获得的东西,即你必须为它编码。
    5. 点击CLICK ME按钮查看saveMesaveMeNot的值,您将看到只显示saveMe值,因为它已在{{1}中保存并在onSaveInstanceState
    6. 中检索

      步骤顺序

      enter image description here

      代码

      的AndroidManifest.xml

      onRestoreInstanceState

      MainActivity.java

      <?xml version="1.0" encoding="utf-8"?>
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="test.saveinstance">
      
          <application
              android:allowBackup="true"
              android:icon="@mipmap/ic_launcher"
              android:label="@string/app_name"
              android:roundIcon="@mipmap/ic_launcher_round"
              android:supportsRtl="true"
              android:theme="@style/AppTheme">
              <activity android:name=".MainActivity">
                  <intent-filter>
                      <action android:name="android.intent.action.MAIN" />
      
                      <category android:name="android.intent.category.LAUNCHER" />
                  </intent-filter>
              </activity>
          </application>
      
      </manifest>
      

      activity_main.xml中

      package test.saveinstance;
      
      import android.support.v7.app.AppCompatActivity;
      import android.os.Bundle;
      import android.util.Log;
      import android.view.View;
      import android.widget.Button;
      import android.widget.Toast;
      
      public class MainActivity extends AppCompatActivity {
      
          // will save in bundle in onSaveInstanceState
          private int saveMe;
      
          // will not save in bundle in onSaveInstanceState
          private int saveMeNot;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
              // do some action that generates values for
              // activity specific variables i.e. saveMe
              // and saveMeNot
              Button saveButton = (Button) findViewById(R.id.save);
              saveButton.setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View view) {
                      saveMe = 10;
                      saveMeNot = 20;
                      Toast.makeText(getApplicationContext(), "SAVED: saveMe: " + saveMe + ";saveMeNot: " + saveMeNot, Toast.LENGTH_LONG).show();
                  }
              });
      
              // will be used to display value of
              // saveMe and saveMeNot after orientation
              // changes.
              Button button = (Button) findViewById(R.id.button);
              button.setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View view) {
                      Toast.makeText(getApplicationContext(), "DISPLAY: saveMe: " + saveMe + ";saveMeNot: " + saveMeNot, Toast.LENGTH_LONG).show();
                  }
              });
          }
      
          @Override
          protected void onSaveInstanceState(Bundle outState) {
              // save saveMe in bundle
              outState.putInt("saveMe", saveMe);
              super.onSaveInstanceState(outState);
              Log.d("TEST", "Saving saveMe in bundle during orientation change");
          }
      
          @Override
          protected void onRestoreInstanceState(Bundle savedInstanceState) {
              super.onRestoreInstanceState(savedInstanceState);
              // retrieve saveMe from bundle
              saveMe = savedInstanceState.getInt("saveMe");
              Log.d("TEST", "Retrieving saveMe in bundle during orientation change");
          }
      }