JSON解析也可以实现,但是需要联网,现在可以做一个离线版
第一个activity是一个工具列表,归属地查询是其中之一,我们需要另一个activity来显示查询页面 QueryAddressActivity
列表
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="60dp" android:text="高级工具" android:background="#00FF00" android:gravity="center" android:textSize="25sp"/> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="号码归属地查询" android:onClick="query"/> </LinearLayout>
public class AdvToolsActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_advtools); } public void query(View v){ //跳到我们的查询的页面 Intent intent = new Intent(this,QueryAddressActivity.class); startActivity(intent); } }
查询
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="60dp" android:text="手机号码归属地查询" android:background="#00FF00" android:gravity="center" android:textSize="25sp"/> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/et_queryaddr_inputnum" android:hint="请输入电话号码"/> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="开始查询" android:onClick="query"/> <TextView android:id="@+id/tv_queryaddr_result" android:layout_width="fill_parent" android:layout_height="50dp" android:gravity="center" android:textSize="20sp"/> </LinearLayout>
public class QueryAddressActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_queryaddr); } public void query(){ } }
两个activity的声明
<activity android:name=".AdvToolsActivity"></activity> <activity android:name=".QueryAddressActivity"></activity>
然后整个管家的homeactivity也要能跳到这,这里intent需求量大,编个号。。。
case 7: Intent intent7 = new Intent(HomeActivity.this,AdvToolsActivity.class); startActivity(intent7); break;
可以给query加一个toast,跟踪一下
现在来看查询逻辑
* 1.先要获取用户输入的手机号
* 2.用该手机号作为条件去数据库查询所在的城市
* 3.将查询结果回显到U
参考之前的MVC模式,第二步可以写成一个接口,告诉它要查询什么就好,给一个string类型的,返回一个string的归属地
public class AdressQueryDao { //加一个static在调用时就无需实例化了 //在QueryAddress里调用这个方法 public static String queryAddr(String num){ String addr = ""; return addr; } }
这里应该是用一个现成的数据库,而不是使用openhelper去自建,把数据库放在apk里,assert下,resource下的文件会编译,产生一个R文件,抽成一个整型值,方便使用
而assert下的只是有一个文件,不编译,要访问这个数据库,调用SQLiteDatabase下的openDatabase方法,返回cursor,第二个参数一般都是空,第三个参数表示读写状态
public class AdressQueryDao { //加一个static在调用时就无需实例化了 //在QueryAddress里调用这个方法 public static String queryAddr(String num){ String addr = ""; SQLiteDatabase db = SQLiteDatabase.openDatabase("file:///assets/address.db", null, SQLiteDatabase.OPEN_READONLY); Cursor cursor =db.rawQuery("select location from data2 where id = (select outkey from data1 where id = ?);", new String[]{num}); //默认游标指向了第一行的前一行,需要next //查询结果只能是一个地方,要么查询到,要么没有,当向下一行读取时,则获取 if (cursor.moveToNext()) { addr =cursor.getString(0); } return addr; } }
这时候最好能有一些测试,之前在web项目里都是在工程里高了一个包用来测试,但是这里最好不这么用,因为要打包发布,会把用户用不到的部分带出去了
用eclipse给的test工具,他会在新的test工程里生成一个包,相当于是放在原工程的包内,需要继承于AndroidTestCase
public class MyQueryAddrTest extends AndroidTestCase { public void testquery(){ String addr = AdressQueryDao.queryAddr("1386518"); System.out.println("MyQueryAddrTest.testquery()"+addr); } }
这个时候走起会报错,无法访问数据库
需要把db拷贝到data文件夹下的file或者database,边读边写
由于在copydb方法内进行读写时需要借道于上下文,所以需要传递一个context的参数,前面的都要改一下
public class AdressQueryDao { //加一个static在调用时就无需实例化了 //在QueryAddress里调用这个方法 public static String queryAddr(Context ctx,String num){ String addr = ""; copydb(ctx); SQLiteDatabase db = SQLiteDatabase.openDatabase("file:///assets/address.db", null, SQLiteDatabase.OPEN_READONLY); Cursor cursor =db.rawQuery("select location from data2 where id = (select outkey from data1 where id = ?);", new String[]{num}); //默认游标指向了第一行的前一行,需要next //查询结果只能是一个地方,要么查询到,要么没有,当向下一行读取时,则获取 if (cursor.moveToNext()) { addr =cursor.getString(0); } return addr; } private static void copydb(Context context){ File file = new File("data/data/com.rjl.mobilephonemanager/database/address.db"); try { InputStream is = context.getAssets().open("file:///assets/address.db"); FileOutputStream fos = new FileOutputStream(file); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
这里继续完成读写就好
private static void copydb(Context context){ File file = new File("data/data/com.rjl.mobilephonemanager/database/address.db"); InputStream is=null; FileOutputStream fos = null; try { is = context.getAssets().open("file:///assets/address.db"); fos = new FileOutputStream(file); byte[] b = new byte[1024]; int len =0; while((len=is.read(b))!=-1){ fos.write(b,0,len); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ if(fos!=null){ try { fos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(is!=null){ try { is.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
测试里面也要获取上下文
public class MyQueryAddrTest extends AndroidTestCase { public void testquery(){ String addr = AdressQueryDao.queryAddr(getContext(),"1386518"); System.out.println("MyQueryAddrTest.testquery()"+addr); } }这里只是复制数据库,AdressQueryDao里的查询SQL部分要先注释掉
走起,还是报了异常,找不到指定路径的数据库,不知道为啥这里绝对路径不行而必须相对路径的方法获取,其实是因为路径名里不能再带目录,没目录会自己建一个目录,有目录就没办法写,直接找文件就好
private static void copydb(Context context){ //去掉最后的目录database,不能带目录 File file = new File("data/data/com.rjl.mobilephonemanager/address.db"); InputStream is=null; FileOutputStream fos = null; try { /*is = context.getAssets().open("file:///assets/address.db");*/ //不能带目录,用方法 is = context.getResources().getAssets().open("address.db"); fos = new FileOutputStream(file);
ok~数据库拷贝进来了 将注释掉的还原,并且打开的路径也改成相对路径,再来test读取数据库是否成功
如此代码OK 可以回到QueryAddressActivity实现逻辑
public class QueryAddressActivity extends Activity { private EditText et_queryaddr_inputnum; private TextView tv_queryaddr_result; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_queryaddr); et_queryaddr_inputnum = (EditText) findViewById(R.id.et_queryaddr_inputnum); tv_queryaddr_result = (TextView) findViewById(R.id.tv_queryaddr_result); } public void query(View v){ String number = et_queryaddr_inputnum.getText().toString(); //截取前8位 String addr = AdressQueryDao.queryAddr(this,number.substring(0, 7)); tv_queryaddr_result.setText(addr); Toast.makeText(this, "正在查询", 0).show(); } }
输入号码查询会卡一下,因为每次都copydb,所以要判断下,第一次卡一下
String addr = ""; //只有第一次卡了 if(!file.exists()){ copydb(ctx); }
连第一次也不能忍,怎么破,放到splash页面去,吊不刁~
在oncreate里调用,在最后完成方法即可,无需static
private void copydb(Context context) { // TODO Auto-generated method stub File file = new File("data/data/com.cskaoyan.mobilemanager/address.db"); //判断下是否存在,不存在才copy if (!file.exists()) { InputStream is =null; FileOutputStream fos =null; try { is = context.getResources().getAssets().open("address.db"); fos= new FileOutputStream(file); byte[] b =new byte[1024]; int len =0; while ((len=is.read(b))!=-1) { fos.write(b, 0, len); } fos.close(); is.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally{ if (fos!=null) { try { fos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (is!=null) { try { is.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
这时其实不用去获取上下文了,需要上下文的已经搬出去了
QueryAddressActivity里的
public void query(View v){ String number = et_queryaddr_inputnum.getText().toString(); //截取前8位 String addr = AdressQueryDao.queryAddr(number.substring(0, 7)); tv_queryaddr_result.setText(addr); Toast.makeText(this, "正在查询", 0).show(); }
AdressQueryDao里的
public static String queryAddr(String num)
MyQueryAddrTest里的
String addr = AdressQueryDao.queryAddr("1386518");
还有一些小bug
如果输入的数据不到8位怎么搞?判断下
把QueryAddressActivity里的切割放进接口AdressQueryDao里去
public void query(View v){ String number = et_queryaddr_inputnum.getText().toString(); //截取前8位 String addr = AdressQueryDao.queryAddr(number); tv_queryaddr_result.setText(addr); Toast.makeText(this, "正在查询", 0).show(); }
if(num.length()==11){ num=num.substring(0,7); SQLiteDatabase db = SQLiteDatabase.openDatabase(file.getAbsolutePath(), null, SQLiteDatabase.OPEN_READONLY); Cursor cursor =db.rawQuery("select location from data2 where id = (select outkey from data1 where id = ?);", new String[]{num}); //默认游标指向了第一行的前一行,需要next //查询结果只能是一个地方,要么查询到,要么没有,当向下一行读取时,则获取 if (cursor.moveToNext()) { addr =cursor.getString(0); } } return addr;
但是用户还有可能输入字母什么的,输入不规则,由于可能的情况比较多,这里可以用正则表达式的搞定
String regexp = "^1\d{2,11}"; if(num.matches(regexp)){ num=num.substring(0,7); SQLiteDatabase db = SQLiteDatabase.openDatabase(file.getAbsolutePath(), null, SQLiteDatabase.OPEN_READONLY); Cursor cursor =db.rawQuery("select location from data2 where id = (select outkey from data1 where id = ?);", new String[]{num}); //默认游标指向了第一行的前一行,需要next //查询结果只能是一个地方,要么查询到,要么没有,当向下一行读取时,则获取 if (cursor.moveToNext()) { addr =cursor.getString(0); } } else { System.out.println("AdressQueryDao.querryAddr() not match regular express"); } return addr;
版权声明:本文为博主原创文章,未经博主允许不得转载。