Android开发 - 文件、保存状态和首选项
关键字:Shared Preference,Preference Activity,Preference Fragement,Preference Header
一个Activity至少应当在进入不活动状态前保存它的用户界面(UI)状态。
Activity生命周期

创建并保存Shared Preference
Shared Preference是一种简单的、轻量级的名称/值对(NVP)机制,用于保存原始应用程序数据。
使用SharedPreference类可以创建名称/值对的命名映射,它们可以在会话之间持久化,并在同一个应用程序沙箱中运行的应用程序组件之间共享(但是对其他应用程序不可用)。
为了创建或者修改一个Shared Preference,可以调用应用程序上下文的getSharedPreferences,并传入要修改的Shared Preference的名称。
String MY_PREFS="myPrefs";
SharedPreferences mySharedPreferences=this.getSharedPreferences(MY_PREFS, Activity.MODE_PRIVATE);

使用 SharedPreferences.Editor 类来修改SharedPreferences对象上的信息。
SharedPreferences.Editor myEditor= mySharedPreferences.edit();
myEditor.putString("Key1","Value1");
myEditor.apply();
通过调用SharedPreferences.Editor对象的apply或者commit方法来异步或同步地保存修改。
检索Shared Preference
通过get获取指定Key值的已保存值。如果还没有保存值,就用第二个参数作为默认值。
mySharedPreferences.getString("Key1","");
通过getAll方法,返回所有可用的Shared Preference键值的映射。通过调用contains方法,检查指定的键是否存在。
Map<String, ?> allreferences= mySharedPreferences.getAll();
allreferences.containsKey("Kye3");
示例:
首先增加一个名为preferences.xml的视图,该试图用来显示配置控件。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@+id/auto_update_prompt"/>
<CheckBox
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/checkBox_auto_update" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/update_freq_prompt"
android:id="@+id/textView"
android:layout_gravity="center_horizontal" />
<Spinner
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/spinner_update_freq" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/min_quake_mag_prompt" />
<Spinner
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/spinner_quake_mag" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@android:string/ok"
android:id="@+id/okButton" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@android:string/cancel"
android:id="@+id/cancelButton" />
</LinearLayout>
</LinearLayout>
同时增加一个名为PreferencesActivity的Activity派生类,该类于视图对应,该类用来填充设置视图,获取视图控件值以及保存设置的配置。
package com.example.guqiang.earthquake;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.Spinner;
/**
* Created by GuQiang on 2016/10/1.
*/
public class PreferencesActivity extends Activity {
CheckBox autoUpdate;
Spinner updateFreqSpinner;
Spinner magnitudeSpinner;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.preferences);
//当前上下文中获取SharedPreferences对象实例
Context context=getApplicationContext();
prefs= PreferenceManager.getDefaultSharedPreferences(context);
//获取配置用控件
updateFreqSpinner=(Spinner)this.findViewById(R.id.spinner_update_freq);
magnitudeSpinner=(Spinner)this.findViewById(R.id.spinner_quake_mag);
autoUpdate=(CheckBox)this.findViewById(R.id.checkBox_auto_update);
//填充下拉列表数据
populateSpinners();
//从SharedPreferences对象中取出配置数据填充UI控件
updateUIFromPreferences();
Button okButton=(Button)this.findViewById(R.id.okButton);
okButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
//保存配置
savePreferences();
//设置返回值
setResult(RESULT_OK);
finish();
}
});
Button cancelButton=(Button)this.findViewById(R.id.cancelButton);
cancelButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
//设置返回值
setResult(RESULT_CANCELED);
finish();
}
});
}
/**
* 保存配置
*/
private void savePreferences() {
int updateIndex=updateFreqSpinner.getSelectedItemPosition();
int minMagIndex=magnitudeSpinner.getSelectedItemPosition();
boolean autoUpdateChecked=autoUpdate.isChecked();
//开启SharedPreferences编辑,并且对指定Key值赋值
SharedPreferences.Editor editor=prefs.edit();
editor.putBoolean(PREF_AUTO_UDPATE,autoUpdateChecked);
editor.putInt(PREF_MIN_INDEX,updateIndex);
editor.putInt(PREF_UPDATE_FREQ_INDEX,minMagIndex);
//同步提交
editor.commit();
}
/**
* 从Shared Preference中读取数据或使用初始数据给控件赋值
*/
private void updateUIFromPreferences() {
boolean autoUpChecked=prefs.getBoolean(PREF_AUTO_UDPATE,false);
int updateFreqIndex=prefs.getInt(PREF_UPDATE_FREQ_INDEX,2);
int minMagIndex=prefs.getInt(PREF_MIN_INDEX,0);
updateFreqSpinner.setSelection(updateFreqIndex);
magnitudeSpinner.setSelection(minMagIndex);
autoUpdate.setChecked(autoUpChecked);
}
static final String USER_PREFERENCE="USER_PREFERENCE";
static final String PREF_AUTO_UDPATE="PREF_AUTO_UPDATE";
static final String PREF_MIN_INDEX="PREF_MIN_INDEX";
static final String PREF_UPDATE_FREQ_INDEX="PREF_UPDATE_FREQ_INDEX";
SharedPreferences prefs;
/**
* 填充Spinner控件
*/
private void populateSpinners() {
//填充更新频率
ArrayAdapter<CharSequence> fAdapter=ArrayAdapter.createFromResource(this,R.array.update_freq_options,android.R.layout.simple_spinner_item);
int spinner_dd_item=android.R.layout.simple_spinner_dropdown_item;
fAdapter.setDropDownViewResource(spinner_dd_item);
updateFreqSpinner.setAdapter(fAdapter);
//填充最小震级微调框
ArrayAdapter<CharSequence> mAdapter=ArrayAdapter.createFromResource(this,R.array.magnitude_options,android.R.layout.simple_spinner_item);
mAdapter.setDropDownViewResource(spinner_dd_item);
magnitudeSpinner.setAdapter(mAdapter);
}
}
Mainfest.xml文件中增加这个Activity的配置

最后在主视图MainActivity中,重写onCreateOptionsMenu、onOptionsItemSelected、onActivityResult,分别对应是创建Options菜单项、菜单项选择动作、其他Activity返回结果后操作。
如果想在Activity中得到新打开Activity 关闭后返回的数据,需要使用系统提供的startActivityForResult(Intent intent, int requestCode)方法打开新的Activity。
新的Activity 关闭后会向前面的Activity传回数据,为了得到传回的数据,必须在前面的Activity中重写onActivityResult(int requestCode, int resultCode, Intent data)方法。
static final int MENU_PREFERENCES= Menu.FIRST+1;
static final int MENU_UPDATE=Menu.FIRST+2;
/**
* 增加菜单
* @param menu
* @return
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0,MENU_PREFERENCES,Menu.NONE,R.string.menu_preferences);
return true;
}
static final int SHOW_PREFERENCES=1;
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()){
case(MENU_PREFERENCES):
Intent i=new Intent(this,PreferencesActivity.class);
startActivityForResult(i,SHOW_PREFERENCES);
return true;
}
return false;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==SHOW_PREFERENCES){
if(resultCode== Activity.RESULT_OK){
updateFromPreferences();
FragmentManager fm=getFragmentManager();
final EarthquakeListFragment earthquakeList=(EarthquakeListFragment)fm.findFragmentById(R.id.EarthquakeListFragment);
Thread t=new Thread(new Runnable() {
@Override
public void run() {
earthquakeList.refreshEarthquakes();
}
});
t.start();
}
}
}
上面代码在onActivityResult中,如果从配置Activity中是正常保存返回的,那么就又会开启一个线程来根据新的设置值刷新数据。
为了保证App下次打开时可以自动读取保存的值对自身进行设置,还需要在onCreate方法中写入读取配置项的方法。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
updateFromPreferences();
}
首选框架和Preference Activity概述
Android提供了一个XML驱动的框架,用于为应用程序创建系统样式的Preference Screen。通过使用该框架,能够确保应用程序中的Preference Activity与本地或其他第三方应用程序中所使用的一致。
- Preference Screen布局。一个XML文件,定义了在Preference Screen中显示的层次结构。它指定了要显示的文本及相关控件、所允许的值和为每个控件使用的Shared Preference键。
- Preference Activity和Preference Fragement。分别是PreferenceActivity和PreferenceFragement的扩展,用于包含Preference Screen。Preference Screent->Preference Fragement->Preference Activity。
- Preference Header定义。一个XML文件,定义了应用程序的Preference Fragement,以及用与现实Preference Fragement的层次结构。
- Shared Preference变化监听程序。一个onSharedPreferenceChangeListener类的实现,用户监听Shared Prefernece的变化。
在XML中定义一个Prefernece Screen布局
与标准的UI布局不同,PreferneceScreen定义存储在res/xml资源文件夹中。
<?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>
也可以使用Intent在Preference Screen中导入系统首选项
下面的XML代码段添加了一个到系统显示设置的链接
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<intent android:action="android.settings.DISPLAY_SETTINGS"/>
</PreferenceScreen>
Preference Fragement
public class myPreference extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.mypreference);
}
}
Preference Header
Preference Header是一些XML资源,存储在res/xml文件夹中。描述了Preference Fragement在Preference Activity中如何分组和显示。
<?xml version="1.0" encoding="utf-8"?>
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
<header android:fragment="com.example.guqiang.earthquake.preferences.myPreference"
android:icon="@drawable/preference_icon"
android:title="Description of these preferneces">
</header>
</preference-headers>
示例:为前面创建的地震查看器创建一个标准的Preference Activity
(1)根据Android框架创建标准的PreferenceScreen
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:key="PREF_AUTO_UPDATE"
android:title="Auto refresh"
android:summary="Select to turn on automatci updating"
android:defaultValue="true"/>
<ListPreference
android:key="PREF_UPDATE_FREQ"
android:title="Refresh frequency"
android:summary="Frequency at shich to refresh earthquake list"
android:entryValues="@array/update_freq_values"
android:dialogTitle="Refresh frequency"
android:defaultValue="60"/>
<ListPreference
android:key="PREF_MIN_MAG"
android:title="Minimum magnitude"
android:summary="Select the minimum magnitude earthquake to report"
android:entries="@array/magnitude_options"
android:entryValues="@array/magnitude"
android:dialogTitle="Magnitude"
android:defaultValue="3"/>
</PreferenceScreen>
(2)将这个PreferenceScreen加入PreferenceHader中
<?xml version="1.0" encoding="utf-8"?>
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
<header android:fragment="com.example.guqiang.earthquake.UserPreferenceFragment"
android:title="Settings"
android:summary="Earthquake Refresh Settings"/>
</preference-headers>
(3)创建一个扩展了PreferenceFragment的新类。重写onCreate方法。用来于UI绑定
public class UserPreferenceFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.userpreference);
}
}
(4)创建一个PreferenceActivity的派生类,重写OnBuilHeaders方法,从UI中加载指定的Header
@Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.preference_headers,target);
}
(5)修改MainActivity中的菜单点击事件,呼叫FragmentPreferences的实例
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()){
case(MENU_PREFERENCES):
Intent i=new Intent(this,FragementPreferences.class);
startActivityForResult(i,SHOW_PREFERENCES);
return true;
}
return false;
}

关键字:Shared Preference,Preference Activity,Preference Fragement,Preference Header
浙公网安备 33010602011771号