大家好,今天给大家发一大招,讲的是电话归属地查询,只要是有效的电话号码都可以查出是哪个地方,还可以查询长途号码的归属地,由于数据库不是很完整,那些短号码就不能查到,比如说110,10086,95588,等一些服务号码,但十一位数的有效的号码这绝对能查的出来的,这大家可放心。废话不多说,直接上图给大家理解理解。
想要查询归属地号码,必须具有强大的数据库,我这里用到的是address.db数据库,这数据网上可以下载,淘宝也可以购买,我是从老师那里拷过来的,节省了很多心思。相信大家有疑问,数据库应该放在哪里。在这里我们放在原生目录Assest,然后通过流再拷到软件的私有文件夹。为什么要这样做呢。因为assest只能有读取操作,而我们这里有涉及到写入操作,所有需要,转路径。
//放在onCreate方法里,一启动Activity,就执行方法,从而拷贝数据库
copyDB("address.db");
//拷贝数据库方法
public void copyDB(String name) {
try {
//读取assest目录下的db
InputStream is = getAssets().open(name);
//设置保存的文件的路径,和文件名
File file = new File(getFilesDir(), name);
//如果文件有就返回
if(file.exists()){
return;
}
//输入流读取数据库
FileOutputStream fos = new FileOutputStream(file);
//将输入流转换为字符节
int len = 0;
byte[] buff = new byte[2014];
while ((len = is.read(buff)) != -1) {
//开始写入文件,参数二:开始值。参数三:结束值
fos.write(buff, 0, len);
}
//关闭流
is.close();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
创建一个数据dao工具类,作为读取和查询在新路径下的文件内容,以及一些得到电话号码的长度的判断。
/**
* 电话号码归属工具类
*/
public class Address {
//新路径:data/data/包名/files/address.db
//参数一:输入的电话号码,参数二:上下文
public static String getAddress(String num, Context context) {
//设置归属地初始值
String location = "";
//数据库保存的新路径
String PATH = context.getFilesDir().getAbsolutePath() + "/address.db";
//打开数据库,读取数据,参数三:标志位可读状态
SQLiteDatabase db = SQLiteDatabase.openDatabase(PATH, null,
SQLiteDatabase.OPEN_READONLY);
//电话号码涉及到位数,总共有六种可能
/**
* 号码的查询分析: 1. 手机号码查询 : 11位 如何设别手机号码 通过正则表达式来识别: ^1[345678]\d{9}$
* 2.三位的号码 110 120 119 121 等 : 特殊号码
* 3. 四位的号码 5556 ,5554 : 虚拟号码
* 4. 五位的号码10086 ,10000 95553 95556 12345 等 服务号码
* 5. 本地座机号码 7位或者8位
* 6. 长途号码020-68767565, 0735-56435434
*/
//正则表达式,^表示起点,$表示:终点,1表示第一个数字,[345678]表示第二位数字有这几个,\d表示0到9的数字,{9}表示重复九次,这样就构成十一位数
if (num.matches("^1[345678]\\d{9}$")) {
//执行address.db语句,查询数据库,根据address.db字段查询
String sql = "select location from data2 where id in(select outkey from data1 where id=?)";
//截取号码前6位数字,因为根据前六位就可以查到归属地
Cursor cursor = db.rawQuery(sql,
new String[] { num.substring(0, 7) });
//遍历游标
while (cursor.moveToNext()) {
location = cursor.getString(0);
}
//关掉游标
cursor.close();
} else {
//设置一个多判断
switch (num.length()) {
case 3:
location = "特殊号码";
break;
case 4:
location = "虚拟号码";
break;
case 5:
location = "服务号码";
break;
case 7:
location = "本机号码";
break;
case 8:
location = "本机号码";
break;
default:
//还有一种情况是0开头的长途号码
//判断一个位数是0,并电话号码长度大于10
if (num.startsWith("0")) {
if (num.length() > 10) {
//依据area条件取得归属地,截取第二位数字
String area = num.substring(1, 3);
String sql = "select location from data2 where area=? ";
Cursor cursor = db.rawQuery(sql, new String[] { area });
while (cursor.moveToNext()) {
location = cursor.getString(0);
}
cursor.close();
//其他情况,可能是0075这种形式的
//截取第二第三位数字,取得游标
} else {
String area1 = num.substring(1, 4);
String sql = "select location from data2 where area=? ";
Cursor cursor = db
.rawQuery(sql, new String[] { area1 });
while (cursor.moveToNext()) {
location = cursor.getString(0);
cursor.close();
}
}
break;
}
}
db.close();
return location;
}
}
数据库工具类方法就写好了,我们就要调用这方法,实现查询归属地这功能,由于layout布局简单,我就不上代码了,直接上实现查询的类。
/**
* 实现电话归属地功能
*
*/
public class AddressActivity extends Activity {
//使用的是注解方法
@ViewInject(R.id.num_et)
private EditText mNumEt;
@ViewInject(R.id.query_btn)
private Button mQueryBtn;
@ViewInject(R.id.num_tv)
private TextView mNumTv;
private Context context;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_address);
//注解这个Activity
ViewUtils.inject(this);
context = this;
//文本内容改变监听,意思是,输入一个字符串就会触发监听,而我这里,只要是输入三位数以上的数字,就会在TextView显示内容
mNumEt.addTextChangedListener(new TextWatcher() {
//文字改变的方法, s是Char类型需要转换为String类型
public void onTextChanged(CharSequence s, int start, int before,
int count) {
//转换为String类型
String result = s.toString();
//调用工具类方法,得到归属地
String location = Address.getAddress(result, context);
//判断是否为空,显示文本
if (!TextUtils.isEmpty(location)) {
mNumTv.setText(location);
}
}
//文字改变之前
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
//文字改变之后
public void afterTextChanged(Editable s) {
}
});
//点击事件
mQueryBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//获取输入值。
String numValue = mNumEt.getText().toString().trim();
if (TextUtils.isEmpty(numValue)) {
//使用抖动动画
Animation shake = AnimationUtils.loadAnimation(
AddressActivity.this, R.anim.shake);
//控件开始执行动画
mNumEt.startAnimation(shake);
} else {
//显示归属地信息
String location = Address.getAddress(numValue, context);
if (!TextUtils.isEmpty(location)) {
mNumTv.setText(location);
}
}
//实现手机震动效果,通过服务获取震动对象,Vibrator
Vibrator vibrator=(Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
//震动时间
vibrator.vibrate(10000);
//震动频率
//2表示根据300,200无限重复震动
//-1表示不重复
/
vibrator.vibrate(new long[]{500,400,300,200}, 2);
//设置震动时间最大值,Integer.MAX_VALUE
//vibrator.vibrate(Integer.MAX_VALUE);
//震动取消
//vibrator.cancel();
}
});
}
}
需要设置震动权限‘
<!-- 手机震动权限 -->
<uses-permission android:name="android.permission.VIBRATE" />
anim下的动画配置xml文件
cycle_7.xml
<?xml version="1.0" encoding="utf-8"?>
<cycleInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:cycles="7" />
shake.xml
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android" android:fromXDelta="0" android:toXDelta="10" android:duration="1000" android:interpolator="@anim/cycle_7" />
查询电话归属地的大致功能就这样了,中间我还添加了抖动动画,系统震动等功能。写了那么久的代码,总结来说,需要的是理解这方法怎么用,知道有这东西,还要重复记忆,知识太多,你不记多记稳,是很难再代码中游刃有余的。晚安。