当前位置: 代码迷 >> Android >> 处女男学Android(十三)-Android 轻量级数据存储之SharedPreferences
  详细解决方案

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

热度:11   发布时间:2016-04-28 02:54:26.0
处女男学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!



2楼lmj623565791昨天 10:11
添个异步写的方式呗~毕竟是io~毕竟在UI线程~
Re: wlwlwlwl015昨天 10:20
回复lmj623565791n好的大神。。那我就把写Share的操作封成一个AsynTask。。以后用的时候都异步操作
1楼ws_love_raito昨天 22:19
0 0
  相关解决方案