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