我在前年做了个查询手机号和邮编地理位置的小程序,已经放到mm和天翼空间上卖了,应这次CU征文我就介绍一下这个项目的详细内幕。
首先最终上效果图
程序代码结构
1.开发准备
1)开发过程首先从网络上找手机号数据库,我找到的是mdb(微软的access),越新越好
2)android的数据库是sqlite,因此我们必须在电脑上创建好数据库,导入到程序里,到sqlite.org上下载windows版的sqlite3,创建好数据库mobile.db:
全国的城市列表名称,使用id作为唯一标识,可以减少数据库大小,因为android程序中文件大小不能超过1MB
点击(此处)折叠或打开
- CREATE TABLE city(id int,name text);
--运营商列表
- CREATE TABLE isp(id int,name text);
---所有城市的邮政编码
- CREATE TABLE code_city(code text,city_id integer);
--所有手机号段对应的运营商和城市列表,这个表公有44400条数据,若是把isp和city的id作为两个字段的话,会超过1MB,我把isp和city的id进行合并成一个字段(最高位为ispid(isp只有3个),后三位为city(357个)的id)能够省下200kb的大小,最终整个库为806KB
- CREATE TABLE mobile (start_num integer, end_num integer, isp_city_id integer);--所有手机号段对应的运营商和城市列表
2.开始开发
新建工程,我选择的是1.6,只是两年前的最新版本,我目前也懒得更新了
2.1 AndroidManifest.xml 这个是android里最重要的文件,这个文件类似于ssh里的applicationContext.xml之类的定义了活动和权限等等信息,我基本上没有改这个文件,因为是单机的不需要调用网络蓝牙和文件写入之类的权限
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="yifangyou.mobile_query"
- android:versionCode="1"
- android:versionName="1.0">
- <application android:icon="@drawable/icon" android:label="@string/app_name">
- <activity android:label="@string/app_name" android:name=".mobile_query">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
- <uses-sdk android:minSdkVersion="2" />
- </manifest>
2.2,在res目录下建立raw目录把mobile.db放入
2.3,在res/values/strings.xml是保存程序中用到的中文字,代码里最好不要写中文,便于实现多语言版本
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <string name="app_name">手机号区号归属</string>
- <string name="searching_txt">请稍后,查询中...</string>
- <string name="search_complete_txt">查询完毕</string>
- <string name="search_txt">查询</string>
- <string name="result_txt">查询结果</string>
- <string name="enter_txt">手机号或者区号</string>
- <string name="id_empty_txt">手机号或者区号为空!</string>
- <string name="id_error_txt">手机号或者区号错误</string>
- <string name="enter_again_txt">请输入手机号或者区号</string>
- <string name="mobile_error_txt">手机号必须是11位的数字串</string>
- <string name="telphone_error_txt">区号必须是大于等于3位的数字串</string>
- <string name="location_txt">所属地区:</string>
- <string name="unknown_txt">未知</string>
- <string name="about_line_txt">开发者:yifangyou\n发布时间:2010年07月\nCopyright?2010 yifangyou\n</string>
- <string name="help_line_txt">本程序实现查询手机号或者区号对应的地理位置信息,精确到省市和运营商,信息库2010年07月01日整理完成,共18万条数据,包含最新的152、186、188、189号码段的归属地数据。\n使用方法:在输入框内输入11位手机号或者3、4位区号,点击搜索即可</string>
- <string name="about_txt">关于</string>
- <string name="exit_txt">退出</string>
- <string name="help_txt">帮助</string>
- <string name="exit_info_txt">已经退出,谢谢使用</string>
- <string name="clean_txt">清空</string>
- <string name="ok_txt">确定</string>
- </resources>
2.4建立菜单,如下面的@+id/help表示菜单项的id,在程序代码中需要响应这个菜单时用到
- <?xml version="1.0" encoding="utf-8"?>
- <menu xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:id="@+id/help"
- android:alphabeticShortcut="h"
- android:title="帮助" />
- <item android:id="@+id/about"
- android:alphabeticShortcut="a"
- android:title="关于" />
- <item android:id="@+id/exit"
- android:alphabeticShortcut="e"
- android:title="退出" />
- </menu>
2.4页面布局,我这个程序界面比较简单用线性竖向布局
main.xml:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_;fill_parent"
- android:layout_height="fill_parent"
- >
- <LinearLayout
- android:orientation="horizontal"
- android:layout_;fill_parent"
- android:layout_height="wrap_content"
- >
- <TextView
- android:layout_;wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/enter_txt"
- />
- <EditText android:id="@+id/search"
- android:layout_;wrap_content"
- android:layout_height="wrap_content"
- android:text=""
- android:layout_weight="1.0"
- />
- <Button android:id="@+id/submit"
- android:layout_;wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:text="@string/search_txt">
- </Button>
- </LinearLayout>
- <TextView
- android:layout_;fill_parent"
- android:layout_height="wrap_content"
- android:textColor="#99FF0000"
- android:text="@string/result_txt"
- />
- <TextView android:id="@+id/result"
- android:layout_;fill_parent"
- android:layout_height="wrap_content"
- android:textColor="#9900FF00"
- android:text=""
- />
- <Button android:id="@+id/clean"
- android:layout_;wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:text="@string/clean_txt"/>
- </LinearLayout>
2.5主程序
1)首先对各个按钮进行设置监听事件,里面的R.id.xxx是对应main.xml
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);//加载布局文件main.xml
- dbm = new DBManager(this);//这是初始化数据库操作类
- search_et = (EditText) findViewById(R.id.search);
- result_et = (TextView) findViewById(R.id.result);
- Button btn = (Button) findViewById(R.id.submit);//定义查询按钮的事件
- btn.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- result_et.setText(getString(R.string.searching_txt)); //读取输入框的数据库
- search();
- }
- });
- Button clean_btn=(Button)findViewById(R.id.clean);
- clean_btn.setOnClickListener(new OnClickListener(){
- public void onClick(View v){
- search_et.setText("");
- }
- });
- isp_names=dbm.get_isp_name();
- city_names=dbm.get_city_name();
- }
菜单显示菜单和设置菜单事件
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- try {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.index, menu);
- } catch (Exception e) {
- }
- return true;
- }
- public boolean onOptionsItemSelected(MenuItem item) {
- super.onOptionsItemSelected(item);
- int id = item.getItemId();
- switch (id) {
- case R.id.help:
- showHelp();
- break;
- case R.id.about:
- showAbout();
- break;
- default:
- alert(getString(R.string.app_name)
- + getString(R.string.exit_info_txt));
- finish();
- break;
- }
- return true;
- }
剩下的就是查询数据库了
注意由于我使用的库是放在raw下,android无法把这个文件作为数据库(不知道为什么),我的解决是把这个文件写到android的数据库库能够读到的地方(一般是程序的安装目录下的files下即可)去
- public DBManager(Context context) {
- this.context = context;
- try {
- dbpath = context.getPackageManager().getApplicationInfo(
- context.getPackageName(), 0).dataDir
- + "/files/" + DB_NAME;
- initDB();
- db = SQLiteDatabase.openOrCreateDatabase(dbpath, null);
- } catch (NameNotFoundException e) {
- e.printStackTrace();
- }
- }
- public boolean initDB() {
- java.io.File f = new java.io.File(dbpath);
- if (f.exists()) {
- return true;
- }
- FileOutputStream stream;
- try {
- stream = context.openFileOutput(DB_NAME, Context.MODE_PRIVATE);
- fp = context.getResources().openRawResource(R.raw.mobile);
- try {
- int size = fp.available();
- byte[] buffer = new byte[size];
- fp.read(buffer);
- stream.write(buffer);
- fp.close();
- stream.close();
- } catch (IOException e1) {
- e1.printStackTrace();
- return false;
- }
- } catch (FileNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return false;
- }