任何一个应用程序,其实说白了就是在不停地和数据打交道,聊QQ、看新闻、刷微博,所关心的都是里面的数据,没有数据的应用程序就变成了一个空壳子,对用户来说没有任何实际用途。大多数的数据基本都是由用户产生的,比如发微博、评论新闻,其实都是在产生数据。
而对于之前博文中我们用到的各种各样的数据,都是瞬时数据。所谓的瞬时数据则是有可能会因为程序关闭或其他原因导致内存被回收而丢失的数据。对于一些关键性的信息而言,这是不可以的。而保证关键性的数据不丢失的技术则是数据持久化技术了。
数据持久化就是指将那些内存中的瞬时数据保存到存储设备中,保证即使在手机或电脑关机的情况下,这些数据仍然不会丢失。保存在内存中的数据是处于瞬时状态的,而保存在存储设备中的数据是处于持久状态的,持久化技术则提供了一种机制可以让数据在瞬时状态和持久状态之间进行转换。Android系统中主要提供了3种方式用于简单地实现数据持久化功能,即文件存储、SharedPreferences存储以及数据库存储。
目录
文件存储
将数据存储到文件中
文件存储是Android中最基本的一种数据存储方式,它不对存储的内容进行任何的格式化处理,所有数据都是原封不动地保存到文件当中的,因而它比较适合用于存储一些简单的文本数据或二进制数据。如果你想使用文件存储的方式来保存一些较为复杂的文本数据,就需要定义一套自己的格式规范,这样可以方便之后将数据从文件中重新解析出来
首先创建一个新的项目命名为FilePersistenceTest项目。并修改activity_main.xml中的代码,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!--加入了一个EditText,用于输入文本内容-->
<EditText
android:id="@+id/edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Type something here"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
运行结果如下。此时,可以输入任意想输入的内容,但是按一下back或者退出程序,所输入的内容都会丢失,因为它只是瞬时数据。在活动被销毁后就会被回收。
接下来,修改MainActivity中的代码,让数据被回收之前。存储到文件当中
package com.example.filepersistencetest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.os.Bundle;
import android.widget.EditText;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class MainActivity extends AppCompatActivity {
private EditText edit;
@Override
protected void onCreate(Bundle savedInstanceState) {//在初始化的时候获取editText实例
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit=(EditText) findViewById(R.id.edit);//获取了EditText的实例
}
//定义一个保存数据的函数
//Context 类中提供了一个openFileOutput() 方法,可以用于将数据存储到指定的文件中
public void save (String inputText){
FileOutputStream out = null;//openFileOutput () 方法返回的是一个FileOutputStream 对象
BufferedWriter writer = null;//用于将文本内容写入到文件中
try {
out = openFileOutput("data", Context.MODE_PRIVATE);
//用于将数据存储到指定的文件中
//第一个参数是文件名,在文件创建的时候使用的就是这个名称,
// 注意这里指定的文件名不可以包含路径,因为所有的文件都是默认存储到/data/data/<package name>/files/目录下的
//第二个参数是文件的操作模式,主要有两种模式可选,MODE_PRIVATE和MODE_APPEND。
//MODE_PRIVATE是默认的操作模式,表示当指定同样文件名的时候,所写入的内容将会覆盖原文件中的内容
//MODE_APPEND则表示如果该文件已存在,就往文件里面追加内容,不存在就创建新文件。
//openFileOutput () 方法返回的是一个FileOutputStream 对象,
// 得到了这个对象之后就可以使用Java流的方式将数据写入到文件中了。
writer = new BufferedWriter(new OutputStreamWriter(out));
//FileOutputStream 对象通过OutputStreamWriter建出一个OutputStreamWriter 对象,
// 接着再使用OutputStreamWriter 构建出一个BufferedWriter 对象,
//通过BufferedWriter 对象来将文本内容写入到文件中
writer.write(inputText);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (writer != null) {
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//这个方法在活动被销毁之前调用,之后活动的状态将变为销毁状态。
//保证在活动销毁之前一定会调用这个方法
//所以通过重载onDestroy() 方法,在其中来保存数据
@Override
protected void onDestroy() {
super.onDestroy();
String inputText = edit.getText().toString();//获取了EditText中输入的内容
save(inputText);//调用上面定义的save函数
}
}
运行程序
然后按下Back键关闭程序,这时我们输入的内容就已经保存到文件中了。
接下来,借助Android Device Monitor工具来查看一下。然而根本找不到。。。网上各种博客说的什么打开文件夹或者在terminal输入什么,全都不行,那些博客基本都是你抄我我抄你的。。。连实现都没实现过就说了。。。
首先打开SDK路径是百分百不行的
根本没有monitor这个东西。既然打不开就不管了。。。直接读取就好了
从文件中读取数据
类似于将数据存储到文件中,Context 类中还提供了一个openFileInput() 方法,用于从文件中读取数据。这个方法要比openFileOutput() 简单一些,它只接收一个参数,即要读取的文件名,然后系统会自动到/data/data/<package name>/files/目录下去加载这个文件,并返回一个FileInputStream 对象,得到了这个对象之后再通过Java流的方式就可以将数据读取出来了。
接下来通过修改MainActivity中的代码,实现得重新启动程序时EditText中能够保留我们上次输入的内容
package com.example.filepersistencetest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.widget.EditText;
import android.widget.Toast;
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 AppCompatActivity {
private EditText edit;
//定义一个读入文件的函数
public String load(){
FileInputStream in = null;
BufferedReader reader = null;
StringBuilder content = new StringBuilder();
try {
//首先通过openFileInput() 方法获取到了一个FileInputStream 对象
in = openFileInput("data");
//然后借助它又构建出了一个InputStreamReader 对象
//接着再使用InputStreamReader 构建出一个BufferedReader 对象
reader = new BufferedReader(new InputStreamReader(in));
String line = "";
while ((line = reader.readLine()) != null) {
content.append(line);//进行一行一行的读取
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return content.toString();
}
@Override
protected void onCreate(Bundle savedInstanceState) {//在初始化的时候获取editText实例
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit=(EditText) findViewById(R.id.edit);//获取了EditText的实例
String inputText = load();//在初始化的时候读入文件
if (!TextUtils.isEmpty(inputText)) { //如果读到的内容不为null
edit.setText(inputText); //调用EditText的setText() 方法将内容填充到EditText里
edit.setSelection(inputText.length()); //调用setSelection() 方法将输入光标移动到文本的末尾位置以便于继续输入
Toast.makeText(this, "Restoring succeeded", Toast.LENGTH_SHORT).show();
}
}
//定义一个保存数据的函数
//Context 类中提供了一个openFileOutput() 方法,可以用于将数据存储到指定的文件中
public void save (String inputText){
FileOutputStream out = null;//openFileOutput () 方法返回的是一个FileOutputStream 对象
BufferedWriter writer = null;//用于将文本内容写入到文件中
try {
out = openFileOutput("data", Context.MODE_PRIVATE);
//用于将数据存储到指定的文件中
//第一个参数是文件名,在文件创建的时候使用的就是这个名称,
// 注意这里指定的文件名不可以包含路径,因为所有的文件都是默认存储到/data/data/<package name>/files/目录下的
//第二个参数是文件的操作模式,主要有两种模式可选,MODE_PRIVATE和MODE_APPEND。
//MODE_PRIVATE是默认的操作模式,表示当指定同样文件名的时候,所写入的内容将会覆盖原文件中的内容
//MODE_APPEND则表示如果该文件已存在,就往文件里面追加内容,不存在就创建新文件。
//openFileOutput () 方法返回的是一个FileOutputStream 对象,
// 得到了这个对象之后就可以使用Java流的方式将数据写入到文件中了。
writer = new BufferedWriter(new OutputStreamWriter(out));
//FileOutputStream 对象通过OutputStreamWriter建出一个OutputStreamWriter 对象,
// 接着再使用OutputStreamWriter 构建出一个BufferedWriter 对象,
//通过BufferedWriter 对象来将文本内容写入到文件中
writer.write(inputText);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (writer != null) {
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//这个方法在活动被销毁之前调用,之后活动的状态将变为销毁状态。
//保证在活动销毁之前一定会调用这个方法
//所以通过重载onDestroy() 方法,在其中来保存数据
@Override
protected void onDestroy() {
super.onDestroy();
String inputText = edit.getText().toString();//获取了EditText中输入的内容
save(inputText);//调用上面定义的save函数
}
}
注意,上述代码在对字符串进行非空判断的时候使用了TextUtils.isEmpty() 方法,这是一个非常好用的方法,它可以一次性进行两种空值的判断。当传入的字符串等于null 或者等于空字符串的时候,这个方法都会返回true ,从而使得我们不需要先单独判断这两种空值再使用逻辑运算符连接起来了。
结果如下图所示
SharedPreferences存储
不同于文件的存储方式,SharedPreferences是使用键值对的方式来存储数据的。也就是说,当保存一条数据的时候,需要给这条数据提供一个对应的键,这样在读取数据的时候就可以通过这个键把相应的值取出来。而且SharedPreferences还支持多种不同的数据类型存储,如果存储的数据类型是整型,那么读取出来的数据也是整型的;如果存储的数据是一个字符串,那么读取出来的数据仍然是字符串。
将数据存储到SharedPreferences中
要想使用SharedPreferences来存储数据,首先需要获取到SharedPreferences 对象。Android中主要提供了3种方法用于得到SharedPreferences 对象。
Context 类中的getSharedPreferences() 方法
此方法接收两个参数,第一个参数用于指定SharedPreferences文件的名称,如果指定的文件不存在则会创建一个,SharedPreferences文件都是存放在/data/data/<package name>/shared_prefs/目录下的。第二个参数用于指定操作模式,目前只有MODE_PRIVATE这一种模式可选,它是默认的操作模式,和直接传入0效果是相同的,表示只有当前的应用程序才可以对这个SharedPreferences文件进行读写。
Activity 类中的getPreferences() 方法
这个方法和Context中的getSharedPreferences() 方法很相似,不过它只接收一个操作模式参数,因为使用这个方法时会自动将当前活动的类名作为SharedPreferences的文件名。
PreferenceManager 类中的getDefaultSharedPreferences() 方法
这是一个静态方法,它接收一个Context 参数,并自动使用当前应用程序的包名作为前缀来命名SharedPreferences文件。得到了SharedPreferences 对象之后,就可以开始向SharedPreferences文件中存储数据了,主要可以分为3步实现。
- 调用SharedPreferences 对象的edit() 方法来获取一个SharedPreferences.Editor 对象。
- 向SharedPreferences.Editor 对象中添加数据,比如添加一个布尔型数据就使用putBoolean() 方法,添加一个字符串则使用putString() 方法,以此类推。
- 调用apply() 方法将添加的数据提交,从而完成数据存储操作。
接下来我们将activity_main.xml中的代码改为:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/save_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Save data"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
这里只是简单的防止一个按钮,用于将一些数据存到SharedPreferences文件当中。修改MainActivity中的代码,如下所示:
package com.example.filepersistencetest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
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 AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button saveData = (Button) findViewById(R.id.save_data);
//注册一个按钮点击事件,
saveData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//通过getSharedPreferences() 方法指定SharedPreferences的文件名为data
SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();
//向这个对象添加3重不同类型的数据
editor.putString("name", "Tom");
editor.putInt("age", 28);
editor.putBoolean("married", false);
//最后通过apply()方法提交,从而完成数据存储的操作
editor.apply();
}
});
}
}
从SharedPreferences中读取数据
SharedPreferences 对象中提供了一系列的get 方法,用于对存储的数据进行读取,每种get 方法都对应了SharedPreferences.Editor中的一种put 方法,比如读取一个布尔型数据就使用getBoolean() 方法,读取一个字符串就使用getString() 方法。这些get 方法都接收两个参数,第一个参数是键,传入存储数据时使用的键就可以得到相应的值了;第二个参数是默认值,即表示当传入的键找不到对应的值时会以什么样的默认值进行返回。
修改activity_main.xml中的代码,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/save_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Save data"
/>
<Button
android:id="@+id/restore_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Restore data"
/>
</LinearLayout>
这里增加了一个还原数据的按钮,我们希望通过点击这个按钮来从SharedPreferences文件中读取数据。修改MainActivity中的代码,如下所示:
package com.example.filepersistencetest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
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 AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button saveData = (Button) findViewById(R.id.save_data);
//注册一个按钮点击事件,保存数据
saveData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//通过getSharedPreferences() 方法指定SharedPreferences的文件名为data
SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();
//向这个对象添加3重不同类型的数据
editor.putString("name", "Tom");
editor.putInt("age", 28);
editor.putBoolean("married", false);
//最后通过apply()方法提交,从而完成数据存储的操作
editor.apply();
}
});
Button restoreData = (Button) findViewById(R.id.restore_data);
//设置一个按钮点击事件,恢复数据
restoreData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//首先通过getSharedPreferences() 方法得到了SharedPreferences 对象
SharedPreferences pref = getSharedPreferences("data", MODE_PRIVATE);
//分别调用它的getString() 、getInt() 和getBoolean() 方法,
//去获取前面所存储的姓名、年龄和是否已婚,
// 如果没有找到相应的值,就会使用方法中传入的默认值来代替,
String name = pref.getString("name", "");
int age = pref.getInt("age", 0);
boolean married = pref.getBoolean("married", false);
//通过Log将这些值打印出来。
Log.d("MainActivity", "name is " + name);
Log.d("MainActivity", "age is " + age);
Log.d("MainActivity", "married is " + married);
}
});
}
}
运行结果如下图所示
实现记住密码功能
之前博文《Android学习笔记之——通过broadcast实现强制下线功能》实现了登陆一个账号,然后进去再注销所有活动的功能。再很多的软件中,都存在记录密码这一功能。
首先修改activity_login.xml中的代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:layout_width="90dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textSize="18sp"
android:text="Account:" />
<EditText
android:id="@+id/account"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:layout_width="90dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textSize="18sp"
android:text="Password:" />
<EditText
android:id="@+id/password"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:inputType="textPassword" />
</LinearLayout>
<!--复选框控件-->
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="@+id/remember_pass"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="Remember password" />
</LinearLayout>
<Button
android:id="@+id/login"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="Login" />
</LinearLayout>
这里使用到了一个新控件CheckBox。这是一个复选框控件,用户可以通过点击的方式来进行选中和取消,我们就使用这个控件来表示用户是否需要记住密码。
然后修改LoginActivity中的代码,如下所示:
package com.example.broadcastbestpractice;
import androidx.appcompat.app.AppCompatActivity;
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;
//继承baseactivity,其内会控制各种activity的启动与销毁
public class LoginActivity extends BaseActivity {
//定义一些SharedPreferences的对象
private SharedPreferences pref;//存数据的SharedPreferences 对象
private SharedPreferences.Editor editor;//读数据
private CheckBox rememberPass;
private EditText accountEdit;
private EditText passwordEdit;
private Button login;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login); //加载布局login.xml的布局
//获取一个SharedPreferences 对象
pref = PreferenceManager.getDefaultSharedPreferences(this);
rememberPass = (CheckBox) findViewById(R.id.remember_pass);
//调用findViewById() 方法分别获取到账号输入框、密码输入框以及登录按钮的实例
accountEdit=(EditText) findViewById(R.id.account);//编辑文本(输入账号)实例化
passwordEdit= (EditText) findViewById(R.id.password);//编辑文本(输入密码)实例化
//调用pref的getBoolean() 方法去获取remember_password 这个键对应的值。
//一开始不存在的时候,默认为false
boolean isRemember = pref.getBoolean("remember_password", false);
if (isRemember) {//如果这个键值为true,也就是有键值。那么将账号和密码都读入一下。
// 将账号和密码都设置到文本框中
String account = pref.getString("account", "");
String password = pref.getString("password", "");
//通过setText将text设入。
accountEdit.setText(account);
passwordEdit.setText(password);
rememberPass.setChecked(true);
}
login=(Button) findViewById(R.id.login);//登陆按键实例化
//在登录按钮的点击事件里面对输入的账号和密码进行判断
login.setOnClickListener(new View.OnClickListener() {//为登陆按键注册监听器
@Override
public void onClick(View v) {
String account= accountEdit.getText().toString();
String password= passwordEdit.getText().toString();
//判断
//如果账号是admin且密码是123456,就认为登录成功
if (account.equals("admin") && password.equals("123456")) {
//////////////////////////////////////////////////////
editor = pref.edit();//跟前面一样,需要调用edit()方法才可以编辑
if (rememberPass.isChecked()) { // 登录成功后会检查复选框是否被选中
//如果勾选了,就将账号和密码的值加进去
//向editor对象中加载数据
editor.putBoolean("remember_password", true);//将remember_password 设置为true
//然后把account 和password 对应的值都存入到SharedPreferences文件当中并提交
editor.putString("account", account);
editor.putString("password", password);
} else {//如果没有勾选则清空一下
editor.clear();//将SharedPreferences文件中的数据全部清除掉
}
//最后通过apply()方法提交,从而完成数据存储的操作
editor.apply();
//////////////////////////////////////////////////////
Intent intent = new Intent(LoginActivity.this, MainActivity.class);//如果成功就通过intent转跳到mainactivity
startActivity(intent);
finish();
} else {
Toast.makeText(LoginActivity.this, "account or password is invalid", Toast.LENGTH_SHORT).show();
}
}
});
}
}
SQLite数据库存储
SQLite是一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,通常只需要几百KB的内存就足够了,因而特别适合在移动设备上使用。
Android为了让我们能够更加方便地管理数据库,专门提供了一个SQLiteOpenHelper帮助类。
SQLiteOpenHelper是一个抽象类,这意味着如果我们想要使用它的话,就需要创建一个自己的帮助类去继承它。SQLiteOpenHelper中有两个抽象方法,分别是onCreate() 和onUpgrade() ,我们必须在自己的帮助类里面重写这两个方法,然后分别在这两个方法中去实现创建、升级数据库的逻辑。
SQLiteOpenHelper中还有两个非常重要的实例方法:getReadableDatabase() 和getWritableDatabase() 。这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则创建一个新的数据库),并返回一个可对数据库进行读写操作的对
象。不同的是,当数据库不可写入的时候(如磁盘空间已满),getReadableDatabase()方法返回的对象将以只读的方式去打开数据库,而getWritableDatabase() 方法则将出现异常。
SQLiteOpenHelper中有造方法中:
- 第一个参数是Context,,必须要有它才能对数据库进行操作。
- 第二个参数是数据库名,创建数据库时使用的就是这里指定的名称。
- 第三个参数允许我们在查询数据的时候返回一个自定义的Cursor,一般都是传入null。
- 第四个参数表示当前数据库的版本号,可用于对数据库进行升级操作。
构建出SQLiteOpenHelper的实例之后,再调用它的getReadableDatabase() 或getWritableDatabase() 方法就能够创建数据库了,数据库文件会存放在/data/data/<package name>/databases/目录下。此时,重写的onCreate() 方法也会得到执行,所以通常会在这里去处理一些创建表的逻辑。