android开发系列之数据存储
在我们的android实际开发过程,必不可少的一种行为操作对象就是数据。有些数据,对于用户而言是一次性的,这就要求我们每次进到App的时候,都需要去刷新数据。有些数据,对于用户而言又是具有一定时效性的,比如用户账号数据。这种情况下,就要求我们采用一定的数据保存措施,在这篇博客里面,我将为大家分享一些android里面常用的数据保存方法。
首先在android里面我们用的比较多的小数量存储方式可能就是SharedPreferences,那么什么是SharedPreferences呢?为了保存软件的设置参数,Android 平台为我们提供了一个SharedPreferences 类,它是一个轻量级的存储类,特别适合用于保存软件配置参数。使用SharedPreferences 保存数据,其背后是用xml文件存放数据,文件存放在/data/data/<package name>/shared_prefs 目录下。说白了,它实际上也是一种文件存储方式。下面让我们来看看它的具体用法:
public static void openSharep(Context context,String name){
SharedPreferences sharedPreferences=context.getSharedPreferences(name,Context.MODE_PRIVATE);
SharedPreferences.Editor editor=sharedPreferences.edit();
editor.putString("name","hello");
editor.commit();
}
上面是将一个字符串,通过键值对的方式存储到xml文件里面。这个时候,你也许会问:在什么情况下,会将SharedPreferences里面的数据删掉呢?当我们卸载app的时候,SharePreferences是否还在呢?当我的应用程序更新的时候,SharePreferences文件是否还在呢?我想这有可能跟你当前所使用android系统版本有关系,本人也没有细查这个问题,如有不对还请留言讨论。通过上面的代码你可能就能够发现,SharePreferences里面保存的数据还是相当有限的,主要是一些标识类的数据。
那么如果你需要在项目里面保存大量的数据,你会怎么办呢?其实常用的有两种方式:一种是文件存储;另外一种就是sqlite数据库;文件储存的方式,我们就不做过多的解释了,直接上代码,大家肯定就能够明白了。
String fileName = etFileName.getText().toString();
String fileContent = etFileContent.getText().toString();
FileOutputStream out = null;
try {
out = context.openFileOutput(fileName, Context.MODE_PRIVATE);
out.write(fileContent.getBytes("UTF-8"));
Toast.makeText(this,"保存成功",Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}finally {
try{
out.close();
}catch (Exception e){
e.printStackTrace();
}
}
上面的代码我们直接定义一个输出流就可以将我们希望保存的信息写入文件系统里面了。然后我们再来看看读取流的代码:
String fileName=etFileName.getText().toString();
FileInputStream in=null;
ByteArrayOutputStream bout=null;
byte[] buf=new byte[1024];
bout=new ByteArrayOutputStream();
int length=0;
try{
in=context.openFileInput(fileName);
while((length=in.read(buf))!=-1){
bout.write(buf,0,length);
}
byte[] content = bout.toByteArray();
tvInfo.setText(new String(content,"UTF-8")); //设置文本框为读取的内容
}catch (Exception e){
e.printStackTrace();
}
tvInfo.invalidate(); //刷新屏幕
try{
in.close();
bout.close();
}
catch(Exception e){}
通过上面的文件操作代码,我们可以很直观的发现文件系统无非就是一些中规中矩的文件读写操作了。接下来,我们将重点看看数据保存的最重要角色sqlite数据库。通过数据库保存下来的文件,我们都知道相对于普通的文件系统具有更好的结构性。就是说我们在操作数据的时候,可以更加有条理性的进行。
首先让我们来看看android里面应该怎样定义一个数据库操作对象呢?其实很简单,我们只需要定义一个类,然后让它继承SQLiteOpenHelper就可以了。请看测试类定义:
public class SqliteTest extends SQLiteOpenHelper {
public SqliteTest(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
通过上面的类定义我们可以看到,当我们实现一个构造方法、onCreate、onUpgrade方法之后,我们具有一个数据库操作的对象了。接下来让我们首先来完善一下上面SqliteTest类,提供完整的代码实现:
public class SqliteTest extends SQLiteOpenHelper {
private static final int VERSION = 1;
private static final String DB_NAME = "test.db";
public SqliteTest(Context context) {
super(context, DB_NAME, null, VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE IF NOT EXISTS person" +
"(_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age INTEGER, info TEXT)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("ALTER TABLE person ADD COLUMN other STRING");
}
}
然后当我们拿到这个数据库操作的对象之后,就应该考虑怎样使用这个对象了?比如我现在想要往这个数据库里面插入一些数据,请看下面的测试代码:
private SQLiteDatabase db;
private SqliteTest helper; private void getSqliteDb(){
db=helper.getWritableDatabase();
} private void addData(List<Person> persons){
db.beginTransaction(); //开始事务
try {
for (Person person : persons) {
db.execSQL("INSERT INTO person VALUES(null, ?, ?, ?)", new Object[]{person.name, person.age, person.info});
}
db.setTransactionSuccessful(); //设置事务成功完成
} finally {
db.endTransaction(); //结束事务
}
}
通过上面的代码我就可以实现数据的插入操作了。
在这篇博客的最后,让我们来看看SQLiteOpenHelper类的源码,探索一下为什么实现该类之后就能够进行数据库操作了呢?我们可以先来看看如下方法:
public SQLiteDatabase getWritableDatabase() {
synchronized (this) {
return getDatabaseLocked(true);
}
}
当我们调用getWriteableDatabase方法之后,程序会同步的调用getDatabaseLocked方法:
private SQLiteDatabase getDatabaseLocked(boolean writable) {
if (mDatabase != null) {
if (!mDatabase.isOpen()) {
// Darn! The user closed the database by calling mDatabase.close().
mDatabase = null;
} else if (!writable || !mDatabase.isReadOnly()) {
// The database is already open for business.
return mDatabase;
}
}
if (mIsInitializing) {
throw new IllegalStateException("getDatabase called recursively");
}
SQLiteDatabase db = mDatabase;
try {
mIsInitializing = true;
if (db != null) {
if (writable && db.isReadOnly()) {
db.reopenReadWrite();
}
} else if (mName == null) {
db = SQLiteDatabase.create(null);
} else {
try {
if (DEBUG_STRICT_READONLY && !writable) {
final String path = mContext.getDatabasePath(mName).getPath();
db = SQLiteDatabase.openDatabase(path, mFactory,
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
} else {
db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
mFactory, mErrorHandler);
}
} catch (SQLiteException ex) {
if (writable) {
throw ex;
}
Log.e(TAG, "Couldn't open " + mName
+ " for writing (will try read-only):", ex);
final String path = mContext.getDatabasePath(mName).getPath();
db = SQLiteDatabase.openDatabase(path, mFactory,
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
}
}
onConfigure(db);
final int version = db.getVersion();
if (version != mNewVersion) {
if (db.isReadOnly()) {
throw new SQLiteException("Can't upgrade read-only database from version " +
db.getVersion() + " to " + mNewVersion + ": " + mName);
}
db.beginTransaction();
try {
if (version == 0) {
onCreate(db);
} else {
if (version > mNewVersion) {
onDowngrade(db, version, mNewVersion);
} else {
onUpgrade(db, version, mNewVersion);
}
}
db.setVersion(mNewVersion);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
onOpen(db);
if (db.isReadOnly()) {
Log.w(TAG, "Opened " + mName + " in read-only mode");
}
mDatabase = db;
return db;
} finally {
mIsInitializing = false;
if (db != null && db != mDatabase) {
db.close();
}
}
}
调用这个方法之后系统就能够给我们提供一个SQLiteDatabase对象,然后我们就可以利用SQLiteDatabase利用的方法进行数据库操作了。
至于SQLiteDatabase层的源码,我自己还没有怎么研究过,如有什么不对的地方,欢迎拍砖!
android开发系列之数据存储的更多相关文章
- Android开发8:数据存储(二)——SQLite数据库和ContentProvider的使用
前言 啦啦啦各位小伙伴们许久不见了~学期末和过年期间自己忙着做其他事没能及时更新Android开发系列课程的博客,实在是罪过罪过~ 好啦~废话不多说,进入我们今天的主题.今天我们将和大家学习其他的数据 ...
- Android开发笔记之: 数据存储方式详解
无论是神马平台,神马开发环境,神马软件程序,数据都是核心.对于开发平台来讲,如果对数据的存储有良好的支持,那么对应用程序的开发将会有很大的促进作用.总体的来讲,数据存储方式有三种:一个是文件,一个是数 ...
- Android开发-API指南-数据存储
Storage Options 英文原文:http://developer.android.com/guide/topics/data/data-storage.html 采集日期:2015-02-0 ...
- Android开发手记(18) 数据存储三 SQLite存储数据
Android为数据存储提供了五种方式: 1.SharedPreferences 2.文件存储 3.SQLite数据库 4.ContentProvider 5.网络存储 SQLite 是以嵌入式为目的 ...
- Android开发手记(17) 数据存储二 文件存储数据
Android为数据存储提供了五种方式: 1.SharedPreferences 2.文件存储 3.SQLite数据库 4.ContentProvider 5.网络存储 本文主要介绍如何使用文件来存储 ...
- Android开发手记(20) 数据存储五 网络存储
Android为数据存储提供了五种方式: 1.SharedPreferences 2.文件存储 3.SQLite数据库 4.ContentProvider 5.网络存储 安卓的网络存储比较简单,因为A ...
- Android开发手记(19) 数据存储四 ContentProvider
转载自:http://www.cnblogs.com/devinzhang/archive/2012/01/20/2327863.html Android为数据存储提供了五种方式: 1.SharedP ...
- Android开发手记(16) 数据存储一 SharedPreferences
Android为数据存储提供了五种方式: 1.SharedPreferences 2.文件存储 3.SQLite数据库 4.ContentProvider 5.网络存储 SharedPreferenc ...
- Android 开发系列教程之(一)Android基础知识
什么是Android Android一词最早是出现在法国作家维里耶德利尔·亚当1986年发表的<未来夏娃>这部科幻小说中,作者利尔·亚当将外表像人类的机器起名为Android,这就是And ...
随机推荐
- css 文字垂直居中问题
CSS 文字垂直居中问题 问题:在 div 中文字居中问题: 当使用 line-height:100%%; 时,文字没有居中,如下: html: <div id="header_log ...
- 开发人员为组件添加自定义的className
在开发过程当中需要给组件写上自己的样式,这个时候怎么办呢? 直接给组件添加className这样是无效的 当给组件添加className之后 在写组件的时候需要对使用你的组件的开发人员提供自定义cla ...
- HDU2767 Proving Equivalences
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission( ...
- 【BZOJ4300】绝世好题(二进制,DP)
题意: n<=100000,ai<=2*10^9 思路:按二进制逐位考虑,只要有至少1位取and后为1就可以接下去 设dp[i]为第i位取and之后为1的最长的序列长度,意会一下 #inc ...
- Eclipse与MyEclipse增加主题
下载所需文件 下载地址:https://pan.baidu.com/s/1slq9lFn 如果eclipse和myeclipse里的MyEclipse 10\dropins存在features和plu ...
- 《Linux命令行与shell脚本编程大全 第3版》Linux命令行---13
以下为阅读<Linux命令行与shell脚本编程大全 第3版>的读书笔记,为了方便记录,特地与书的内容保持同步,特意做成一节一次随笔,特记录如下:
- VIM使用技巧2
假如有以下程序片段: var foo = 1 var bar = 'a' var foobar = foo + bar 如果我们想在每行行尾加上分号, (1)使用$移动光标到行尾, (2)执行a;&l ...
- hdu 4786(生成树)
Fibonacci Tree Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
- jquery 中的post和get方法同步问题
解决方法: 在需要同步的js代码前修改ajax的async属性. 有两种设置方法: 1: $.ajaxSettings.async = false; 2: $.ajaxSetup({ async : ...
- AC日记——青蛙的约会 poj 1061
青蛙的约会 POJ - 1061 思路: 扩展欧几里得: 设青蛙们要跳k步,我们可以得出式子 m*k+a≡n*k+b(mod l) 式子变形得到 m*k+a-n*k-b=t*l (m-n)*k-t ...