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;版权声明:本文为博主原创文章,未经博主允许不得转载。