保存简单的APP数据
1.Shared Preferences
是一个简单,轻量级的,以键值对的机制(name/value pair---NVP)存储一些基础数据(Boolean,string,float等),最常用在保存用户的APP参数。
2.保存APP~UI状态
当APP被移到后台,Activity和Fragment都包含用来帮助记录当前UI状态的生命周期事件回调函数。
3.Files
文件不是完美的选择,但是有时候读写文件是唯一的选择。安卓可以让你在外部或者内部媒介上创建文件,也提供支持在公有访问的文件夹下创建临时缓存文件和存储文件。
创建和保存Shared Preferences
去创建或者修改Shared Prefence,通过调用getSharedPreferences.
SharedPreferences mySharedPreferences = getSharedPreferences(MY_PREFS,Activity.MODE_PRIVATE);
如何去修改呢?
答:使用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 Activity 和 Preference 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-PreferenceFragment—preference-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变量会传给onCreate和onRestoreInstanceState.
注意:正常的结束是不会产生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);
}
}
来源:oschina
链接:https://my.oschina.net/u/923173/blog/105376