android之Files,Saving State,Preferences(一)

 

保存簡單的APP數據

1.Shared Preferences html

是一個簡單,輕量級的,以鍵值對的機制(name/value pair---NVP)存儲一些基礎數據(Boolean,string,float等),最經常使用在保存用戶的APP參數。 java

2.保存APP~UI狀態 android

當APP被移到後臺,Activity和Fragment都包含用來幫助記錄當前UI狀態的生命週期事件回調函數。 緩存

3.Files 安全

文件不是完美的選擇,可是有時候讀寫文件是惟一的選擇。安卓可讓你在外部或者內部媒介上建立文件,也提供支持在公有訪問的文件夾下建立臨時緩存文件和存儲文件。 app

 

建立和保存Shared Preferences

去建立或者修改Shared Prefence,經過調用getSharedPreferences. 框架

SharedPreferences mySharedPreferences = getSharedPreferences(MY_PREFS,Activity.MODE_PRIVATE); 異步

如何去修改呢? ide

答:使用SharedPreferences.Editor類。 函數

SharedPreferences.Editor editor = mySharedPreferences.edit();

根據指定的鍵,使用put方法去更新或者插入值。

// Store new primitive types in the shared preferences object.  
editor.putBoolean(「isTrue」, true); 
editor.putFloat(「lastFloat」, 1f); 
editor.putInt(「wholeNumber」, 2);  
editor.putLong(「aNumber」, 3l); 
editor.putString(「textEntryValue」, 「Not Empty」);

 

完了後,須要提交一下,使用editor.apply()或者editor.commit() 前者是異步的,後者是同步的。

注意:apply方法是在API level 9(Android 2.3)引入的。使用此方法,能夠安全得異步寫入。由於是異步,因此一般這個方法更受歡迎。

若是你使用commit呢,是會阻塞調用的線程,寫入成功會返回true,反之亦然。

 

獲取Shared Preferences

直接看代碼:用起來相似於hashMap,第2個參數是默認值,就是若是沒有就返回默認值。

// Retrieve the saved values.   
boolean isTrue = mySharedPreferences.getBoolean(「isTrue」, false); 
float lastFloat = mySharedPreferences.getFloat(「lastFloat」, 0f); 
int wholeNumber = mySharedPreferences.getInt(「wholeNumber」, 1); 
long aNumber = mySharedPreferences.getLong(「aNumber」, 0); 
String stringPreference = mySharedPreferences.getString(「textEntryValue」, 「」);

 

再看:

Map<String, ?> allPreferences = mySharedPreferences.getAll(); //獲取所有
boolean containsLastFloat = mySharedPreferences.contains(「lastFloat」); //是否包含這個鍵

 

介紹Preference框架和Preference Activity

安卓提供一個基於XML驅動的框架,爲你的APP建立系統風格的Preferences Screens。經過使用這個框架你能夠建立Preferences Activities(此activity在原生APP或者第3方APP都保持風格一致)。

Preference框架包含4部分:

1.Preference Screen layout  Preference Screen的佈局文件。

2.Preference ActivityPreference Fragment  分別繼承與PreferenceActivity和PreferenceFragment, 被用來支持Preference Screen。在Android 3.0以前,Preference Activities直接支持Preference Screen,可是如今, PreferenceScreen<---PreferenceFragment<----Activity。

3.Preference Header Definition  3.0後引入

4.Shared Preference Change Listener  實現了onSharedPreferenceChangeListener的類,來監聽某個Shared Preferences的狀態改變。

 

用XML定義一個Preference Screen Layout

這種佈局是作爲xml資源,而不是layout資源,存放在res/xml下,程序中以R.xml.文件名.

首先須要一對<PreferenceScreen>標籤,

<?xml version=」1.0」 encoding=」utf-8」?> 
<PreferenceScreen 
   xmlns:android=」http://schemas.android.com/apk/res/android」> 
</PreferenceScreen>
 

PreferenceCategory 用來分類,以標題欄做爲分隔符,像個容器:

<PreferenceCategory
  android:title=」My Preference Category」/>

 

Preference的控制視圖至少包含:

1.android:key  這個與Shared Preference的key有關。

2.android:title 爲這個Preference顯示錶明性的標題。

3.android:summary  以略微小的字體,略長的字數,概述當前的preference。

4.android:defaultValue 默認值,若是未設置。

 

下面舉一個簡單的example,包含PreferenceCategory和CheckBox Preference

<?xml version=」1.0」 encoding=」utf-8」?> 
<PreferenceScreen 
  xmlns:android=」http://schemas.android.com/apk/res/android」> 
  <PreferenceCategory 
     android:title=」My Preference Category」> 
     <CheckBoxPreference 
       android:key=」PREF_CHECK_BOX」 
       android:title=」Check Box Preference」 
       android:summary=」Check Box Preference Description」 
       android:defaultValue=」true」 
     /> 
  </PreferenceCategory> 
</PreferenceScreen>

 

PreferenceCategory 更像一個分門別類的容器。

 

列舉安卓提供的preference控制視圖:

1.CheckBoxPreference

2.EditTextPreference

3.ListPreference

4.MultiSelectListPreference  Android 3.0(API level 11) 引入,與check box list相等效果。

5.RingtonePreference 當你想構建一個爲設置Notification的視圖,會頗有用。

具體不解釋,試試纔是真諦。

 

你還能夠自定義自個兒的preference控制視圖,經過繼承Preference類。更多細節,參考

http://developer.android.com/reference/android/preference/Preference.html

 

使用Intents向Preference Screens裏導入系統Preferences

除了剛纔那些,preference層級視圖中你還能夠加入其它APP的Preference Screen.

先看片斷:

<?xml version=」1.0」 encoding=」utf-8」?> 
<PreferenceScreen xmlns:android=」http://schemas.android.com/apk/res/android」 
         android:title=」Intent preference」 
         android:summary=」System preference imported using an intent」>

      <intent android:action=」android.settings.DISPLAY_SETTINGS 「/> 
</PreferenceScreen>

 

系統視此intent爲請求,會調用startActivity()。

android.provider.Settings 類包含一些android.settings.*常量,這些常量能夠被用來調用系統設置界面。

 

3.0前與如今的不一樣

以往是:先定義個xml Preference Screen佈局文件,而後再建立個類繼承PreferenceActivity,在onCreate中:

@Override 
public void onCreate(Bundle savedInstanceState) { 
   super.onCreate(savedInstanceState); 
   addPreferencesFromResource(R.xml.preference_layout);  
}

 

注意這是一種xml資源。

activity都是要註冊的。

 

3.0後步驟是:先建立個繼承於PreferenceFragment的類,在其onCreate中:

@Override 
public void onCreate(Bundle savedInstanceState) { 
    // TODO Auto-generated method stub 
    super.onCreate(savedInstanceState); 
    this.addPreferencesFromResource(R.xml.preference_layout); 
    
}

 

而後寫個xml preference-headers文件:

<?xml version="1.0" encoding="utf-8"?> 
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android" > 
    <header 
        android:fragment="com.example.test.PreFragment" 
        android:icon="@drawable/ic_launcher" 
        android:title="My Preferences" 
        android:summary="Description of these preferences"/> 
    
</preference-headers>

 

最後建立個繼承於PreferenceActivity的類,重寫方法onBuildHeaders:

@Override 
public void onBuildHeaders(List<Header> target) {

    super.onBuildHeaders(target); 
    this.loadHeadersFromResource(R.xml.pref_header, target); 
    
}

 

preference-header也是屬於xml資源。

總結:

3.0前,關係是  PreferenceScreen xml---PreferenceActivity

3.0後,關係是  PreferenceScreen xml-PreferenceFragmentpreference-header—PreferenceActivity

 

header還能夠引入Intents:

<header android:icon=」@drawable/ic_settings_display」 
            android:title=」Intent」 
            android:summary=」Launches an Intent.」> 
            <intent android:action=」android.settings.DISPLAY_SETTINGS 「/> 
</header>

 

這個header就沒有指定PreferenceFragment了.

 

向後兼容

爲你的程序預先建立2種版本:

Class c = Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB ? 
   MyPreferenceActivity.class : MyFragmentPreferenceActivity.class;

Intent i = new Intent(this, c); 
startActivityForResult(i, SHOW_PREFERENCES);

 

Build.VERSION.SDK_INT 意思是你當前項目編譯的版本,若是小於Build.VERSION_CODES.HONEYCOMB 3.0,那麼我就選擇MyPreferenceActivity.class,不然MyFragmentPreferenceActivity。

上述是一種兼容解決方案。

 

說了這麼多,如何使用由Preference Screens所設置的Shared Preferences呢?

答:

Context context = getApplicationContext(); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); // TODO Retrieve values using get<type> 

使用PreferenceManager.getDefaultSharedPreferences得到的SharedPreferences,是能夠被APP全部組件共享的。

 

介紹Shared Preference Change Listeners

既然是個監聽者,那就說說何時會觸發。

當Shared Preference值被增長,移除或者修改的時候觸發。

一般這會很是有用,給Activities和Services使用Shared Preferences框架去設置APP preferences,若是合適的話,以此來更新UI和APP的行爲。

 

什麼是App Preferences?

答:就是前面提到的PreferenceManager.getDefaultSharedPreferences方式得到的,具備全局意義的,能夠被app全部組件共享的。

下面看個實現的例子:

public class MyActivity extends Activity implements 
  OnSharedPreferenceChangeListener {

  @Override 
  public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState);

     // Register this OnSharedPreferenceChangeListener 
     SharedPreferences prefs = 
       PreferenceManager.getDefaultSharedPreferences(this); 
     prefs.registerOnSharedPreferenceChangeListener(this); 
  }

  public void onSharedPreferenceChanged(SharedPreferences prefs, 
                                              String key) { 
     // TODO Check the shared preference and key parameters 
     // and change UI or behavior as appropriate. 
  } 
}

 

總結:有3種SharedPreference

1.以PreferenceManager.getDefaultSharedPreferences,這種保存的能夠被App全部組件獲取

2.Activtiy.getSharedPreferences 這個方法,能夠指定一個名字,只要名字正確,也是能夠全局被獲取。

3.Activity.getPreferences()這個方法所保存的是針對於當前的activity,不是全局。

 

使用Shared Preferences保存Activity狀態

例子:

// Create or retrieve the activity preference object. 
SharedPreferences activityPreferences = 
getPreferences(Activity.MODE_PRIVATE);

// Retrieve an editor to modify the shared preferences. 
SharedPreferences.Editor editor = activityPreferences.edit();

// Retrieve the View 
TextView myTextView = (TextView)findViewById(R.id.myTextView);

// Store new primitive types in the shared preferences object. 
editor.putString(「currentTextValue」, myTextView.getText().toString());

// Commit changes. 
editor.apply();

 

使用Activity生命週期函數來保存和恢復Activity實例狀態

Activity提供onSaveInstanceState回調函數去保存與UI狀態相關的數據,主要情形呢:activity在後臺由於資源緊張被殺死,待資源恢復後,或者是硬件配置改變後致使的重啓,須要恢復以前的UI狀態。

private static final String TEXTVIEW_STATE_KEY = 「TEXTVIEW_STATE_KEY」;

@Override 
public void onSaveInstanceState(Bundle saveInstanceState) { 
   // Retrieve the View 
   TextView myTextView = (TextView)findViewById(R.id.myTextView);

   // Save its state 
   saveInstanceState.putString(TEXTVIEW_STATE_KEY, 
     myTextView.getText().toString());

   super.onSaveInstanceState(saveInstanceState); 
}

在super.onSaveInstanceState以前,保存你想要保存的UI狀態數據。

當Activity重啓的時候,saveInstanceState變量會傳給onCreateonRestoreInstanceState.

注意:正常的結束是不會產生saveInstanceState變量的。所謂正常,就是在前臺用戶選擇了退出。(如按返回鍵)致使了finish,觸發onDestory。

恢復的小DEMO:

@Override 
public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main);

     TextView myTextView = (TextView)findViewById(R.id.myTextView);

     String text = 「」; 
     if (savedInstanceState != null && 
          savedInstanceState.containsKey(TEXTVIEW_STATE_KEY)) 
       text = savedInstanceState.getString(TEXTVIEW_STATE_KEY);

     myTextView.setText(text); 
}

 

使用生命週期函數來保存和恢復 Fragment實例狀態

大多數APP的UI,都會內嵌在Fragments中。相應的,Fragments也包含了一個onSaveInstanceState回調函數,很像activity。

它所產生的Bundle對象,會傳遞給onCreate,onCreateView,onActivityCreated。

若是一個Activity由於硬件配置改變,實例被殺死而後重啓,好比屏幕翻轉等,你可讓你的fragment實例不作任何改變,經過在Fragment的onCreate中調用setRetainInstance便可,這樣的話相關的activity重啓,也無論它的事兒了,fragment的實例不會被殺死,就不會被從新建立。

注意:onCreate和onDestory那時候不會被觸發了,即使如此,onAttach,onCreateView,onActivityCreated,onStart,onResume和它們的一致的事件函數仍是會被調用。

(在onCreate方法中保存初始化,這樣就最大化的保存狀態了,效率比起之前沒有fragment仍是有好處的)

public class MyFragment extends Fragment {

            private static String USER_SELECTION = 「USER_SELECTION」; 
            private int userSelection = 0; 
            private TextView tv;

            @Override 
            public void onCreate(Bundle savedInstanceState) { 
              super.onCreate(savedInstanceState); 
              setRetainInstance(true); 
              if (savedInstanceState != null) 
                 userSelection = savedInstanceState.getInt(USER_SELECTION); 
            }

            @Override 
            public View onCreateView(LayoutInflater inflater, 
                                          ViewGroup container, 
                                          Bundle savedInstanceState) { 
              View v = inflater.inflate(R.layout.mainfragment, container, false);

              tv = (TextView)v.findViewById(R.id.text); 
              setSelection(userSelection);

              Button b1 = (Button)v.findViewById(R.id.button1); 
              Button b2 = (Button)v.findViewById(R.id.button2); 
              Button b3 = (Button)v.findViewById(R.id.button3);

              b1.setOnClickListener(new OnClickListener() { 
                 public void onClick(View arg0) { 
                   setSelection(1); 
                 }

           });

           b2.setOnClickListener(new OnClickListener() { 
              public void onClick(View arg0) { 
                setSelection(2); 
              } 
           });

           b3.setOnClickListener(new OnClickListener() { 
              public void onClick(View arg0) { 
                setSelection(3); 
              } 
           });

           return v; 
         }

         private void setSelection(int selection) { 
           userSelection = selection; 
           tv.setText(「Selected: 「 + selection); 
         }

         @Override 
         public void onSaveInstanceState(Bundle outState) { 
           outState.putInt(USER_SELECTION, userSelection); 
           super.onSaveInstanceState(outState); 
         }  
}
相關文章
相關標籤/搜索