Persisting Data to the Device

Overview

The Android framework offers several options and strategies for persistence:

  • Shared Preferences - Easily save basic data as key-value pairs in a private persisted dictionary.
  • Local Files - Save arbitrary files to internal or external device storage.
  • SQLite Database - Persist data in tables within an application specific database.
  • ORM - Describe and persist model objects using a higher level query/update syntax.

Use Cases

Each storage option has typical associated use cases as follows:

  • Shared Preferences - Used for app preferences, keys and session information.
  • Local Files - Often used for blob data or data file caches (i.e disk image cache)
  • SQLite Database - Used for complex local data manipulation or for raw speed
  • ORM - Used to store simple relational data locally to reduce SQL boilerplate

Note that a typical app utilizes all of these storage options in different ways.

Shared Preferences

Settings can be persisted for your application by using SharedPreferences to persist key-value pairs.

To retrieve an existing username key from your Shared Preferences, you can type:

SharedPreferences pref =
PreferenceManager.getDefaultSharedPreferences(this);
String username = pref.getString("username", "n/a");

SharedPreferences can be edited by getting access to the Editor instance:

SharedPreferences pref =
PreferenceManager.getDefaultSharedPreferences(this);
Editor edit = pref.edit();
edit.putString("username", "billy");
edit.putString("user_id", "65");
edit.commit();

Local Files

Android can read/write files to internal as well as external storage. Applications have access to an application-specific directory where preferences and sqlite databases are also stored. Every Activity has helpers to get the writeable directory. File I/O API is a subset of the normal Java File API.

Writing files is as simple as getting the stream using openFileOutput method] and writing to it using a BufferedWriter:

// Use Activity method to create a file in the writeable directory
FileOutputStream fos = openFileOutput("filename", MODE_WORLD_WRITEABLE);
// Create buffered writer
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos));
writer.write("Hi, I'm writing stuff");
writer.close();

Reading the file back is then just using a BufferedReader and then building the text into a StringBuffer:

BufferedReader input = null;
input = new BufferedReader(
new InputStreamReader(openFileInput("myfile")));
String line;
StringBuffer buffer = new StringBuffer();
while ((line = input.readLine()) != null) {
buffer.append(line + "\n");
}
String text = buffer.toString();

You can also inspect and transfer files to emulators or devices using the DDMS File Explorer perspective which allows you to access to filesystem on the device.

SQLite

For maximum control, developers can use SQLite directly by leveraging the SQLiteOpenHelper for executing SQL requests and managing a local database:

public class TodoItemDatabase extends SQLiteOpenHelper {
public TodoItemDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
} // These is where we need to write create table statements.
// This is called when database is created.
@Override
public void onCreate(SQLiteDatabase db) {
// SQL for creating the tables
} // This method is called when database is upgraded like
// modifying the table structure,
// adding constraints to database, etc
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion,
int newVersion) {
// SQL for upgrading the tables
}
}

Check out our managing databases with SQLiteOpenHelper guide for a more detailed look at working with SQLite. In many cases, rather than interacting with SQL directly, Android apps can leverage one of the many available higher-level ORMs (object relational mappers) to persist Java models to a database table as shown below. If needed, we can also access the SQLite database for debugging.

There are a handful of interesting SQLiteOpenHelper wrappers which reduce the level of code written including the following libraries:

  • Cupboard - Original take on SQL wrapper
  • SQLBrite - Square's take on a SQL wrapper
  • StorIO - Popular new take on a light SQL wrapper

Each of these provide a thin layer of abstraction on SQLiteOpenHelper. For a more comprehensive abstraction, we can use mapping engines that automatically create model objects based on SQL data as outlined below.

Object Relational Mappers

Instead of accessing the SQLite database directly, there is no shortage of higher-level wrappers for managing SQL persistence. There are many popular ORMs for Android, but one of the easiest to use is ActiveAndroid (cliffnotes). Here's a few alternatives as well:

  • DBFlow - Newer, light syntax, fast (cliffnotes)
  • SugarORM - Very easy syntax, uses reflection to infer data (cliffnotes)
  • Siminov - Another viable alternative syntax
  • greenDAO - Slightly different take (DAO vs ORM)
  • ORMLite - Lightweight and speed is prioritized
  • JDXA - Simple, non-intrusive, flexible

For this class, we selected ActiveAndroid. With ActiveAndroid, building models that are SQLite backed is easy and explicit using annotations. Instead of manually creating and updating tables and managing SQL queries, simply annotate your model classes to associate fields with database columns:

@Table(name = "Users")
public class User extends Model {
@Column(name = "Name")
public String name; @Column(name = "Age")
public int age; // Make sure to define this constructor (with no arguments)
// If you don't querying will fail to return results!
public User() {
super();
} // Be sure to call super() on additional constructors as well
public User(String name, int age){
super();
this.name = name;
this.age = age;
}
}

Inserting or updating objects no longer requires manually constructing SQL statements, just use the model class as an ORM:

User user = new User();
user.name = "Jack";
user.age = 25;
user.save();
// or delete easily too
user.delete();

ActiveAndroid queries map to SQL queries and are built by chaining methods.

List<User> users = new Select()
.from(User.class).where("age > ?", 25)
.limit(25).offset(0)
.orderBy("age ASC").execute();

This will automatically query the database and return the results as a List for use. For more information, check out ourActiveAndroid Guide for links to more resources and answers to common questions. As needed, we can also access the SQLite database for debugging.

References

// Use Activity method to create a file in the writeable directory
FileOutputStream fos = openFileOutput("filename", MODE_WORLD_WRITEABLE);
// Create buffered writer
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos));
writer.write("Hi, I'm writing stuff");
writer.close();

Persisting Data to the Device的更多相关文章

  1. [Node.js] Level 7. Persisting Data

    Simple Redis Commands Let's start practicing using the redis key-value store from our node applicati ...

  2. SPRING IN ACTION 第4版笔记-第十一章Persisting data with object-relational mapping-006Spring-Data的运行规则(@EnableJpaRepositories、<jpa:repositories>)

    一.JpaRepository 1.要使Spring自动生成实现类的步骤 (1)配置文件xml <?xml version="1.0" encoding="UTF- ...

  3. SPRING IN ACTION 第4版笔记-第十一章Persisting data with object-relational mapping-005Spring-Data-JPA例子的代码

    一.结构 二.Repository层 1. package spittr.db; import java.util.List; import org.springframework.data.jpa. ...

  4. SPRING IN ACTION 第4版笔记-第十一章Persisting data with object-relational mapping-002设置JPA的EntityManagerFactory(<persistence-unit>、<jee:jndi-lookup>)

    一.EntityManagerFactory的种类 1.The JPA specification defines two kinds of entity managers:  Applicatio ...

  5. SPRING IN ACTION 第4版笔记-第十一章Persisting data with object-relational mapping-004JPA例子的代码

    一.结构 二.Repository层 1. package spittr.db; import java.util.List; import spittr.domain.Spitter; /** * ...

  6. SPRING IN ACTION 第4版笔记-第十一章Persisting data with object-relational mapping-003编写JPA-based repository( @PersistenceUnit、 @PersistenceContext、PersistenceAnnotationBeanPostProcessor)

    一.注入EntityManagerFactory的方式 package com.habuma.spittr.persistence; import java.util.List; import jav ...

  7. SPRING IN ACTION 第4版笔记-第十一章Persisting data with object-relational mapping-001-使用Hibernate(@Inject、@EnableTransactionManagement、@Repository、PersistenceExceptionTranslationPostProcessor)

    一.结构 二.Repository层 1. package spittr.db; import java.util.List; import spittr.domain.Spitter; /** * ...

  8. Persisting iOS Application Data in SQLite Database Using FMDB

    In previous articles we have utilized NSUserDefaults and .NET web services to persist iPhone data. N ...

  9. 部署samba服务之后,在客户端用挂载访问的方式,错误信息:mount: block device //192.168.1.108/mysqldata is write-protected, mounting read-only mount: cannot mount block device //192.168.1.108/mysqldata read-only

    部署samba服务之后,在客户端用挂载访问的方式,错误信息:mount: block device //192.168.1.108/mysqldata is write-protected, moun ...

随机推荐

  1. CSS中display对布局的影响以及元素display的默认值

    比如div元素,它的默认display属性值为“block”,成为“块级”元素(block-level):而span元素的默认display属性值为“inline”,称为“行内”元素.

  2. ul标签中,li标签的移除、属性值获取

  3. P2866 糟糕的一天

    糟糕的一天 洛谷链接 挺水的一道题,也就是看每个数后面有多少数比它小,最后把总数加起来. 我们可以用单调栈来实现,并用一个数组来保存每个数现在的状态. 代码: #include<cstdio&g ...

  4. HDU1757-A Simple Math Problem,矩阵快速幂,构造矩阵水过

    A Simple Math Problem 一个矩阵快速幂水题,关键在于如何构造矩阵.做过一些很裸的矩阵快速幂,比如斐波那契的变形,这个题就类似那种构造.比赛的时候手残把矩阵相乘的一个j写成了i,调试 ...

  5. MyBatis使用Mapper动态代理开发Dao层

    开发规范 Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同原始Dao接口实现类方法. Mappe ...

  6. POJ3528移石头

    题目大意: 河道两旁直线上有两块石头不能移动,距离为L,但中间放置了N块石头并列出这N块石头到起点的距离,可以移走M块,那么移走石头后每次牛跨石头的最小距离如何达到最大值,输出这个最大值 让最小距离的 ...

  7. 【BZOJ1211】树的计数(Prufer编码)

    题意:一个有n个结点的树,设它的结点分别为v1, v2, …, vn, 已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵. 其中1<=n<=150,输入数据保证满足条件的 ...

  8. .net core webapi jwt 更为清爽的认证 ,续期很简单(2)

    .net core webapi jwt 更为清爽的认证  后续:续期以及设置Token过期 续期: 续期的操作是在中间件中进行的,续期本身包括了前一个Token的过期加发放新的Token,所以在说续 ...

  9. C. The Two Routes---cf602C(Dij)

    http://codeforces.com/problemset/problem/602/C 题目大意:  有n个城市 有m条铁路  如果两个城市没有铁路  那么一定有公路 求从1 到 n 用铁路和公 ...

  10. 转 常见hash算法的原理

    散列表,它是基于快速存取的角度设计的,也是一种典型的“空间换时间”的做法.顾名思义,该数据结构可以理解为一个线性表,但是其中的元素不是紧密排列的,而是可能存在空隙. 散列表(Hash table,也叫 ...