Android开发 - 文件保存状态和首选项

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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开发 - 文件保存状态和首选项的主要内容,如果未能解决你的问题,请参考以下文章

显示默认打印机的属性和首选项

Android导航组件:如何保存片段状态

5. 保存数据

保存游戏状态 Android

Android:通过保存 Activity 状态进行测试的捷径

Android:为什么在创建选项卡时会调用onTabSelected?