2017-07-25 40 views
1

我是Android的初學者。Android視圖 - 什麼是自動保存和恢復活動

在Android中,一些泛型元素可以在onSaveInstanceState/onRestoreInstanceState中自動保存/恢復。

例如,EditText上保存/恢復的Text屬性的RatingBar保存/恢復等級屬性...

我從一些測試看看,但我不能找到文檔中沒有談到這個。

我的問題:

我怎麼知道什麼是保存/恢復沒有我的干預?

例如,在哪裏可以找到EditText.Text自動保存/恢復?

我確切我不想測試所有屬性。從JRG答案

編輯:

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

保存您的活動狀態當你的活動開始,停止, 調用的onSaveInstanceState()方法< ...>默認實現系統該方法的 保存關於 活動的視圖層次的狀態的瞬態信息,例如EditText小部件中的文本或ListView的滾動位置wi DGET。

我如何知道保存/恢復的默認實現?

第二個編輯重讀後JRG答案:

默認情況下,系統採用Bundle實例狀態,以節省約>在活動佈局每個視圖對象(如文本值進入>一個EditText信息小部件)。

默認實現保存/恢復元素視圖的所有狀態。

回答

2

Android文檔解釋了關於保存狀態和關於在活動和片段中保存狀態的非常好的文章。

保存和恢復活動狀態有些情況下,你的活動是由於正常的應用程序的行爲摧毀了幾個方案,比如當用戶按下「後退」按鈕,或者您的活動通過調用finish()方法來標記自己的銷燬。如果活動處於停止狀態並且很長一段時間未使用活動,或者前臺活動需要更多資源,系統還可能銷燬包含活動的進程以恢復內存。

當您的活動因用戶按下「後退」或活動自行完成而被銷燬時,該活動實例的系統概念將永遠消失,因爲該行爲表示活動不再需要。但是,如果系統由於系統限制(而不是正常的應用程序行爲)而破壞了活動,那麼雖然實際的活動實例已經消失,但系統會記住它已存在,因此如果用戶導航回它,系統會創建一個新的使用一組保存的數據描述活動在銷燬時的狀態。系統用於恢復先前狀態的已保存數據稱爲實例狀態,是存儲在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,由機器人提供:id屬性。

要保存持久數據(例如用戶首選項或數據庫數據),當您的活動處於前臺時,應該採取適當的機會。如果沒有這樣的機會出現,您應該在onStop()方法中保存這些數據。

恢復您的活動狀態 當您的活動被重建後,先前被破壞,可以從捆綁恢復保存的狀態,該系統傳遞到您的活動。 onCreate()和onRestoreInstanceState()回調方法都會收到包含實例狀態信息的相同Bundle。

因爲無論系統是在創建活動的新實例還是重新創建前一個實例,都會調用onCreate()方法,您必須在嘗試讀取之前檢查狀態Bundle是否爲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 
    } 
    ... 
} 

相反的onCreate()中恢復狀態,你可以選擇實施onRestoreInstanceState (),系統在onStart()方法之後調用。該系統調用onRestoreInstanceState()只如果有恢復已保存的狀態,這樣你就不會需要檢查包是否爲空:

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的( ),所以默認實現可以恢復視圖層次的狀態。

+0

從你的答案,我已經編輯我的問題。謝謝。 – Orwel

+0

查看我的第二個答案,提供更多詳細信息和代碼,以解釋什麼數據可以免費保存,哪些數據需要您編碼!如果解釋,請接受答案並投票! – JRG

+0

我不好,你迴應我的問題。感謝JRG。 – Orwel

0

這裏是解釋一個例子...

  • 什麼默認情況下,如何保存?
  • 什麼數據需要您添加代碼才能保存?

我創建了一個簡單的android項目,它總共有4個數據點,在應用程序生命週期的某個時間點有一些值。

  1. 活動內部變量saveMe
  2. 活動內部變量saveMeNot
  3. 視圖的EditText上withid(有機器人:ID)
  4. 視圖的EditText上(沒有機器人:ID)

這裏是截圖中的事件序列。

  1. 啓動Android應用程序
  2. 點擊SAVE按鈕設定值內部變量saveMesaveMeNot。將顯示一個Toast它保存了這兩個變量的值。
  3. 在編輯文本中輸入一些文本,如Hello和Hi。這將在編輯文本中設置文本。
  4. 旋轉屏幕即方向改變。以下將會發生......
    • Android將保存在activity_main.xml中定義的所有視圖的值android:id。這裏只有Hello會被保存爲EditText,其中輸入的Hello有一個android:[email protected]+id/withId。另一個具有文本Hi的EditText不會被Android自動保存,因爲它沒有任何android:id。這是你免費獲得的(如果你的所有視圖都有android:id定義)。如果您擁有擴展視圖的自定義視圖,那麼他們也有android:id定義。
    • Android還調用onSaveInstanceState和onRestoreInstanceState,它使您能夠存儲活動的所有內部變量的狀態,即saveMesaveMeNot。你必須爲它編碼,否則狀態就會丟失。就像在我的例子中,我已經保存了saveMe的狀態,而不是saveMeNot。這是你不能免費獲得的東西,即你必須爲它編碼。
  5. 點擊CLICK ME按鈕查看saveMesaveMeNot的價值觀,你會看到,因爲它是在onSaveInstanceState救了你和檢索的步驟

    onRestoreInstanceState

序列僅顯示saveMe

enter image description here

代碼

AndroidManifest.xml中

<?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> 

MainActivity.java

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

activity_main.xml中

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    tools:context="test.saveinstance.MainActivity"> 

    <EditText 
     android:id="@+id/withId" 
     android:layout_marginTop="30dp" 
     android:layout_width="match_parent" 
     android:layout_height="70dp" 
     android:gravity="center" 
     android:hint="Type Here (has android:id)" /> 

    <EditText 
     android:layout_below="@id/withId" 
     android:layout_marginTop="20dp" 
     android:layout_width="match_parent" 
     android:layout_height="70dp" 
     android:gravity="center" 
     android:hint="Type Here (doesn't have android:id)" /> 

    <Button 
     android:id="@+id/button" 
     android:layout_alignParentBottom="true" 
     android:layout_marginBottom="10dp" 
     android:text="Click Me" 
     android:layout_width="match_parent" 
     android:layout_height="50dp" /> 

    <Button 
     android:id="@+id/save" 
     android:layout_above="@id/button" 
     android:layout_marginBottom="10dp" 
     android:text="Save" 
     android:layout_width="match_parent" 
     android:layout_height="50dp" /> 

</RelativeLayout> 
+0

對不起,我的問題不清楚。一個例子。我想用'Switch'。我打開文檔:https://developer.android.com/reference/android/widget/Switch.html。我在哪裏可以看到保存/恢復? – Orwel