Android中有5种数据存储方式,分别为文件存储、SQLite数据库、SharedPreferences、ContentProvider、网络。每种存储方式的特点如下:
- File文件存储/SD卡:与Java中实现I/O的程序是完全一样的,提供openFileInput()和openFileOutput()方法来读取设备上的文件。
- SharedPreferences存储:一种轻型的数据存储方式,常用来存储一些简单的配置信息,本质是基于XML文件存储key-value键值对数据。
- SQLite数据库存储:一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,在存储大量复杂的关系型数据的时可以使用。
- ContentProvider:四大组件之一,用于数据的存储和共享,不仅可以让不同应用程序之间进行数据共享,还可以选择只对哪一部分数据进行共享,可保证程序中的隐私数据不会有泄漏风险。
1、File文件存储/SD卡
文件存储方式是一种较常用的方法,在Android中读取/写入文件的方法,与Java中实现I/O的程序是完全一样的,提供openFileInput()和openFileOutput()方法来读取设备上的文件。
将数据存储到文件中:
String data = "data to save";
FileOutputStream out = openFileOutput("文件名", 覆盖:MODE_PRIVATE 追加:MODE_APPEND);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
writer.write(data);
writer.close();
从文件中读取数据:
FileInputStream in = openFileInput("文件名");
BufferedReader reader = new BufferedReader(new InputStreamReader());
StringBuffer content = new StringBuffer();
String line = "";
while ((line.reader.readLine()) != null) {
content.append(line);
}
reader.close();
return content.toString();
将数据存储到手机内存中
private void saveTosdcard() {
String str = "data to save";
//文件输出流
FileOutputStream fos = null;
//设置文件路径 ,第一个参数是文件保存的路径,null放在根目录下,第二个参数是文件名
File file = new File(getExternalFilesDir(null), "/data666.txt");
try {
//传入参数第一是file,第二可以传boolean表示是否追加
fos = new FileOutputStream(file,true);
fos.write(str.getBytes());
Toast.makeText(MainActivity.this, "保存到SD卡成功!", Toast.LENGTH_SHORT).show();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
// 关闭输入流
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- getExternalFilesDir(null):路径在/storage/sdcard0/Android/data/包名/files/文件名
- Environment.getExternalStorageDirectory():路径在/storage/sdcard0/文件名
删除getExternalFilesDir路径文件
private void deleteSocket() {
try {
// 找到文件所在的路径并删除该文件
File file = new File(getExternalFilesDir(null), "/dataSocketHiMate.txt");
if (file.exists()) {
file.delete();
} else {
Toast.makeText(MainActivity.this, "没有文件可以删除", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
2、SharedPreferences
SharePreferences是一种轻型的数据存储方式,常用来存储一些简单的配置信息,如int、string、boolean、float和long。它的本质是基于XML文件存储key-value键值对数据。
- 保存位置: data/data/程序包名/share_prefs/
- 主要用途:
- 保存应用的设置 例如:设置静音,下次进入还是静音
- 判断是否是第一次登陆
- 保存登录用户名密码等情形
将数据存储到SharedPreferences
- 步骤1. 调用 getSharedPreferences() 方法获得 SharedPreferences 对象,提供两个参数,指定文件名和操作模式。MODE_PRIVATE只有当前程序才能读写。
- 步骤2. 调用 SharedPreferences 对象的 edit() 方法来获取 SharedPreferences.Editor 对象。
- 步骤3. 调用Edit接口的形如put某某某()方法以键值对形式保存某某某类型的数据。
- 步骤4. 调用Edit接口的commit()方法提交键值对。
SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();
editor.putString("name", "Tom");
editor.putInt("age", 28);
editor.putBoolean("married", false);
editor.remove("married");
editor.commit();
从SharedPreferences中读取数据
SharedPreferences pref = getSharedPreferences("data",MODE_PRIVATE);
String name = pref.getString("name","默认值");
int age = pref.getInt("age",0);
boolean married = pref.getBoolean("married",false);
3、SQLite数据库
SQLite是一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,在存储大量复杂的关系型数据的时可以使用,比前面学过的只适用于存储简单数据的两种存储方式要好很多。
创建数据库
自定义帮助类并继承SQLiteOpenHelper,并重写两个方法:onCreate()和 onUpgrade(),分别在这两个方法中去实现创建、升级数据库的逻辑。还需要一个构造方法,这里用含有四个参数的构造方法就可以
public class MyDatabaseHelper extends SQLiteOpenHelper {
private Context mContext;
public static final String CREATE_BOOK = "create table Book(" +
"id integer primary key autoincrement," +
"author text," +
"price readl," +
"price integer," +
"name text)";
public MyDatabaseHelper(Context context, String name,
SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
}
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//升级数据库的话先修改版本号
//drop删除表,delete是删除数据
db.execSQL("drop table if exists Book");
onCreate(db);
}
}
数据库进行增删改查的操作
public class Main2Activity extends AppCompatActivity {
private MyDatabaseHelper dbHepler;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dbHepler = new MyDatabaseHelper(this, "BookStore.db", null, 1);
//都是打开和创建,区别在于空间满的情况w是出现异常,R是只读
//dbHepler.getWritableDatabase();
dbHepler.getReadableDatabase();
SQLiteDatabase db = dbHepler.getWritableDatabase();
//添加
ContentValues values = new ContentValues();
values.put("name", "tom");
values.put("pages", 464);
values.put("price", 14.23);
db.insert("Book", null, values);
values.clear();
//更新
ContentValues values = new ContentValues();
values.put("name", "HHH");
db.update("Book", values, "price>?", new String[]{"10"});
//删除
db.delete("Book", "price>?", new String[]{"10"});
//查询
Cursor c = db.query("Book",null,null,null,null,null,null);
String s = c.getString(c.getColumnIndex("name"));
c.close();
}
}
sqlite数据导出到csv、txt
String sql = "select * from location";
Cursor cursor = db.rawQuery(sql, null);
//如果要其他格式的话,只需修改文件后缀名即可
ExportToCSV(cursor, "test666.csv");
核心代码块ExportToCSV()
private void ExportToCSV(Cursor c, String fileName) {
int rowCount = 0;
int colCount = 0;
FileWriter fw;
BufferedWriter bfw;
//获取SD卡路径
File sdCardDir = Environment.getExternalStorageDirectory();
File saveFile = new File(sdCardDir, fileName);
try {
rowCount = c.getCount();
colCount = c.getColumnCount();
fw = new FileWriter(saveFile);
bfw = new BufferedWriter(fw);
if (rowCount > 0) {
c.moveToFirst();
// 写入表头
for (int i = 0; i < colCount; i++) {
if (i != colCount - 1)
bfw.write(c.getColumnName(i) + ',');
else
bfw.write(c.getColumnName(i));
}
// 写好表头后换行
bfw.newLine();
// 写入数据
for (int i = 0; i < rowCount; i++) {
c.moveToPosition(i);
Log.d(TAG, "正在导出第" + (i + 1) + "条");
for (int j = 0; j < colCount; j++) {
if (j != colCount - 1) {
bfw.write(c.getString(j) + ',');
} else
bfw.write(c.getString(j));
}
// 写好每条记录后换行
bfw.newLine();
}
}
// 将缓存数据写入文件
bfw.flush();
Log.d(TAG, "ExportToCSV: " + bfw.toString());
// 释放缓存
bfw.close();
Log.d(TAG, "导出完毕!");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
c.close();
}
}
4、ContentProvider
并不能用户存储数据。主要用于不同应用程序之间共享数据,只是为我们存储以及添加数据制定统一的接口而已。
5、网络存储数据
通过网络上提供的存储空间来上传(存储)或下载(获取)我们存储在网络空间中的数据信息
6、共享数据的方式
1.File, 2.Sqlite,3.Content Provider,4.Service,5.Broadcast Receiver,6.Intent
7、了解SQLite中的事务处理吗?是如何做的?
使用SQLiteDatabase的beginTransaction()方法可以开启一个事务,程序执行到endTransaction() 方法时会检查事务的标志是否为成功,如果程序执行到endTransaction()之前调用了setTransactionSuccessful() 方法设置事务的标志为成功则提交事务,如果没有调用setTransactionSuccessful() 方法则回滚事务。多用于大量数据操作时,能明显减少耗时。
SQLiteDatabase db = dbHepler.getWritableDatabase();
db.beginTransaction();//开始事务
try{
db.execSQL(...);
db.execSQL(...);
//调用此方法会在执行到endTransaction() 时提交当前事务,如果不调用此方法会回滚事务
db.setTransactionSuccessful();
} finally{
//由事务的标志决定是提交事务,还是回滚事务
db.endTransaction();
}
db.close();
8、事务的属性
- 原子性(Atomicity):确保工作单位内的所有操作都成功完成,否则,事务会在出现故障时终止,之前的操作也会回滚到以前的状态。
- 一致性(Consistency):确保数据库在成功提交的事务上正确地改变状态。
- 隔离性(Isolation):使事务操作相互独立和透明。
- 持久性(Durability):确保已提交事务的结果或效果在系统发生故障的情况下仍然存在。
9、使用SQLite做批量操作有什么好的方法吗?
即使用事务处理进行优化,默认SQLite的数据库插入操作,如果没有采用事务的话,它每次写入提交,就会触发一次事务操作,而这样几千条的数据,就会触发几千个事务的操作,这就是时间耗费的根源
10、如果现在要删除SQLite中表的一个字段如何做?
SQLite数据库只允许增加表字段而不允许修改和删除表字段,只能采取复制表思想,即创建一个新表保留原表想要的字段、再将原表删除。
11、使用SQLite时会有哪些优化操作?
- 使用事务做批量操作:具体操作见上。
- 及时关闭Cursor,避免内存泄漏。
- 耗时操作异步化:数据库的操作属于本地IO,通常比较耗时,建议将这些耗时操作放入异步线程中处理。
- ContentValues的容量调整:ContentValues内部采用HashMap来存储Key-Value数据,ContentValues初始容量为8,扩容时翻倍。因此建议对ContentValues填入的内容进行估量,设置合理的初始化容量,减少不必要的内部扩容操作
- 使用索引加快检索速度:对于查询操作量级较大、业务对要求查询要求较高的推荐使用索引
12、Android 中有哪几种解析xml的类,官方推荐哪种?以及它们的原理和区别。
Android 提供了三种解析XML的方式:SAX(Simple API XML) ,DOM(Document Object Model), Pull解析
- Dom解析:将XML文件的所有内容读取到内存中(内存的消耗比较大),然后允许您使用DOM API遍历XML树、检索所需的数据。
- Sax解析:Sax是一个解析速度快并且占用内存少的xml解析器,Sax解析XML文件采用的是事件驱动,它并不需要解析完整个文档,而是按内容顺序解析文档的过程。
- Pull解析:Pull解析器的运行方式与 Sax 解析器相似。它提供了类似的事件,可以使用一个switch对感兴趣的事件进行处理。
本文参考资料:
- 《Android开发艺术探索》
- 《第一行代码》
- https://www.jianshu.com/p/718aa3c1a70b