一、目标

  1、 在项目中引入SQLiteDatabase数据库,通过输入输出流将数据库复制至指定path目录下;

  2、通过SQLiteDatabase的openDatabase()使用数据库,通过 rawQuery()方法执行SQL语句;

  3、初步实现号码归属地查询功能。

数据库结构:

data1:

Android DatabaseHelper拷贝db文件_数据库

  data2:

Android DatabaseHelper拷贝db文件_数据库_02

 数据库在项目中:

Android DatabaseHelper拷贝db文件_SQL_03

     查询结果:

Android DatabaseHelper拷贝db文件_SQL_04

二、代码实现

  1、将电话归属地数据库(名称address.db)拷贝至项目的assets文件夹下;

  2、在项目src文件夹中新建数据库工具包(取名com.example.mobilesafe.db.dao),在其下面新建工具类(取名NumberAddQueryUtils);

  3、在工具类(NumberAddQueryUtils)中新建返回值类型为String的静态方法(取名queryNumber),该方法需传入String类型的参数number;

  4、在新建方法(queryNumber)中通过数据库对象SQLiteDatabase的openDatabase(String path, CursorFactory factory, int flags)方法打开数据库,第二个参数factory表示工厂可用null表示默认,第三个参数flags表示打开方式(可用SQLiteDatabase下的OPEN_READONLY表示以只读的形式打开),对于第一个参数path表示需要加载的数据库的路径,由于SQL数据库无法通过file的形式加载,因此需要在程序初始化的时候将数据库拷贝至系统的data/data/包名(此例为com.example.mobilesafe)/files/数据库名称.db(详见第8步介绍),此时path的值就为“data/data/com.example.mobilesafe/files/address.db”,path定义成类的静态成员变量,并赋值;

  5、第4步openDatabase()方法返回的是一个SQLiteDatabase对象(取名database),通过SQLiteDatabase对象(取名database)的rawQuery(String sql, String[] selectionArgs)方法执行数据库查询语句,参数String sql表示需要执行的SQL语句(这个需要根据数据库的特征编写,此例中为select location from data2 where id = (select outkey from data1 where id = ?)),参数String[] selectionArgs为SQL语句中所有?所对应的参数组成的数组(需要通过new实例化,此例为queryNumber方法传入的参数number),由于number为11位,而数据库中只有7位,因此可通过String对象(number)的substring(int start, int end)方法截取前7位数(即0,7,其中7取不到)

  6、第5布中通过rawQuery()方法返回Cursor对象(取名cursor),采用while语句判断Cursor对象(cursor)是否还有下一项(moveToNext()),如果有,则在While语句中通过Cursor对象(cursor)的getString(int columnIndex)方法得到归属地,参数int columnIndex为归属地信息所在列的列号;该方法返回String类型的对象(取名location),由于数据库数据不完整或更新不及时,存在某些号码无归属地,所以在queryNumber方法开头先实例化location,并使其值等于号码,当在While语句中查询到归属地时再将值赋给location;

  7、通过Cursor对象(cursor)的close()方法释放Cursor对象资源,最后返回location;

queryNumber(String number)方法代码;

Android DatabaseHelper拷贝db文件_实例化_05

Android DatabaseHelper拷贝db文件_实例化_06

1 public static String queryNumber(String number) {
 2         
 3         String location = number;
 4 
 5         SQLiteDatabase database = SQLiteDatabase.openDatabase(path, null,
 6                 SQLiteDatabase.OPEN_READONLY);
 7         Cursor cursor =database.rawQuery(
 8                 "select location from data2 where id = (select outkey from data1 where id = ?)",
 9                 new String[] { number.substring(0, 7) });
10         while (cursor.moveToNext()) {
11             location = cursor.getString(0);
12         }
13         cursor.close();
14         return "";
15     }

View Code

  8、程序初始化时将assets文件夹下的数据库拷贝至制定目录中。在初始化界面(SplashActivity)中新建拷贝数据库至path目录下的方法(取名copyDB()),该方法类型为private。在copyDB()方法中:

    (1)通过new File(File dir, String name)方法实例化一个File对象(取名file),参数File dir为文件创建的目录(本例中目录为程序下的file文件中,因此可以通过getFilesDir()方法得到),参数String name为文件名(本例中与拷贝的文件名一致,即open方法中的文件名);    

    (2)通过getAssets()方法(其实是在content下,此处省略了this)的open(String fileName)方法打开assets文件夹下制定文件名(参数String fileName)的文件,从而得到InputStream对象(取名is)。由于本方法存在异常,所以通过try...catch...语句将异常捕获;    

    (3)通过new FileOutputStream(File file) 方法实例化一个文件输出流对象FileOutputStream(取名fos),参数File file为(2)中创建的File对象;

    (4)通过new实例化一个长度为1024的byte数组对象(取名buffer),再定义值为0的int对象(取名len);

    (5)通过InputStream对象(is)的read(byte[] buffer)方法读取其长度并将结果赋值给int对象(len),参数byte[] buffer为(4)中的数组对象,通过while语句判断读取到的结果是否为-1来执行相关操作(当InputStream对象中无数据时,此时会返回-1),如果判断条件不等于-1成立,则执行while语句;

    (6)在while语句中通过FileOutputStream对象(fos)的write(byte[] buffer, int byteOffset, int byteCount) 方法将InputStream对象中的数据写至FileOutputStream对象中,参数byte[] buffer为字节数据,即(4)中的buffer,参数int byteOffset表示从buffer的起始位置(为0),参数int byteCount表示从buffer中写入流中的长度(为len)

    (7)关闭输入流InputStream对象(is)和输出流FileOutputStream对象(fos);

    (8)优化拷贝方法。因此在打开程序执行初始化时总会执行拷贝数据方法(copyDB()),这样会出现重复拷贝,所以在copyDB()方法中创建file文件(即上面的第(1)步)后通过File对象的exists()方法和length()方法判断文件是否存在且长度大于零,如果存在则打印日志或者输出“初始化完成”等语句等均可,如果不存在则执行上述第(1)至第(7)步;

拷贝数据库至指定目录代码:

Android DatabaseHelper拷贝db文件_实例化_05

Android DatabaseHelper拷贝db文件_实例化_06

1 private void copyDB() {
 2         try {
 3             File file = new File(getFilesDir(), "address.db");
 4             if(file.exists()&&file.length()>0){
 5                 //已经存在无需拷贝
 6                 System.out.println("数据库已经拷贝完成");
 7             }else{
 8                 //拷贝数据库
 9                 InputStream is = getAssets().open("address.db");                
10                 FileOutputStream fos = new FileOutputStream(file);
11                 byte [] buffer = new byte[1024];
12                 int len = 0;
13                 while((len=(is.read(buffer)))!=-1){
14                     fos.write(buffer, 0, len);
15                 }
16                 is.close();
17                 fos.close();
18             }            
19         } catch (IOException e) {
20             e.printStackTrace();
21         }
22     }

View Code

 

  9、在“号码归属地查询页面”(NumberAddQueryActivity)的“查询号码归属地”方法(numberAddQuery)中判断输入文本框不为空(即else语句中)后,通过工具类(NumberAddQueryUtils)中的queryNumber(String number)方法将前面的电话号码(phone_number)传入,返回一个String类型的地址值(取名address);

  10、通过TextView对象(show_number_add)的setText(CharSequence text)方法将9中取得值填入,从而查的号码归属地。

使用工具类中的方法代码:

Android DatabaseHelper拷贝db文件_实例化_05

Android DatabaseHelper拷贝db文件_实例化_06

1 //去数据库查询号码归属地
2             String address = NumberAddQueryUtils.queryNumber(phone_number);
3             show_number_add.setText(address);

View Code