首页 > 代码库 > Android开发 - 文件、保存状态和首选项
Android开发 - 文件、保存状态和首选项
一个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; }
Android开发 - 文件、保存状态和首选项