1.Shared Preferences
是一个简单,轻量级的,以键值对的机制(name/value pair---NVP)存储一些基础数据(Boolean,string,float等),最常用在保存用户的APP参数。
2.保存APP~UI状态
当APP被移到后台,Activity和Fragment都包含用来帮助记录当前UI状态的生命周期事件回调函数。
3.Files
文件不是完美的选择,但是有时候读写文件是唯一的选择。安卓可以让你在外部或者内部媒介上创建文件,也提供支持在公有访问的文件夹下创建临时缓存文件和存储文件。
去创建或者修改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,反之亦然。
直接看代码:用起来类似于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”); //是否包含这个键
安卓提供一个基于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资源,而不是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 更像一个分门别类的容器。
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
除了刚才那些,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.*常量,这些常量可以被用来调用系统设置界面。
以往是:先定义个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 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。
上述是一种兼容解决方案。
答:
Context context = getApplicationContext(); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); // TODO Retrieve values using get<type>
使用PreferenceManager.getDefaultSharedPreferences获得的SharedPreferences,是可以被APP所有组件共享的。
既然是个监听者,那就说说什么时候会触发。
当Shared Preference值被增加,移除或者修改的时候触发。
通常这会非常有用,给Activities和Services使用Shared Preferences框架去设置APP preferences,如果合适的话,以此来更新UI和APP的行为。
答:就是前面提到的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. } }
1.以PreferenceManager.getDefaultSharedPreferences,这种保存的可以被App所有组件获取
2.Activtiy.getSharedPreferences 这个方法,可以指定一个名字,只要名字正确,也是可以全局被获取。
3.Activity.getPreferences()这个方法所保存的是针对于当前的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提供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); }
当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); }
大多数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); } }