編輯:關於Android編程
本文介紹Android中關於Activity的兩個神秘方法:onSaveInstanceState()和onRestoreInstanceState(),並且在介紹這兩個方法之後,再分別來實現使用InstanceState保存和恢復數據功能、Android實現屏幕旋轉異步下載效果這樣兩個示例。
首先來介紹onSaveInstanceState()和onRestoreInstanceState()。關於這兩個方法,一些朋友可能在Android開發過程中很少用到,但在有時候掌握其用法會幫我們起到比較好的效果。尤其是在應用程序在不知道的情況下退出後,如何實現其數據保存的功能。先來讓我們看下這兩個方法的有什麼樣的作用。
這就是onSaveInstanceState() 和 onRestoreInstanceState() 兩個函數的基本作用和用法。
總而言之,onSaveInstanceState()的調用遵循一個重要原則,即當系統存在“未經你許可”時銷毀了我們的activity的可能時,則onSaveInstanceState()會被系統調用,這是系統的責任,因為它必須要提供一個機會讓你保存你的數據(當然你不保存那就隨便你了)。如果調用,調用將發生在onPause()或onStop()方法之前。(雖然測試時發現多數在onPause()前)
onRestoreInstanceState()在onStart() 和 onPostCreate(Bundle)之間調用。
由上所述, 如果我們需要覆寫onSaveInstanceState()方法, 一般會在第一行代碼中調用該方法的默認實現:super.onSaveInstanceState(outState)。
由於onSaveInstanceState()方法方法不一定會被調用,因此不適合在該方法中保存持久化數據,例如向數據庫中插入記錄等.。保存持久化數據的操作應該放在onPause()中。若是永久性值,則在onPause()中保存;若大量,則另開線程吧,別阻塞UI線程。
另外,當屏幕的方向發生了改變,Activity會被摧毀並且被重新創建,如果你想在Activity被摧毀前緩存一些數據,並且在Activity被重新創建後恢復緩存的數據。可以重寫Activity的 onSaveInstanceState() 和 onRestoreInstanceState()方法,如下代碼所示:
import android.R; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; /** * Android使用InstanceState保存和恢復數據 */ public class MainActivity extends Activity { private String message = ""; private EditText text = null; private Button button = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); text = (EditText) findViewById(R.id.editText1); button = (Button) findViewById(R.id.btnSave); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(getApplicationContext(), "保存", Toast.LENGTH_SHORT).show(); } }); } @Override public void onResume() { super.onResume(); Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG) .show(); } @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); savedInstanceState.putString("message", text.getText().toString()); } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); message = savedInstanceState.getString("message"); } }還有需要注意的是,onSaveInstanceState()方法並不是一定會被調用的,因為有些場景是不需要保存狀態數據的。比如用戶按下BACK鍵退出activity時,用戶顯然想要關閉這個activity,此時是沒有必要保存數據以供下次恢復的,也就是onSaveInstanceState()方法不會被調用。如果調用onSaveInstanceState()方法,調用將發生在onPause()或onStop()方法之前。
@Override public void onSaveInstanceState(Bundle savedInstanceState) { savedInstanceState.putBoolean("MyBoolean", true); savedInstanceState.putDouble("myDouble", 1.9); super.onSaveInstanceState(savedInstanceState); }
@Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); boolean myBoolean = savedInstanceState.getBoolean("MyBoolean"); double myDouble = savedInstanceState.getDouble("myDouble"); }我們可以用旋轉屏幕來測試我們的程序保存狀態的能力。因為一般旋轉時,activity會被重新執行onCreate(),onStart()等操作,程序此時能夠保存狀態是很重要的。可以考慮使用該方法保存數據。當然了在旋轉屏幕時我們除了使用onSaveInstanceState()外,還可以使用onRetainNonConfigurationInstance()和getLastNonConfigurationInstance()這兩個方法來保存切換屏幕的狀態。與onSaveInstanceState()不同的是,onRetainNonConfigurationInstance()和getLastNonConfigurationInstance() 方法主要用於屏幕之間的旋轉操作時保存數據。
@Override public Object onRetainNonConfigurationInstance() { // 在這裡設置需要保存的內容,在切換時不是bundle了,我們可以直接通過object來代替。 returnsuper.onRetainNonConfigurationInstance(); }在恢復屏幕時可以不使用onRestoreInstanceState(),而使用getLastNonConfigurationInstance()來代替。我們可以直接在oncreate()方法中獲取上次保存的對象。
@Override protectedvoid onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.main); // 獲取上次切換屏幕保存的對象 Object obj = getLastNonConfigurationInstance(); }
對於我們的程序而言,或多或少的都需要進行Activity之間的跳轉操作,其中有一些是為了獲得系統中的資源或是一些必要信息,而一般是通過啟動Activity(常用startActivity()和startActivityForResult()函數)來進行操作。在這個跳轉的期間,我們當前的Activity暫時失去了焦點,處於不可操作狀態,可在此之前先通過onSaveInstanceState()方法來保存一些暫時時的數據。當回到先前的Activity時,先前的Activity重新獲取了焦點,系統就是觸發onRestoreInstanceState()方法,可獲取失去焦點前的一些數據。onRetainNonConfigurationInstance()方法也具有類似的功能來處理這樣的數據操作。先前說過,onRetainNonConfigurationInstance()方法主要是用於屏幕的旋轉操作。
說到這裡了,可能有的人就要問了,既然onSaveInstanceState()和onRetainNonConfigurationInstance()都可以實現保存數據的功能,如果是兩個同時使用時,執行順序是哪個在先,哪個在後呢?根據Android官方網站上介紹,如果兩個方法同時出現時,onSaveInstanceState()方法執行在先,而onRetainNonConfigurationInstance()方法執行在後。它們的執行順序都在onStop()和onDestroy()之間,關於這點需要我們大家注意。
之前在其它網站上看到有的朋友說:"onSaveInstanceState()和onRetainNonConfigurationInstance()既然都可以實現保存數據的功能,而且onSaveInstanceState()相比onRetainNonConfigurationInstance()方法可以實現更多情況下的數據保存功能,那麼onRetainNonConfigurationInstance()豈不是多余的嗎?"。關於這點,從設計的角度看,onRetainNonConfigurationInstance()並不是多余的函數。一般情況下,如果我們要保存的數據不太大,而且適合放在Bundle中,那麼使用onSaveInstanceState()是比較合適的;如果要保存的數據不適合放在Bundle中(比如:一個socket)或是數據比較大(比如:一個Bitmap),那麼這個時間我們就應該使用onRetainNonConfigurationInstance(),而且我們使用onRetainNonConfigurationInstance()可以保存任何類型的對象,像AsyncTask和SQLiteDatabse,我們都可以進行保存。這些類型的數據可能會被一個新的Activity實例所重新使用。所以onSaveInstanceState()和onRetainNonConfigurationInstance()在我們的程序中扮演的是不同的角色,需要在不同的時機下調用,用來處理不同類型的數據。
例如下面代碼所示要保存一個復雜的數據:
import android.graphics.Bitmap; public class DataHolder { int a; Bitmap b; String s; public Object onRetainNonConfigurationInstance() { DataHolder dh = new DataHolder(); dh.a = a; dh.b = b; dh.s = s; return dh; } }
不過呢,onRetainNonConfigurationInstance()在新版本的SDK中是一個過時的方法,我們可以用setRetainInstance(boolean)來代替onRetainNonConfigurationInstance(),在舊的平台中我們仍然可以使用onRetainNonConfigurationInstance()。如果是部分朋友不知道如何使用setRetainInstance(boolean)來保存自定義的對象數據,可以使用onRetainCustomNonConfigurationInstance()來代表onRetainNonConfigurationInstance(),同時使用getLastCustomNonConfigurationInstance()代替getLastNonConfigurationInstance()。
下面是一個使用onRetainNonConfigurationInstance()和getLastNonConfigurationInstance()來實現屏幕旋轉時異步下載更新進度條並保存數據的效果,代碼如下所示:import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.os.SystemClock; import android.util.Log; import android.view.View; import android.widget.ProgressBar; /** * Android實現屏幕旋轉異步下載效果 * * @Description: Android實現屏幕旋轉異步下載效果 * * @File: RotationAsyncActivity.java * * @Package com.rotation.demo * * @Author Hanyonglu * * @Date 2012-03-28 下午08:14:57 * * @Version V1.0 */ public class RotationAsyncActivity extends Activity { // 進度條 private ProgressBar progressBar = null; // 異步任務類 private RotationAsyncTask asyncTask = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); progressBar = (ProgressBar) findViewById(R.id.progress); // 獲取對象 asyncTask = (RotationAsyncTask) getLastNonConfigurationInstance(); if (asyncTask == null) { asyncTask = new RotationAsyncTask(this); asyncTask.execute(); } else { asyncTask.attach(this); updateProgress(asyncTask.getProgress()); if (asyncTask.getProgress() >= 100) { markAsDone(); } } } /** * 保存對象 */ @Override public Object onRetainNonConfigurationInstance() { asyncTask.detach(); return asyncTask; } private void updateProgress(int progress) { progressBar.setProgress(progress); } private void markAsDone() { findViewById(R.id.completed).setVisibility(View.VISIBLE); } // 異步任務類 private static class RotationAsyncTask extends AsyncTask我們在運行示例時就會發現,無論怎樣旋轉屏幕都不會影響進度條的更新與下載,需要解釋下的是這裡我並沒有設置下載功能,有興趣或需要的朋友自己添加即可。實現效果圖如下所示:{ private RotationAsyncActivity activity = null; private int progress = 0; /** * 默認的構造器 */ public RotationAsyncTask() { // TODO Auto-generated constructor stub } /** * 帶參構造器 * * @param activity */ public RotationAsyncTask(RotationAsyncActivity activity) { attach(activity); } @Override protected Void doInBackground(Void... unused) { for (int i = 0; i < 20; i++) { SystemClock.sleep(500); publishProgress(); } return null; } @Override protected void onProgressUpdate(Void... unused) { if (activity == null) { Log.w("RotationAsyncActivity", "onProgressUpdate()"); } else { progress += 5; activity.updateProgress(progress); } } @Override protected void onPostExecute(Void unused) { if (activity == null) { Log.w("RotationAsyncActivity", "onPostExecute()"); } else { activity.markAsDone(); } } protected void detach() { activity = null; } protected void attach(RotationAsyncActivity activity) { this.activity = activity; } protected int getProgress() { return progress; } } }
以上就是在Android中關於InstanceState保存數據和恢復數據的過程,在這裡我想再重復一遍:onSaveInstanceState()和onRestoreInstanceState()機制來保存數據時,它僅在非用戶顯式的指令殺死應用程序時保存和恢復數據。我們可以使用它在我們的程序中來保存數據,可以作為保存數據的一種方式,但在使用過程中需要注意其使用原理和方法。
Android PreferenceActivity與PreferenceFragment前言轉來轉去又回到了Android,閒話少說,這裡是參考Androi
SharedPreferences是Android中最容易理解的數據存儲技術,實際上SharedPreferences處理的就是一個key-value(鍵值對)。Shar
Android4.4新特性,系統狀態欄一體化。 實現的步驟主要有以下幾點: 1.android4.4 以上版本 2.設置app全屏: 方法:在AndroidManifes
本文實例講述了Android開發之自定義View(視圖)用法。分享給大家供大家參考,具體如下:View類是Android的一個超類,這個類幾乎包含了所有的屏幕類型。每一個