处女男学Android(十三)---Android 轻量级数据存储之SharedPreferences

来源:互联网 发布:ug编程吧 编辑:程序博客网 时间:2024/05/06 01:28



一、前言



转载请标明出处:http://blog.csdn.net/wlwlwlwl015/article/details/42437007

初学Android的时候在Activity之间传值我都是用Intent+Bundle这种模式去实现的,刚开始觉得没什么,后来渐渐发现了弊端,就是说只能逐层传递,当我的好几个Activity都需要从一个Activity中取数据的时候,这样就显得相当局限了,传来传去的即麻烦,又不合理,后来就想在Android中有没有web开发中类似于Session的东西,只要会话没有结束,那么在多个jsp页面之间就可以任意共享数据,这样就相当方便了,查阅了相关资料,发现SharedPreferences就是我要找的东西,通过本篇blog记录一下我学习它的过程,并彻底解决以后所有项目中遇到的轻量级数据存储问题。



二、创建SharedPreferences



首先看一下官方文档中对SharedPreferences的概述:


整体翻译一下,SharedPreferences提供了一个“允许我们去保存或者读取基本数据类型的键值对数据”的框架,你可以使用SharedPreferences去保存任意的基本数据类型的数据,例如:布尔类型、浮点型、整型、长整型以及字符串类型。在SharedPreferences中保存的数据可以"跨Seesion"保存(甚至你的application已经销毁)。


看了这段话我们大体上应该已经了解了SharedPreferences的作用了,我看完之后简单总结了以下三点:

1.SharedPreferences保存的数据格式是key-value的键值对格式,类似于Map集合。

2.SharedPreferences可保存的数据类型大体上都是基本数据类型

3.SharedPreferences中保存的数据不依赖上下文(猜也能猜出来肯定是保存在文件中了,这个后面再说)。


好了,接下来就该看看如何获取SharedPreferences对象,继续看文档,紧挨着上面一段:


显而易见,我们有2种选择,分别是通过getSharedPreferences()getPreferences()

简单看一下,第一种是可以创建多个参数文件,并通过name属性区分(name就是你指定的第一个参数),而第二种只能为当前Activity创建一个参数文件,并且不需要指定name,因为它只能作用于当前的Activity。很明显,我们需要用第一种,因为我们需要在多个Activity之间去共享数据。那么下面就具体看一下这个方法:

package com.wl.sharedpreferencesdemo;import com.example.sharedpreferencesdemo.R;import android.app.Activity;import android.content.Context;import android.content.SharedPreferences;import android.os.Bundle;public class MainActivity extends Activity {private Context context;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);context = this;SharedPreferences sharedPreferences = context.getSharedPreferences("currUserInfo", Context.MODE_PRIVATE);}}

第一个参数没问题,就是我们为SharedPreferences指定的name(上面下划线标出的文档翻译),而第二个参数是一个整型的mode,具体看一下官方的APIs中的解释:


蓝色线条标出的就是所有的MODE,所以说第二个参数我们可以选择这4种之中的任意一种,当然具体还是看需求了,下面分别解释一下官方给出的这4种MODE的适用场合。

1.MODE_PRIVATE 

Use 0 or MODE_PRIVATE for the default operation,翻译一下,使用0或者MODE_PRIVATE作为默认的操作。那就是说一般情况下我们设置这个MODE就可以了,其实这个MODE指定了该SharedPreferences数据只能被本应用程序读、写,大多数情况下我们的需求应该就是这样。

2.MODE_WORLD_READABLE

指定该SharedPreferences数据能被其它应用程序读,但不能写。在有些情况下这个权限是相当有用的,比如当一个应用需要从另一个应用中获取数据时。

3.MODE_WORLD_WRITEABLE

这个模式就是在上面的模式中追加了“可写”的权限,没有特殊需求应该不会用到这个模式。

4.MODE_MULTI_PROCESS

这个模式允许在多进程间改变相同的SharedPreferences文件,它通常用在Android 2.3及其以下的版本,所以这里就不做介绍了。

OK,了解了实例化SharedPreferences对象的方法以及参数的意思,那么就可以根据需求去实例化SharedPreferences对象了。顺带一提,getSharedPreferences()方法是以单例模式去得到对象的。



三、写入&读取数据



既然SharedPreferences是数据存储的对象,那么实例化对象之后首先应当做的就是写入数据了,至于怎么写,继续看文档,不用跳行,接着我上面贴出的那段To get...打头的往下看:


清晰明了的三个步骤:

1.调用edit()方法去得到Editor对象。

2.通过Editor对象的putXxx方法存值。

3.调用Editor对象的commit()方法提交保存。

首先我们要明确一点,就是写入数据是通过Editor对象实现的,而Editor对象正是SharePreferences对象提供的,感觉没什么再需要说的了,下面就写一小段示例代码:

package com.wl.sharedpreferencesdemo;import android.app.Activity;import android.content.Context;import android.content.Intent;import android.content.SharedPreferences;import android.content.SharedPreferences.Editor;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.EditText;public class MainActivity extends Activity {private EditText etUsername;private EditText etPassword;private Button btnToOtherActy;private Context context;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);context = this;etUsername = (EditText) findViewById(R.id.et_username);etPassword = (EditText) findViewById(R.id.et_password);btnToOtherActy = (Button) findViewById(R.id.btn_to_other_acty);btnToOtherActy.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 得到SharedPreferences对象SharedPreferences perferences = context.getSharedPreferences("userInfo", Context.MODE_PRIVATE);// 获取EditText输入的内容String username = etUsername.getText().toString();String password = etPassword.getText().toString();// 得到Editor对象Editor editor = perferences.edit();// 存值editor.putString("username", username);editor.putString("password", password);// 提交保存editor.commit();startActivity(new Intent(MainActivity.this,SecondActivity.class));}});}}
界面很简单,只放了2个EditText和1个Button,就不贴代码了,Activity做的事情也很简单,就是得到输入的值并保存到SharedPreferences中,可以看到最后一行跳转到了另一个Activity,其实这里我只是想在另一个Activity中去取值显示,有存必有取,从而验证是否存下了,是否能取到。顺带就贴上SecondActivity的代码看看如何取值:

package com.wl.sharedpreferencesdemo;import android.app.Activity;import android.content.Context;import android.content.SharedPreferences;import android.os.Bundle;import android.widget.TextView;public class SecondActivity extends Activity {private TextView tvUsername;private TextView tvPassword;private Context context;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.second);context = this;tvUsername = (TextView) findViewById(R.id.tv_username);tvPassword = (TextView) findViewById(R.id.tv_password);SharedPreferences preferences = context.getSharedPreferences("userInfo", Context.MODE_PRIVATE);String username = preferences.getString("username", "");String password = preferences.getString("password", "");tvUsername.setText(username);tvPassword.setText(password);}}

很简单,直接通过SharedPreferences的getXxx方法即可根据key去获取相应的value了。现在运行一下程序,看看是否能正常取值显示:



BINGO,看上去工作的很好,我们通过SharedPreferences成功实现了两个Activity之间的传值。



四、SharedPreferences的存储位置



之前也提到过了SharedPreferences实际是将数据存在了文件中,那么文件是什么格式,文件存在哪里呢?这些问题也是我们必须弄清楚的。程序运行之后,我们在eclipse中进入DDMS视图,切换过去之后选择“File Explorer”面板,第一次进入可能要稍等片刻,文件列表加载需要少量时间,之后我们就能看见这样的文件结构:


需要注意的路径我已经标出来了,因为SharedPreferences的数据总是保存在

/data/data/<package name>/shared_prefs

这个路径下,进入到这个路径后我们可以发现这样一个文件:


没错,其实就是在这个xml文件中保存了SharedPreferences的key-value键值对,而getSharedPreferences()方法的第一个参数正是这个xml文件的文件名。最后点击右上角的“Pull a file from the device”将这个xml文件pull到电脑上,并打开看一下:


果真是通过xml文件,以key-value格式去存的数据,这也就和我们前面提到的种种猜测相吻合了。

最后需要注意一点,如果在File Explorer的根目录下的data文件夹下没有发现任何文件,或者可以点开,但看不到任何文件,那么一般应该是手机没有ROOT权限的原因,建议通过虚拟机调试即可。



五、SharedPreferences结合自定义Application的应用



在实际的项目中我们基本会结合自定义application去操作sharedpreferences,尽管sharedpreferences并不依赖上下文,但这样做还是有一定的好处和方便的,我个人认为有以下两点好处:

1.简化了数据读取的步骤。

2.提升了数据读取的性能。

比如在带有登录功能的APP中,我们一般都会在登录成功之后把用户信息存在SharedPreferences里面,下次再进入应用的时候就不必登录了。结合这个实例,我依次分析一下上面我提到的两点。


第一,简化了数据读取的步骤。

如果我们不使用application,那么在Activity中凡是需要读取数据,都要先通过当前Activity的上下文对象去获取到SharedPreferences对象,然后再通过preferences.getXxx去取值。如果我们在自定义application中定义一个用于封装用户信息的对象,在application的onCreat()方法中操作SharedPreferences读取数据并赋值给这个对象,那么在整个应用的运行过程中只需要得到application对象再取值就OK了,节省了获取SharedPreferences对象的这一行代码。


第二,提升了数据读取的性能。

如果按上面的方式去做,那么在程序运行的过程中只需要访问一次SharedPreferences,以后再取数据就可以直接从内存中的application取,而如果不用application的话,那么每次都要通过SharedPreferences访问xml文件获取数据,一个是从内存中读,一个是从文件中读,哪个快一些很明显了吧。


以上两点是我个人通过实际应用分析出来的结论,毕竟我还是新手,有些问题考虑的不一定对,不一定准确,如果有错误的地方还恳请各位批评指正。


最后就贴一段application结合sharedpreferences使用的代码。

MyApplication:

package com.wl.sess;import com.wl.sess.model.MyConstants;import com.wl.sess.model.UserEntity;import android.app.Application;import android.content.Context;import android.content.SharedPreferences;public class MyApplication extends Application {private UserEntity userEntity = new UserEntity();public UserEntity getUserEntity() {return userEntity;}public void setUserEntity(UserEntity userEntity) {this.userEntity = userEntity;}@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.onCreate();SharedPreferences sp = getSharedPreferences(MyConstants.SP_USERINFO,Context.MODE_PRIVATE);userEntity.setUserid(sp.getLong(MyConstants.SP_USERINFO_ID, -1));userEntity.setUsername(sp.getString(MyConstants.SP_USERINFO_USERNAME,""));userEntity.setUserpassword(sp.getString(MyConstants.SP_USERINFO_PWD, ""));userEntity.setUsertel(sp.getString(MyConstants.SP_USERINFO_TEL, ""));userEntity.setSessionid(sp.getString(MyConstants.SP_USERINFO_SESSIONID,""));}}

可以看到,每次程应用启动的时候首先会从SharedPreferences中去读取数据,这样的话如果有数据,那么在其它Activity需要使用数据的时候就很方便了,直接通过application.getUserEntity.getXxx取取值就行了。一般对SharedPreferences的写入和删除都会简单封装一下,我是这样封装的:

/** * 存储用户登录信息 *  * @param mApp * @param sp * @param userEnt */public static void saveLoginUserinfo(MyApplication mApp,SharedPreferences sp, UserEntity userEnt) {Editor sped = sp.edit();sped.putLong(MyConstants.SP_USERINFO_ID, userEnt.getUserid());sped.putString(MyConstants.SP_USERINFO_USERNAME, userEnt.getUsername());sped.putString(MyConstants.SP_USERINFO_PWD, userEnt.getUserpassword());sped.putString(MyConstants.SP_USERINFO_TEL, userEnt.getUsertel());sped.putString(MyConstants.SP_USERINFO_SESSIONID,userEnt.getSessionid());sped.commit();mApp.setUserEntity(userEnt);}/** * 清除用户登录信息 *  * @param mApp */public static void clearUserLoginInfo(MyApplication mApp) {SharedPreferences sp = mApp.getSharedPreferences(MyConstants.SP_USERINFO, Context.MODE_PRIVATE);Editor sped = sp.edit();sped.remove(MyConstants.SP_USERINFO_ID);sped.remove(MyConstants.SP_USERINFO_USERNAME);sped.remove(MyConstants.SP_USERINFO_PWD);sped.remove(MyConstants.SP_USERINFO_TEL);sped.remove(MyConstants.SP_USERINFO_SESSIONID);sped.commit();}

可以看到,写入数据之后,内存中的数据也应该保持一致。好了,到这里关于SharedPreferences的介绍就暂时告于段落,目前的使用都很简单,后续如果有更深层次的应用和理解的话会继续更新本篇blog。



六、总结



之前一直想学一下这个但总是没时间,因为SharedPreferences太常用了,比如Activity之间的数据共享和传递,或者是轻量级数据的持久化等等,第一次学有些地方可能说的不好或者不标准,欢迎各路大神批评指正,因为只有不断的改正错误才能提高,也希望自己早日脱离Android菜鸟阶段,这个点也该洗洗睡了,明天开始可能要好好总结一下hibernate优化相关的技术,有时间的话也会以blog的形式分享出来,今天就到这里,还要继续努力,加油,Raito!



3 0