1. 数据持久化技术简介
- 什么是瞬时数据?
瞬时数据指的是那些存储在内存当中的数据,这些数据由于内存被回收或者程序被意外终止之后又可能丢失.
2.数据持久化技术的引入的必要性:
有一些关键性重要的数据,我们不希望由于内存的回收而丢失,这个时候就需要数据持久化技术.
数据持久化技术就是讲那些内存中的瞬时数据保存到存储设备中,保证即使在电脑或手机关机的情况下,
这些数据依然不会丢失.保存内存中的数据时处于瞬时状态的,而保存在存储设备中的数据是处于持久化状态的,持久化
技术提供了一种机制可以让数据在瞬时状态和持久化状态之间进行转换.
2.Android中的数据持久化技术
2.1 android中的三种简单的方式实现数据持久化技术的功能:
1> 文件存储
2> SharedPreferences 偏好设置
3> SQLite 数据库存储
当然除了这三种方式之外,你也可以讲数据存储到手机的sd卡当中,只不过使用文件,SharedPreferences或数据库来保存数据会
相对简单一些,而且比起将数据保存到sd卡中会更加的安全.
3. Android持久化技术之 文件存储
3.1 文件存储的特点:
它不对存储的内容进行任何的格式化处理,所有的数据都是原封不动地保存到文件当中的,因而它比较适合存储
一些简单的文本数据或二进制数据.如果你想要使用文件存储的方式保存一些较为复杂的文本数据,就需要定义
一套自己的格式规范,这样方便之后将数据从文件中重新解析出来.
3.2 将数据存储到文件当中
Context类提供了一个方法
openFileOutput(String name, int mode);
返回一个FileOutputStream ,第一个参数是文件名,在文件创建的时候使用的就是这个名称,这里的文件名不可以包含路径.
因为所有的文件都是默认存储到/data/data//files/ 目录下的.第二个参数是文件的操作模式,主要有两种
模式可以选择: MODE_PRIVATE和MODE_APPEND.其中MODE_PRIVATE是默认的操作模式,表示当指定的文件名称一样的时候
所写入的内容会覆盖掉原文件中的内容,而MODE_APPEND表示如果该文件已经存在就在文件的末尾追加,如果文件不存在就
重新创建.
openFileOutput()方法返回的是一个FileOutputStream 对象,拿到之后就可以使用javaIO流的操作方法对其进行操作了.
下面是一个例子,用于保存从一个输入框中获取数据.保存到文件当中.
首先是布局文件一个EditText,用于用户输入内容,一个Button,用于用户点击之后保存到文件当中.
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.my09_filepersistence.MainActivity"
tools:ignore="HardcodedText" >
<EditText
android:id="@+id/et_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:hint="请输入要保存的内容"
android:layout_marginTop="18dp"
>
</EditText>
<Button
android:id="@+id/btn_keep"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/et_content"
android:layout_marginTop="58dp"
android:onClick="doClick"
android:text="保存到文件当中" />
</RelativeLayout>
然后在MainActivity.java当中通过处理点击事件而保存用户输入的内容.
MainActivity.java
package com.example.my09_filepersistence;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
public class MainActivity extends Activity
{
private EditText etInput;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etInput = (EditText) findViewById(R.id.et_content);
}
public void doClick(View view)
{
switch(view.getId())
{
case R.id.btn_keep:
String text = etInput.getText().toString();
FileOutputStream fos = null;
BufferedWriter writer = null;
try
{
fos = openFileOutput("data", MODE_PRIVATE);
writer = new BufferedWriter(new OutputStreamWriter(fos));
writer.write(text);
} catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
if(writer != null)
{
writer.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
}
break;
}
}
}
这样当我们点击保存的时候,就会在项目目录下发现一个data文件,打开之后就可以看到我们保存的内容.
3.3 从文件中读取数据
类似于将数据存储到文件当中,Context类中还提供了一个openFileInput(String name)方法,
该方法只接收一个参数,即要读取的文件名,然后系统会自动到/data/data//files/ 目录下去加载
这个文件,并返回一个FileInputStream对象,得到这个对象之后再通过Java流的方式就可以讲数据读取出来了.
下面是一个完整的Demo,把输入框中数据保存到文件当中,还有就是从文件当中读取数据显示到TextView当中.
package com.dream.fioman.fioman_filesave;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class MainActivity extends Activity {
private EditText etInput;
private TextView tvShowContent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etInput = (EditText) findViewById(R.id.editText);
tvShowContent = (TextView) findViewById(R.id.textView);
}
public void doClick(View view) {
switch (view.getId()) {
case R.id.button1: //将输入的内容保存到文件当中
String input = etInput.getText().toString();
FileOutputStream fos = null;
try {
//1.先获取文件输出流
fos = openFileOutput("input", MODE_PRIVATE);
//2.将文件输出流转换为缓存字符输出流(高级流)
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos));
//3.写入到文件当中
writer.write(input);
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
break;
case R.id.button2: //从文件中读取数据内容
//1.先获取文件输入流
FileInputStream fis = null;
try {
fis = openFileInput("input");
//2.将文件输入流转换为缓存字符输入流(高级流)
BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
//3.从文件中读取内容到内存中,由于内容比较少,我就不写循环读取了
String content = reader.readLine();
//4.显示内容
tvShowContent.setText(content);
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
}
4. 数据持久化存储技术之 SharedPreferences
sharedPreferences存储的特点,位置固定,sharedPreferences存储文件的地方都是在data/data/项目包名路径/shared-prefs/目录下. sharedPreferences是使用键值队的方式来存储数据的.也就是当保存一条数据的时候,需要给这条数据提供一个对应的键值,这样在读取的时候就可以根据对应的键值取到相应的数据.sharedPreferences支持多种不同的数据类型进行存储.存储的文件
一般是xml文件.使用sharedPreferences进行文件存储的步骤:
1> 首先是获取sharedPreferences对象.
有三种方式:
Context类中的getSharedPreferences(String fileName, int mode);
第一个参数值保存的sharedPreferences文件的名称,如果指定的文件不存在,则会创建一个.它们都是存放在data/data/项目package名称/shared-prefs/目录下的. 第二个参数用于指定操作模式,主要有两种模式可以选择,MODE_PRIVATE和
MODE_MUTI_PROCESS.第一个是默认的操作模式,和直接传入0的效果是一样的,表示只有当前的应用程序才可以对这个sharedPreferences文件进行操作,第二种MODE_MUTI_PROCESS一般是用于多个应用进程中对同一个sharedPreferences
文件进行操作的情况.
Activity类中的getPreferences(int Mode);
值接收一个操作模式参数,文件名称默认将当前活动的类名作为文件名称.
PreferencesManager类中的getDefaultPreferences(Context context);
它接收一个Context类型的参数,并自动使用当前应用程序的包名作为前缀来命名sharedPreferences文件.
2.获取到sharedPreferences对象之后,就可以向sharedPreferences文件存储数据了,主要可以分为三步来实现:
1> 调用sharedPreferences 对象的edit()方法,获取editor对象.
2> editor.putxxx(“String”,要保存的值) 存入数据到文件中.
3>editor.commit();
3.获取数据的时候直接调用sharedPreferences对象的getxxx(String key);方法即可.
下面是一个Demo:
/**
* 向SharedPreferences文件中写入内容
*/
private void keepToShared() {
SharedPreferences ref = getSharedPreferences("input", MODE_PRIVATE);
SharedPreferences.Editor editor = ref.edit();
editor.putInt("id", 9527);
editor.putString("name", "FioMan");
editor.putInt("age", 28);
editor.putString("gender", "男");
editor.commit();
}
/**
* 从SharedPreferences中读取内容,并显示到TextView上面
*/
private void readFromShared() {
SharedPreferences ref = getSharedPreferences("input", MODE_PRIVATE);
String name = ref.getString("name","");
String gender = ref.getString("gender", "");
int id = ref.getInt("id", 0);
int age = ref.getInt("age", 18);
tvShowContent.setText("\nname: "+name+"\ngender: "+gender +"\nid: "+id+"\nage: "+age);
}
5. 实现记住密码功能, 以及复习强制下线功能
分析思路:
1> 要想实现记住密码功能,只需在登录界面中加一个Checkbox复选框,每次启动活动的时候或者登录的时候都检查
其是否被勾选.如果在启动Activity的时候检查出它被勾选,则就去对应的sharedPreferences文件中找到对应的账号
密码,填入即可.如果登录的时候检查它被勾选,则将这个值保存到sharedPreferences文件中,以供启动activity的时候读取到true
2> 强制下线功能实现: 发送广播,而后重新启动登录界面
代码如下:
首先是登录界面实现记住密码功能,当点击登录的时候会弹出ForceOffline活动.
MainActivity.java
package com.dream.fioman.fioman_03rememberpassword;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
private EditText etUsername;
private EditText etPassword;
private CheckBox cbRememberPwd;
private Button btnLogin;
private SharedPreferences pref;
private SharedPreferences.Editor editor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化控件
setViews();
pref = PreferenceManager.getDefaultSharedPreferences(this);
boolean isRemember = pref.getBoolean("remember_password", false);
if (isRemember) {
//将账号和密码都设置到文本框中
etUsername.setText(pref.getString("username", ""));
etPassword.setText(pref.getString("password", ""));
cbRememberPwd.setChecked(true);
}
//为控件设置监听器
btnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if ("admin".equals(etUsername.getText().toString()) && "123456".equals(etPassword.getText().toString())) {
editor = pref.edit();
if (cbRememberPwd.isChecked()) {
//如码框被选中
editor.putBoolean("remember_password", true);
editor.putString("username", etUsername.getText().toString());
editor.putString("password", etPassword.getText().toString());
} else {
editor.clear();
}
editor.commit();
Intent intent = new Intent(MainActivity.this, ForceOffLine.class);
startActivity(intent);
finish();
} else {
Toast.makeText(MainActivity.this, "账号或密码错误,请重新输入", Toast.LENGTH_SHORT).show();
}
}
});
}
private void setViews() {
etPassword = (EditText) findViewById(R.id.et_password);
etUsername = (EditText) findViewById(R.id.et_username);
cbRememberPwd = (CheckBox) findViewById(R.id.cb_remember_password);
btnLogin = (Button) findViewById(R.id.btn_login);
}
}
ForceActivity.java里面就是发送一条强制下线的广播.
package com.dream.fioman.fioman_03rememberpassword;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
/**
* 强制用户下线的类
*/
public class ForceOffLine extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_force_off_line);
Intent intent = new Intent("fioman_dream_ForceOffLine");
sendBroadcast(intent);
}
}
然后是写一个广播接收器,接收这条广播.并在广播接收器里面弹处一个警告窗口,当用户点击确定的时候
就会返回到登录界面,并且账号密码都自动填上去了.
ForceOfflineReceiver.java
package com.dream.fioman.fioman_03rememberpassword;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.view.WindowManager;
/**
* Created by FioMan on 2016/10/29.
* Description : 强制下线的广播接收器,当接收到fioman.dream.ForceOffline这条广播的时候,会执行相关的业务.
*/
public class ForceOffLineReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, final Intent intent) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("警告")
.setMessage("你应经被强制下线, 请重新登录!")
.setCancelable(false)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
Intent intent = new Intent(context, MainActivity.class);
//启动一个新的活动
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
break;
}
}
});
AlertDialog dialog = builder.create();
//由于是系统广播,需要设置其类型,保证在广播接收器中可以正常的弹出
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
dialog.show();
}
}
这里注意一定要在清单文件中注册,并且必须加上系统弹窗权限:
6. Android 数据存储方案之 数据库存储
SQLite是一款轻量级的关系型数据库,它的运算速度非常的快,占用资源很少,通常只需要几百K就可以了.
因而特别适合在移动设备上使用.前面介绍的数据持久化存储只适合一些保存数据量较小的方式,数据一旦牵涉
比较大的时候,就需要使用SQlite数据库.创建数据库
1> Android中管理数据库的类是一个SQLiteOpenHelper类,首先你要知道这个类是一个抽象类,我们如果要对数据库进行
操作必须要创建一个类MySQLiteOpenHelper,让其继承自SQLiteOpenHelper类,并且重写里面的两个抽象方法:
onCreate()方法和onUpgrade()方法,然后在这两个方法中去实现创建|升级数据库的逻辑.2>SQLiteOpenHelper中还有两个非常重要的抽象方法,getReadableDatabase()和getWriteableDatabase().这两个方法都
可以创建或打开一个现有的数据库(如果数据库已经存在则直接打开,否则重新创建一个新的数据库),并返回一个可以对数据库
进行读写操作的对象.不同的是,当数据库不可写入的时候(如磁盘空间已满)getReadableDataBase()方法返回的对象将以
只读的方式打开数据库,而getWriteableDatabase()方法将报出异常.3>SQLiteOpenHelper中有两个构造方法可以供重写,一般使用参数少一点的那个构造方法即可.
public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version);
第一个参数是Context,第二个参数是数据库的名称,第三个参数运行我们在查询数据库的时候返回一个自定义的Cursor,一般
都是传入null表示选择默认设置.第4个参数表示数据库的版本.4>当构建完数据库帮助类SQLiteOpenHelper的实例之后,再调用它的getReadableDatabase()或getWriteableDatabase()
方法就能够创建数据库了,数据库文件会存放在data/data/<项目的包名>/databases/目录下.此时,重写的onCreate()方法
会得到执行,所以会在这里去处理一些创建表的逻辑.
下面通过一个例子,来看一下SQLite数据库的操作:
1.新建MySQliteDatabaseHelper类继承自SQLiteOpenHelper.代码如下:
package com.dream.fioman.fioman_04sqliteopenhelper;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;
/**
* Created by FioMan on 2016/10/29.
* Description : 自定义数据库管理工具类
*/
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
private static final String CREATE_BOOK = "create table book (" +
"id integer primary key autoincrement," +
"author text, " +
"price read ," +
"pages integer," +
"name text)" ;
private Context context;
public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
this.context = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
Toast.makeText(context, "数据库表格创建成功!", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
解析: 我们在onCreate()方法中调用了SQLiteDatabase的execSQL方法去执行一条建表语句.并提示一个Toast去
提示建表成功.
然后值主Activity中的代码:
package com.dream.fioman.fioman_04sqliteopenhelper;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private Button btnCreate;
private MySQLiteOpenHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnCreate = (Button) findViewById(R.id.btnCreate);
//获取自定义数据库管理工具类实例
dbHelper = new MySQLiteOpenHelper(this, "bookstore.db", null, 1);
btnCreate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//创建打开数据库
dbHelper.getWritableDatabase();
}
});
}
}
注意MyOpenHelper中的onCreate()方法调用的时机,首先是我们第一次点击按钮的时候,就会检测到当前
程序没有bookstore.db这个数据库,于是就会创建数据库,并执行onCreate()方法,这样book表也就得到了创建.
在数据库已经存在的时候,onCreate()方法便不会再次得到执行.
3.升级数据库
onUpgrade()方法是用于对数据库进行升级的,它在整个数据库的管理工作中担当着非常重要的作用,如果我们想在
bookstore.db数据库文件中添加一张表,这个时候直接创建表是行不通的,以为这个数据库已经存在了,之后不管我们
要执行多少次点击按钮事件,它都不会重新创建列表了.怎么办?这个时候可在onUpgrade()方法中强制执行onCreate()
方法,不过之前我要将可能已经存在的表删除掉,db.execSQL(“drop table if exits Book”); db.execSQL(“drop table if exits
Category”); onCreate(db);
如果数据库中的表已经存在就删除掉而后在onCreate()方法中重新创建即可.代码如下:
但是如何让程序调用onUpgrade()方法呢? 只需要在获取helper对象的时候,更改版本号即可.代码如下:
package com.dream.fioman.fioman_04sqliteopenhelper;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;
/**
* Created by FioMan on 2016/10/29.
* Description : 自定义数据库管理工具类
*/
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
private static final String CREATE_BOOK = "create table book (" +
"id integer primary key autoincrement," +
"author text, " +
"price read ," +
"pages integer," +
"name text)" ;
private static final String CREATE_CATEGORY="create table Category (" +
"id integer primary key autoincrement," +
"category_name text," +
"category_code integer)";
private Context context;
public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
this.context = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
db.execSQL(CREATE_CATEGORY);
Toast.makeText(context, "数据库表格创建成功!", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists Book");
db.execSQL("drop table if exists Category");
onCreate(db);
}
}
onUpgrade()方法的调用时机,当传递过来的版本号增加改变的时候,就会调用onUpgrade()方法.
- 添加数据(insert)
1> getWriteableDatabase()方法会返回一个SQLiteDatabase对象,借助这个对象就可以对数据进行增删改查操作.
添加数据的逻辑如下:
//给添加数据按钮设置监听器
btnAddData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", "The First Line");
values.put("author", "GuoLin");
values.put("pages", 554);
values.put("privce", 66.6);
db.insert("Book", null, values);
//清空values
values.clear();
//开始组装第二条数据
values.put("name", "FioMan Start Skill");
values.put("author", "FioMan");
values.put("pages", 125);
values.put("privce", 77.7);
db.insert("Book", null, values);
}
});
注意: 可以连续添加几条数据,利用values.但是必须在使用的时候先清空values.还有就是insert()方法中第二个参数一般传入null.
5.更新(改)数据 (update())
怎么样才能做到修改表中已经存在的数据呢?
主要是调用update方法
public int update(String table, ContentValues values, String whereClause, String[] whereArgs);
第一个参数是表名称, 第二个参数是ContentValues对象,第三个和第四个参数代表where子句,表示你要更新的数据的位置.
第三个参数代表的where,而第四个参数是对第三个参数占位符的补充
//为修改表中数据的按钮设置监听器
btnUpdateData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("price", 112);
db.update("Book", values, "name = ?", new String[] {"The First Line"});
}
});
6.删除数据(delete()),删除数据主要是调用
dbHelper.delete(String table, String whereClause, String[] whereArgs);
一个参数是表明,另外两个参数是删除的约束条件.
//为删除表中数据的按钮设置监听器
btnDeleteData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete("Book", "pages > ", new String[]{"500"});
}
});
- 查询表中的数据
1> SQL的全称是 Structured Query Language,结构化查询语言. 主要是靠Query方法.
public Cursor query(String table, String[] columns, String selection,
String[] selectionArgs, String groupBy, String having,
String orderBy);
第一个参数是表名,第二个参数用于表明去查询那几列,如果不指定,则默认查询所有的列.
第三个,第四个参数用于去约束查询某一行或某几行的数据,不指定则默认查询所有行的数据.
第5个参数用于指定需要groupBy的列,不指定则表示不对查询结构进行groupBy操作.第6个参数表示
对groupBy进行进一步的过滤,不指定则表示不过滤.第7个参数用于指定查询结果的排序方式,不指定则
表示采用默认的排序方式.
一个查询数据库的demo
//为查询数据库表添加监听器
btnQueryData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
//查询所有的数据
Cursor c = db.query("Book", null, null, null, null, null, null, null);
if (c.moveToFirst()) {
do {
//遍历Cursor,取出数据并打印
String name = c.getString(c.getColumnIndex("name"));
String author = c.getString(c.getColumnIndex("author"));
int pages = c.getInt(c.getColumnIndex("pages"));
double price = c.getDouble(c.getColumnIndex("price"));
Log.i("MyTag", "onClick() -> book name is " + name);
Log.i("MyTag", "onClick() -> book author is "+author);
Log.i("MyTag", "onClick() -> book pages is "+pages);
Log.i("MyTag", "onClick() -> boo price is "+price);
} while (c.moveToNext());
}
c.close();
}
});
- SQLite数据库的最佳实践
事务的标准用法:首先是调用SQLiteDatabase的beginTransaction()方法来开启一个事务,然后在一个异常捕获代码中去执行
相应的具体的执行数据库的操作,当所有的操作完成之后,调用setTransactionSuccessful()表示事务已经执行成功了,最后在finally
代码块中调用endTransaction()结束事务.如果抛出异常,则整个事务就是失败的,之前的删除操作也会失败.
/**
* 使用事务的监听器
*/
btnUseTransaction.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.beginTransaction();//开启事务
try {
db.delete("Book", null, null);
ContentValues values = new ContentValues();
values.put("name", "北京遇到西雅图");
values.put("author","吴秀波");
values.put("pages", 30);
values.put("price",10.89);
db.insert("Book", null, values);
//事务执行成功
db.setTransactionSuccessful();
} catch (Exception e) {
e.printStackTrace();
} finally {
db.endTransaction();//结束事务
}
}
});
- 升级数据库的最佳写法:
前面的例子,升级数据的方法中只是简单的将原来的表全部删除了,而后重新创建了一个新表,这样做是不够的,因为这样就将原来
表中的数据给删除掉了,这样会一旦版本升级,用户以前的数据就会丢失,这样做显然是不行的.如何做呢?要用如下的方式来进行.
巧用onUpgrade()方法中的oldVersion参数.
package com.dream.fioman.fioman_04sqliteopenhelper;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;
/**
* Created by FioMan on 2016/10/29.
* Description : 自定义数据库管理工具类
*/
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
private static final String CREATE_BOOK = "create table book (" +
"id integer primary key autoincrement," +
"author text, " +
"price read ," +
"pages integer," +
"name text)";
private static final String CREATE_CATEGORY = "create table Category (" +
"id integer primary key autoincrement," +
"category_name text," +
"category_code integer)";
private Context context;
public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
this.context = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
Toast.makeText(context, "数据库表格创建成功!", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1:
db.execSQL(CREATE_CATEGORY);
case 2:
db.execSQL("alert table Book add colum category_id integer");
default:
}
db.execSQL("drop table if exists Book");
db.execSQL("drop table if exists Category");
onCreate(db);
}
}
注意这里的switch不用break,因为要确保所有的升级版本依次执行,因为有的用户也许是从1,直接升级到3.
如果有break,就会使得表创建的不完全.