«

[安卓]手机管家(九)高级工具之号码归属地查询

时间:2024-3-2 19:19     作者:韩俊     分类: Android


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;


版权声明:本文为博主原创文章,未经博主允许不得转载。

标签: android

热门推荐