黑马程序员Android学习笔记——金山卫士项目——第四天

来源:互联网 发布:ww聊天软件下载 编辑:程序博客网 时间:2024/05/02 13:34

主要学习内容:

1)号码归属地查询UI设计

2)号码归属地查询的原理

3)号码归属地查询的代码实现

5)输入框抖动和震动效果

6)来电、去电号码归属地的显示

7)代码注册广播接受者的实现

8)自定义吐司显示号码归属地【实现号码归属地显示效果:加背景、加图片、加文字


首先看一下UI实现的效果:

                                                               

                                                                                   

通过UI效果可以清楚看到我们实现了哪些内容:第一幅图片的查询是查询过程中就在查数据库,动态加载电话号码信息;设置号码归属地是可选的;来电归属地显示效果通过自定义吐司实现不同效果。



查询原理:

第一种:联网查询;

第二种:把数据库 放在本地;

 

------1、百度上输入:手机号码归属地

-----2、数据库的来源,可以在淘宝上购买;

  买的数据不一定是Android下用的数据库;

  如果在Android上使用得自己做一个;把数据写到Android的数据库里;

 


号码归属地的查询实现

1、把数据库拷贝到assets目录并创建包com.itheima.mobilesafe.db.dao 包创建该类

   file:///android_aset/address.db 这种无法访问

   知识回顾:

WebView还可以加载图片String str = "file:///android_asset/icon.png";


在APP刚启动的时候,自动加载数据,将assets中的数据库复制到数据库。

private void copyDb() {//只要你拷贝了一次,我就不要你再拷贝了try {File file=new File(getFilesDir(), "address.db");if(file.exists()&&file.length()>0){//正常了,不需要拷贝了    Log.i(TAG,"正常了,不需要拷贝了");}else{InputStream is=getAssets().open("address.db");FileOutputStream fos=new FileOutputStream(file);byte[] buffer=new byte[1024];int len=0;while(is.read(buffer)!=-1){fos.write(buffer,0,len);}is.close();fos.close();} }catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}


关于电话号码的常识可以到百度百科中搜集资料,非常多的介绍。


关于数据库查询归属地的工具代码如下

package com.example.mobilesafe.db.dao;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;public class NumberAddressQueryUtils {private static String path="data/data/com.example.mobilesafe/files/address.db";                            /* * 产一个号码进来,返回一个归属地回去 */public static String queryNumber(String number){String address=number;//path  把address.db这个数据库拷贝到data/data/包名/files/address.dbSQLiteDatabase database=SQLiteDatabase.openDatabase(path, null,SQLiteDatabase.OPEN_READONLY);//手机号码 13  14  15 16  18//手机号码正则表达式if(number.matches("^1[34568]\\d{9}$")){//手机号码//Cursor cursor=database.rawQuery("select location from data2 where id=(select outkey from data1 where id=?)", new String[]{number.substring(0, 7)});Cursor cursor = database.rawQuery("select location from data2 where id = (select outkey from data1 where id = ?)",new String[] { number.substring(0, 7) });while(cursor.moveToNext()){String location=cursor.getString(0);        address=location;        System.out.println("address"+address);}cursor.close();}else{//其它的电话号码switch(number.length()){case 3:address="匪警号码";break;case 4:address="模拟器";break;//10086case 5:address="客服电话";break;case 7:address="本地号码";break;case 8:address="本地号码";break;default://处理长途电话if(number.length()>10&&number.startsWith("0")){Cursor cursor = database.rawQuery("select location from data2 where area=?)",new String[] { number.substring(1, 3) });while(cursor.moveToNext()){String location=cursor.getString(0);address=  location.substring(0, location.length()-2);}cursor.close();//0855-353253445 cursor = database.rawQuery("select location from data2 where area=?)",new String[] { number.substring(1, 4) });while(cursor.moveToNext()){String location=cursor.getString(0);address=  location.substring(0, location.length()-2);}}break;}}return address;}}


实现输入框输入部分位数号码只能查找该号码归属地:输入框是有状态事件的

private EditText ed_phone;


ed_phone.addTextChangedListener(new TextWatcher() {/* * 文本發生變化的時候回調 */@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {// TODO Auto-generated method stubif(s.length()>=3){//查詢數據庫String address=NumberAddressQueryUtils.queryNumber(s.toString());result.setText(address);}}/* * 文本發生變化之前變化(non-Javadoc) * @see android.text.TextWatcher#beforeTextChanged(java.lang.CharSequence, int, int, int) */@Overridepublic void beforeTextChanged(CharSequence s, int start, int count,int after) {// TODO Auto-generated method stub}/* * 文本發生變化之後回調(non-Javadoc) * @see android.text.TextWatcher#afterTextChanged(android.text.Editable) */@Overridepublic void afterTextChanged(Editable s) {// TODO Auto-generated method stub}});




输入框或者其它组件震动与抖动效果实现

抖动和振动效果_32

-----1、进入模拟器的APIDemo展示点击输入框振动效果(views/animation/shake);

      //shake 动摇;摇动;震动;握手的意思

------2、找系统sdk\samples\android-16\ApiDemos 并导入工程,如果有错误就解决;

-----3、找代码搜索代码

  功能--》布局文件---》代码

-----3、找到抖动代码移植;并演示;

-----4、介绍插入器(interpolator

------5、看APIDemoviews/animation/interpolators 的各种动画

   Accelerate 加速动画  decelerate 减速动画 

Interpolator类似一个函数,计算动画如何播放


          /** * 系统提供的振动服务 */private Vibrator vibrator;

vibrator=(Vibrator) getSystemService(VIBRATOR_SERVICE);
如果输入查询号码为空时查询,实现震动效果:

if(TextUtils.isEmpty(phone)){Toast.makeText(this, "号码为空", 0).show();Animation shake = AnimationUtils.loadAnimation(this, R.anim.shake);ed_phone.startAnimation(shake);//当电话号码为空的时候就去震动手机提醒用户vibrator.vibrate(1000);/*long[] pattern={200,200,300,300,1000,2000};vibrator.vibrate(pattern, -1);*/return;}


震动权限:

<uses-permission android:name="android.permission.VIBRATE"/>




来电号码归属地的显示


引入:1、演示打进电话,说明系统的拨号不能改。2、展示土司;

-----1、创建后台监听来电服务AddressService 并在功能清单文件注册;

检查是否有权限:

<uses-permission android:name="android.permission.READ_PHONE_STATE" /> 

-----1、在AddressService 服务里面注册来电状态

(TelephoneManager)   tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);

-------3、自定义监听类MyPhoneStateListener

private class MyListenerPhone extends PhoneStateListener{@Overridepublic void onCallStateChanged(int state, String incomingNumber) {//state:状态,incomingNumber:来电号码super.onCallStateChanged(state, incomingNumber);            switch(state){            case TelephonyManager.CALL_STATE_RINGING:   //来电铃声想起            //查询数据库的操作            String address=NumberAddressQueryUtils.queryNumber(incomingNumber);            //Toast.makeText(getApplicationContext(), address, 1).show();            myToast(address);            break;            case TelephonyManager.CALL_STATE_IDLE: //电话的空闲状态            //把这个View移出            if(view!=null){            wm.removeView(view);            }                                    break;                        default:            break;            }}}


取消监听:

tm.listen(listener, PhoneStateListener.LISTEN_NONE);listener = null;

-------3、在SettingActivity设置中心里配置设置,当点击开启的时候就启动服务,否则相反。然后演示;

 

    布局文件:

<com.itheima.mobilesafe.ui.SettingItemView        android:id="@+id/siv_show_address"        itheima:title="设置号码归属地显示"        itheima:desc_on="号码归属地显示已经打开"        itheima:desc_off="号码归属地显示已经关闭"        android:layout_width="match_parent"        android:layout_height="wrap_content" />

SettingActivity里的代码:

//设置号码归属地显示

//设置归属地显示控件    siv_show_address=(SettingItemView) findViewById(R.id.siv_show_address);    showAddress=new Intent(this,AddressService.class);    boolean isServiceRunning=ServiceUtils.isServiceRunning(SettingActivity.this, "com.example.mobilesafe.service.AddressService");    if(isServiceRunning){    //监听来电服务是否开启的    siv_show_address.setChecked(true);        }else{    siv_show_address.setChecked(false);    }            siv_show_address.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if(siv_show_address.isChecked()){//变为非选中状态siv_show_address.setChecked(false);stopService(showAddress);}else{//选中状态siv_show_address.setChecked(true);startService(showAddress);}}});


------3、创建一个类ServiceStatusUtils 里面的方法isServiceRunning()校验检查一个服务是否开启;

public class ServiceUtils {/* * 某个服务是否还活着 */public static boolean isServiceRunning(Context context,String serviceName){//校验服务是否还活着ActivityManager am=(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);List<RunningServiceInfo> infos=am.getRunningServices(100);for(RunningServiceInfo info:infos){String name=info.service.getClassName();if(serviceName.equals(name)){return true;}}return false;}}

去电号码归属地的显示

------1、创建广播接收者OutCallReceiver 并注册;监听电话打出去的广播,需要意图;

public class OutCallReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stub//这就是我们拿到的拨出去的电话号码String phone=getResultData();//查询数据库String address=NumberAddressQueryUtils.queryNumber(phone);Toast.makeText(context, address, 1).show();}}


<receiver  android:name="com.itheima.mobilesafe.receiver.OutCallReceiver">  <intent-filter >  <action android:name="android.intent.action.NEW_OUTGOING_CALL"></action>     </intent-filter> </receiver>

------2、需要监听具体意图和权限;

<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>



代码注册广播接收者

 

 

------1、演示功能:演示勾选的来电去电、 进程杀掉时的来电去电;

 

------2、四大组件 :

   activity 、 service content provider

   Broadcast Receiver

 都需要在功能清单文件注册。

Broadcast Receiver不仅可以在功能清单文件注册还可以用代码注册;

 

-------3.移植到AddressService 里和服务生命周期一样。并且演示。

 注册在onCreate()

//代码注册一个广播接收者

receiver = new OutCallReceiver();IntentFilter filter = new IntentFilter();filter.addAction("android.intent.action.NEW_OUTGOING_CALL")registerReceiver(receiver, filter); 取消在onDestroy():

 //代码取消注册一个广播接收者

 unregisterReceiver(receiver); receiver = null;




自定义土司显示归属地

演示:目前的土司的缺陷,比如:无法控制消失、界面丑

-----1、看Toast的源代码

-----2、查看toast布局文件的背景目录:\sdk\platforms\android-16\data\res\values\themes.xml

 

-----3、实现代码 

private WindowManager wm;public void showMyToast(String address) {view = new TextView(this);view.setTextSize(20);view.setTextColor(Color.RED);view.setText(address);WindowManager.LayoutParams params = new WindowManager.LayoutParams();    params.height = WindowManager.LayoutParams.WRAP_CONTENT;        params.width = WindowManager.LayoutParams.WRAP_CONTENT;        params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE              | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE              | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;        params.format = PixelFormat.TRANSLUCENT;        params.type = WindowManager.LayoutParams.TYPE_TOAST;wm.addView(view, params);}


------3、演示发现无法把土司一直停留页面;

 

------4、处理电话挂断情形

case TelephonyManager.CALL_STATE_IDLE:if(view != null){ wm.removeView(view); view = null;}break;

更改归属地的背景风格

准备:安装市场类似软件(金山软件)开启另外一个模拟器

-------1、创建布局文件toast_address.xml  图片(ic_menu_call

-------2、借用市场软件的图片背景(call_locate_gray

 

<LinearLayout     android:background="@drawable/call_locate_gray"    android:gravity="center_vertical"    android:orientation="horizontal" >     <ImageView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@android:drawable/ic_menu_call" />     <TextView        android:id="@+id/tv_location"        android:text="归属地”        android:textSize="20sp"         android:textColor="#000000"        /> </LinearLayout>
<span style="font-size: 12px; font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">------3、演示金山的软件的</span>

-------4、基于ui_setting_item_view自定义点击条目(金山里去找\res\\drawable\jiantou1_pressed.png


-------5、基于SettingItemView 自定义SettingClickView 并只处理标题和内容描述内容;

-------6、在SettingActivity 处理点击事件;

//设置归属地的背景scv_changebg = (SettingClickView) findViewById(R.id.scv_changebg);final String [] items = {"半透明","活力橙","卫士蓝","金属灰","苹果绿"};scv_changebg.setTitle("归属地提示框风格");int which = sp.getInt("which", 0);scv_changebg.setDesc(items[which]);scv_changebg.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {AlertDialog.Builder builder = new Builder(SettingActivity.this);builder.setTitle("归属地提示框风格");int which = sp.getInt("which", 0);builder.setSingleChoiceItems(items, which, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {Editor editor = sp.edit();editor.putInt("which", which);scv_changebg.setDesc(items[which]);editor.commit();dialog.dismiss();}});builder.setNegativeButton("取消", null);builder.show();}});

----------7、在实现具体的逻辑

   int which = sp.getInt("which", 0);//"半透明","活力橙","卫士蓝","金属灰","苹果绿"int [] bgs = {R.drawable.call_locate_white,R.drawable.call_locate_orange,R.drawable.call_locate_blue,R.drawable.call_locate_gray,R.drawable.call_locate_green};view = (View) View.inflate(this, R.layout.toast_address, null);view.setBackgroundResource(bgs[which])

0 0
原创粉丝点击