Android学习进入第三周,由UI(用户界面)开始转入操作层。
今天,学习的是SharedPreferences与SQLite数据库。下面,就来具体了解一下,这两个Android平台上的两个存储数据的类和库。
SharedPreferences是Android平台上一个轻量级的存储类,主要是保存一些常用的配置比如窗口状态,一般在Activity中 重载窗口状态onSaveInstanceState保存一般使用SharedPreferences完成.
在Android系统中,一般的应用程序都会提供“设置”或者“首选项”的这样的界面,这些设置最后就可以通过Preferences来保存,而这些信息是以XML文件的形式保存在/data/data/PACKAGE_NAME /shared_prefs 目录下的。
SharedPreferences spf =getSharedPreferences("soft",
Context.MODE_WORLD_READABLE);
这里,可以调用Activity提供的方法,这两个方法的两个参数,分别为文件名、创建模式。
文件名:在Android 中已经确定了 SharedPreferences 是以 xm l形式保存,所以,在填写文件名参数时,不要给定 ”.xml ” 后缀,android 会自动添加。
创建模式:有四种,分别是——
Context.MODE_PRIVATE
Context. MODE_APPENDMODE_APPEND
Context.MODE_WORLD_READABLE
Context.MODE_WORLD_WRITEABLE
下面来结合实例来了解一下SharedPreferences的用法,具体实现保存与读取的操作:
首先,在string.xml文件中第一用到的文本字段:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">SharedPreferencesTest</string>
<string name="name_text">姓名</string>
<string name="age_text">年龄</string>
<string name="save_text">保存</string>
<string name="read_text">读取</string>
</resources>
其次,创建布局文件main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<TextView
android:layout_width="50dp"
android:layout_height="wrap_content"
android:text="@string/name_text" />
<EditText
android:id="@+id/nameEt"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<TextView
android:layout_width="50dp"
android:layout_height="wrap_content"
android:text="@string/age_text" />
<EditText
android:id="@+id/ageEt"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<TableLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:stretchColumns="*" >
<TableRow >
<Button
android:id="@+id/saveBtn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="@string/save_text" />
<Button
android:id="@+id/readBtn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="@string/read_text" />
</TableRow>
</TableLayout>
</LinearLayout>
最后在创建实现操作的SharedPreferences.java文件:
package cn.class3g.activity;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class SharedPreferencesTestActivity extends Activity implements
OnClickListener {
Button saveBtn, readBtn;
EditText nameEt, ageEt;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViews();
}
private void findViews() {
nameEt = (EditText) this.findViewById(R.id.nameEt);
ageEt = (EditText) this.findViewById(R.id.ageEt);
saveBtn = (Button) this.findViewById(R.id.saveBtn);
readBtn = (Button) this.findViewById(R.id.readBtn);
saveBtn.setOnClickListener(this);
readBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
String name = "无名氏";
int age = -1;
SharedPreferences shared = this.getSharedPreferences("info",
Context.MODE_WORLD_READABLE );//这个模式,是所有应用都可调用这个shared
switch (v.getId()) {
case R.id.saveBtn:
name = nameEt.getText().toString().trim();
age = Integer.valueOf(ageEt.getText().toString().trim());
Editor editor = shared.edit();
editor.putString("name", name);
editor.putInt("age", age);
// 保证操作的事务完整性
editor.commit();
break;
case R.id.readBtn:
name = shared.getString("name", "无名氏");
age = shared.getInt("age", -1);
Toast.makeText(this, "name="+name+ " age="+age, Toast.LENGTH_LONG).show();
break;
}
}
}
启动模拟机:
Ok,成功实现。
那么,如何在其它应用中实现这个储存的数据呢?
接下来我们创建一个新的应用来调用这个SharedPreferences,这里需要注意的是SharedPreferences的第二个参数也就是创建模式应该选择Context.MODE_WORLD_READABLE。
同样的首先创建布局文件main.xml这里,只须创建一个Button即可。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/readOther"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="读取其它工程的SharedPreferences文件" />
</LinearLayout>
然后实现操作的ReadOtherSharedPreferences.java文件:
package cn.class3g.readother;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class ReadOtherSharedPreferencesActivity extends Activity implements
OnClickListener {
Button readBtn;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViews();
}
private void findViews() {
readBtn = (Button) this.findViewById(R.id.readOther);
readBtn.setOnClickListener(this);
}
public void onClick(View v) {
if (v.getId() == R.id.readOther) {
try {
Context otherContext = this.createPackageContext(
"cn.class3g.activity", Context.CONTEXT_IGNORE_SECURITY);
SharedPreferences shared = otherContext.getSharedPreferences(
"info", MODE_PRIVATE);
String res = "name=" + shared.getString("name", "wms")+
" age="+ String.valueOf(shared.getInt("age", -1));
Toast.makeText(this, res, Toast.LENGTH_LONG).show();
} catch (NameNotFoundException e) {
e.printStackTrace();
}
}
}
}
启动虚拟机:
Ok。成功实现!
接下来,来了解SQLite数据库。
SQLite是一个开源的嵌入式关系数据库,它可以减少应用程序管理数据的开销, SQLite 可移植性好 、 很容易使用 、 很小 、 高效而且可靠 。
SQLite的五大特点:
1. 零配置
SQlite3 不用安装、不用配置、不用启动、关闭或者配置数据库实例。当系统崩溃后不用做任何恢复操作,在下次使用数据库的时候自动恢复。
2. 可移植
它是运行在Windows 、 Linux 、 BSD 、 Mac OS X 和一些商用 Unix 系统 , 比如 Sun 的 Solaris 、IBM 的 AIX ,同样,它也可以工作在许多嵌入式操作系统下,比如 Android 、 QNX 、VxWorks 、 PalmOS 、 Symbin 和 Windows CE 。
3. 紧凑
SQLite 是被设计成轻量级、自包含的。一个头文件、一个 lib 库,你就可以使用关系数据库了,不用任何启动任何系统进程。
4. 简单
SQLite 有着简单易用的 API 接口。
5. 可靠
SQLite 的源码达到 100% 分支测试覆盖率。
下面使用SQLiteOpenHelper抽象类建立数据库。
为了实现对数据库版本进行管理,SQLiteOpenHelper类提供了两个重要方法,分别为:onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabasedb,int oldVersion, intnewVersion)用于初次使用软件时生成数据库表,后者用于升级软件时更新数据库表结构。
Public SQLiteOpenHelper(Context context,String name,SQLiteDatabase.CursorFactory factory, int version)
Context:代表应用上下文。
Name : 代表数据库的名称。
Factory: 代表记录集游标工厂 , 是专门用来生成记录集游标, 记录集游标是对查询结果进行迭代的,后面我们会继续介绍。
Version :代表数据库的版本,如果以后升级软件的时候,需要更改 Version 版本号,那么onUpgrade(SQLiteDatabase db,int oldVersion, int newVersion) 方法会被调用,在这个方法中比较适合实现软件更新时修改数据库表结构的工作。
下面,通过建立数据库类DatabaseHelper,实现增删改查来了解SQList数据库。
首先,建立数据库类DatabaseHelper:
package cn.class3g.service;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class DatabaseHelper extends SQLiteOpenHelper {
static String dbName= "mydb.db";
static int dbVersion = 2;
public DatabaseHelper(Context context) {
super(context, dbName, null, dbVersion);
}
//只在初次使用数据库的时候会被自动调用一次
public void onCreate(SQLiteDatabase db) {
Log.i("TAG","onCrete被调用了");
String sql = "create table person(personid integer primary key autoincrement," +
"name varchar(20), age integer)";
db.execSQL(sql);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i("TAG","onUpgrade被调用了");
String sql = "alter table person add phone char(20) null";
db.execSQL(sql);
}
}
然后编写测试类TestDbHelper进行测试。
package cn.class3g.dbtest;
import cn.class3g.service.DatabaseHelper;
import android.test.AndroidTestCase;
public class TestDbHelper extends AndroidTestCase {
public void testDb() throws Throwable{
DatabaseHelper dbHelper = new DatabaseHelper(this.getContext());
dbHelper.getReadableDatabase();
}
}
Ok,接下来,来实现CRUD(即增删改查)
首先,创建业务类PersonService.java:
package cn.class3g.service;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import cn.class3g.domain.Person;
public class PersonService {
private DatabaseHelper dbHelper;
public PersonService(Context context){
dbHelper = new DatabaseHelper(context);
}
public void add(Person person){
SQLiteDatabase db = dbHelper.getReadableDatabase();
String sql = "insert into person(name, age, phone) values(?,?,?)";
db.execSQL(sql,new Object[]{person.getName(), person.getAge(), person.getPhone()});
}
public void delete(int id){
SQLiteDatabase db = dbHelper.getReadableDatabase();
String sql = "delete from person where personid=?";
db.execSQL(sql,new Object[]{id});
}
public void update(Person person, int id){
SQLiteDatabase db = dbHelper.getReadableDatabase();
String sql = "update person set name=?, age=?, phone=? where personid=?";
db.execSQL(sql,new Object[]{person.getName(),person.getAge(),person.getPhone(), id});
}
public Person find(int id){
SQLiteDatabase db = dbHelper.getReadableDatabase();
String sql = "select * from person where personid=?";
Cursor cursor = db.rawQuery(sql, new String[]{String.valueOf(id) });
if(cursor.moveToNext()){
Person person = new Person();
person.setPersionid(cursor.getInt(0));
person.setName(cursor.getString(cursor.getColumnIndex("name")));
person.setAge(cursor.getInt(2));
person.setPhone(cursor.getString(3));
return person;
}
return null;
}
public int getRecordsCount(){
SQLiteDatabase db = dbHelper.getReadableDatabase();
String sql = "select count(*) from person";
Cursor cursor = db.rawQuery(sql, null);
cursor.moveToFirst();
int count = cursor.getInt(0);
cursor.close();
return count;
}
//跳过前面的start条记录,读取其后count记录
public List<Person> getScrollData(int start, int count){
SQLiteDatabase db = dbHelper.getReadableDatabase();
String sql = "select * from person limit ?,?";
Cursor cursor = db.rawQuery(sql,
new String[] { String.valueOf(start),
String.valueOf(count) });
List<Person> list = new ArrayList<Person>();
while(cursor.moveToNext()){
Person p = new Person();
p.setPersionid(cursor.getInt(0));
p.setName(cursor.getString(1));
p.setAge(cursor.getInt(2));
list.add(p);
}
cursor.close();
return list;
}
}
然后,创建测试类PersonServiceTest.java进行检测:
package cn.class3g.dbtest;
import java.util.List;
import cn.class3g.domain.Person;
import cn.class3g.service.PersonService;
import android.test.AndroidTestCase;
import android.util.Log;
public class PersonServiceTest extends AndroidTestCase {
public void testAdd() throws Throwable{
PersonService service = new PersonService(this.getContext());
Person person = new Person("Mary",19,"119");
service.add(person);
}
public void testUpdate() throws Throwable{
PersonService ps = new PersonService(this.getContext());
Person person = new Person("Ton", 122,"120");
ps.update(person, 2);//需要实现查看数据库中Ton的id值
}
public void testFind() throws Throwable{
PersonService service = new PersonService(this.getContext());
Person p = service.find(1);
if(p != null){
Log.i("TAG",p.toString());
}
}
public void testDelete() throws Throwable{
PersonService ps = new PersonService(this.getContext());
ps.delete(2);
}
public void testScroll() throws Throwable{
PersonService service = new PersonService(this.getContext());
List<Person> personList = service.getScrollData(3, 2);
Log.i("TAG",personList.toString());
}
public void testCount() throws Throwable{
PersonService service = new PersonService(this.getContext());
long count = service.getRecordsCount();
Log.i("TAG", String.valueOf(count));
}
}