处女男学Android(十三)---Android 轻量级数据存储之SharedPreferences
一、前言
转载请标明出处: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; @Override protected 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; @Override protected 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() { @Override public 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; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.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; } @Override public void onCreate() { // TODO Auto-generated method stub super.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!
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。