Android实例-手机安全卫士(三十三)-将数据库导入程序中

一、目标

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

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

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

数据库结构:

data1:  data2:

数据库在项目中:     查询结果:

二、代码实现

  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)方法代码;

 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     }

  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)步;

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

 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     }

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

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

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

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

时间: 2024-10-24 08:40:30

Android实例-手机安全卫士(三十三)-将数据库导入程序中的相关文章

Android实例-手机安全卫士(三十一)-根据指令完成相应操作二(锁屏和数据清除)

一.目标 1.实现远程锁屏和数据销毁操作: 2.初步制作“一键锁屏”应用和优化. 二.代码实现 1.在Receiver包下新建一个类(取名LockScreenReceiver)继承DeviceAdminReceiver类(是BroadcastReceiver类的一个子类),并在清单配置文件配置receiver标签 (1)在receiver标签中,增加name.permission属性,name为新建类(LockScreenReceiver)的全路径名称,permission为必须的BIND_DE

Android实例-手机安全卫士(三)-设计主页面UI

一.目标. 主界面UI如图所示: 方面是一个功能列表提示框(采用TextView),下面是功能列表(采用GridView). 二.代码实现. 1.在主界面布局文件(activity_home.xml)中增加组件.主界面布局文件(activity_home.xml)采用线性布局,上面一个TextView,根据UI设置相应属性:下面一个是GridView,通过android:numColumns属性设置该组件的列数,由于GridView还需要inflate单个布局文件,所以为其设置id. 主界面布局

Android实例-手机安全卫士(十八)-完成设置向导的4个UI和跳转事件

一.目标. 制作向导设置里面每一步的UI布局及点击事件控制. 1.使用自定义button背景.自定义组合控件.自定义文本样式等. 2.利用SharedPreferences对象,设置应用程序配置信息(向导设置完成后就不再进入)           二.代码实现. 1.在程序包下新建另外3个UI的类(分别为SetupWizard_ui_2.java.SetupWizard_ui_3.java.SetupWizard_ui_4.java),并在配置文件中注册Activity. 2.根据UI设计,在设

Android实例-手机安全卫士(三十七)-显示去电号码的归属地

一. 目标  利用BroadcastReceive获取去电广播,并获取去电号码,再查询数据库获取归属信息: 二.代码实现: 1.在广播包(receiver)下新建一个类(取名OutCallReceiver)继承BroadcastReceive: 2.在清单文件中注册,意图过滤器(inter-filter)中监听的动作为去电(NEW_OUTGOING_CALL) 广播接受者注册代码: 1 <receiver android:name="com.example.mobilesafe.recei

Android实例-手机安全卫士(三十)-根据指令完成相应操作一(报警音乐和GPS追踪)

一.目标 根据安全号码发送的指令完成相应的操作.                      二.代码实现 1.完成播放报警音乐操作 ①.在res文件夹下新建名为raw文件夹,并将音频文件拷贝至该文件夹下: ②.在播放报警音乐命令代码处(即SMSReceiver类中的else if("#*alarm*#".equals(body))里面),通过MediaPlayer对象的create(Context context(上下文), int resid(资源文件id))方法创建一个MediaP

Android实例-手机安全卫士(三十九)-自定义吐司(文本格式、显示窗口)

一.目标 自定义显示的吐司,包括内容文本格式.显示窗口格式. 二.代码实现 1.在“显示号码归属地”服务类(ShowPhoneAddService)中自定义吐司方法(取名myToast(String sting)),参数string为需要显示的字符串(注:本例中只需要使用自定义的吐司来显示号码归属地,其他地方不使用,因此在类中创建方法).在自定义方法中(myToast): (1)通过new TextView(Context context)方法定义一个TextView对象(取名view),参数c

Android实例-手机安全卫士(三十四)-优化归属地查询

一.目标 1.处理110.10086.座机等非手机号码的归属地: 二.代码实现 1.判断输入框中的文本是否符合手机号码的格式(1开头,第二位是345678,后面9位均为0-9的整数),根据手机号码的特点确定其正则表达式为“1[345678]\d{9}”,在代码中正则表达式以“^”开头,以“$”结束,同时里面的“\”需要转义,所以判断条件为“^1[345678]\\d{9}$”.上述正则表达式说明:[345678]表示“[]”里面的数任取一个,\d表示0-9的数任取一个,{9}表示前面的\d正好匹

Android实例-手机安全卫士(二十三)-自定义抽象类及使用

一.目标. 将二十二节中通过滑动切换Activity界面效果的代码提取出来做成一个自定义抽象类,并定义抽象方法,便于其他类的调用.也就是其他Activity(如设置向导2.3.4)通过继承自定义的类,再通过实现其未实现的方法来快速实现滑动切换. 二.代码实现. 1.在程序包下新建一个类(取名SlideActivity),继承Activity,指定其类型为抽象类(public abstract class SlideActivity extends Activity).在自定义的抽象类代码中,定义

Android实例-手机安全卫士(三十六)-根据Service是否开启确定CheckBox选中状态

一.目标 1.根据service是否在后台运行情况来确定CheckBox的选中状态: 2.解决"设置中心"的“开启来电号码显示归属地”功能在退出程序再进入时选中状态消失,在任务管理器中关闭“来显”服务时,功能仍为选中状态 二.代码实现 1.在src文件下新建一个包(取名com.example.mobilesafe.utils)用于存放各种工具类: 2.在工具类包下新建类(取名ServiceUtils,无需继承任何类),用于校验某个服务是否在正常运行(开启):在新建类(ServiceUt