【0067】【项目实战】-【手机安全卫士】-【7】归属地-通信卫士
1. 去电归属地的查询
1.1 效果

1.2 去电归属地查询的服务
【对于广播的注册方式】
【1】静态的注册方式

【2】动态的注册
【框架】
【源码】



【权限的增加】可以使用先不增加权限,等待程序运行出错之后再重警告信息中查询所需要的权限;


【增加权限】

【效果】去电归属地可以查询出来了;


===========================【通信卫士】==========================================================

2.黑名单功能
2.1 功能及效果展示
【1】进入通信卫士中,可以 针对短信/电话/短信+电话一起进行屏蔽;
并且,拦截的添加内容之后,新添加的内容在第一条出现;






【2】可以删除添加的拦截的条目;

【注意】

【3】需要将设置与业务真正的绑定起来;
2.2 布局的编写
【说明】上面使用的是自定义的样式,然后将文字的显示放在左侧;
下面使用的是listView;

【主页的跳转】

【创建跳转的activity并且配置清单】


【布局文件的填写】

【布局分析】外部使用线性布局,标题使用相对布局;

【布局源码】
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 <RelativeLayout 7 android:layout_width="match_parent" 8 android:layout_height="wrap_content"> 9 <TextView 10 style="@style/TitleStyle" 11 android:gravity="left" 12 android:text="黑名单管理"/> 13 <Button 14 android:id="@+id/bt_add" 15 android:text="添加" 16 android:layout_alignParentRight="true" 17 android:layout_centerVertical="true" 18 android:layout_width="wrap_content" 19 android:layout_height="wrap_content"/> 20 </RelativeLayout> 21 <ListView 22 android:id="@+id/lv_blacknumber" 23 android:layout_width="match_parent" 24 android:layout_height="wrap_content"> 25 </ListView> 26 </LinearLayout>
2.3 数据库的创建
【说明】需要三个字段:_id 自增长的字段 黑名单号码 拦截类型;


2.3.1 表的创建

【说明】括号和 分号一定要使用 英文样式的,否则会出现问题;







2.3.2 在源码中创建类
【说明】在数据的执行语句db.execSQL()语句,一定要现在数据库软件中执行了语句之后再次在源码中书写,否则源码中无法验证语句的正确与否;

【表的创建】

【增删改查包的创建】增删改查类的源码


【注意】单例模式的创建步骤


【增】

【删】

【改】

【查】将查询的数据放入到javabean中

【javabean的封装】共有的成员,没有提供get方法,私有的必须提供get方法;


2.4 junit测试
【说明】对完成的数据库进行测试;
【测试工程的建立】主要目标是复制其中的两段关键的代码;





【源码的增加】将测试工程的配置的两段源码复制到被测试工程的配置文件中;


【测试源码的书写】




【查看插入的数据】


【查看删除的数据】


【查看更新之后的数据】


2.5 黑名单号码数据适配器
【说明】将数据查出来,然后丢到listView的数据适配器中;
【说明】在数据的初始化中,将所有的数据查询出来显示在listView中;


【listView中的单个条目的布局】


【背景选中的效果的切换】




【数据适配器的完善】



【效果】运行之后可以将数据库中的数据显示出来;

2.6 添加按钮对话框
【对话框的设置的效果】

【框架】

【对话框的布局】


【布局源码】
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 <TextView 7 style="@style/TitleStyle" 8 android:background="#fcc" 9 android:text="添加黑名单号码"/> 10 <EditText 11 android:id="@+id/et_phone" 12 android:hint="请输入拦截号码" 13 android:inputType="phone" 14 android:textColor="#000" 15 android:layout_width="match_parent" 16 android:layout_height="wrap_content"/> 17 <RadioGroup 18 android:id="@+id/rg_group" 19 android:orientation="horizontal" 20 android:gravity="center" 21 android:layout_width="match_parent" 22 android:layout_height="wrap_content"> 23 <RadioButton 24 android:id="@+id/rb_sms" 25 android:text="短信" 26 android:textColor="#000" 27 android:checked="true" 28 android:layout_width="wrap_content" 29 android:layout_height="wrap_content"/> 30 <RadioButton 31 android:id="@+id/rb_phone" 32 android:text="电话" 33 android:textColor="#000" 34 android:layout_width="wrap_content" 35 android:layout_height="wrap_content"/> 36 <RadioButton 37 android:id="@+id/rb_all" 38 android:text="所有" 39 android:textColor="#000" 40 android:layout_width="wrap_content" 41 android:layout_height="wrap_content"/> 42 </RadioGroup> 43 <LinearLayout 44 android:layout_width="match_parent" 45 android:layout_height="wrap_content"> 46 <Button 47 android:id="@+id/bt_submit" 48 android:text="确认" 49 android:textColor="#000" 50 android:layout_width="0dp" 51 android:layout_weight="1" 52 android:layout_height="wrap_content"/> 53 <Button 54 android:id="@+id/bt_cancel" 55 android:text="取消" 56 android:textColor="#000" 57 android:layout_width="0dp" 58 android:layout_weight="1" 59 android:layout_height="wrap_content"/> 60 </LinearLayout> 61 </LinearLayout>
【逻辑的完善】

【效果】

2.7 逻辑对话框的逻辑



1 protected void showDialog() { 2 Builder builder = new AlertDialog.Builder(this); 3 4 final AlertDialog dialog = builder.create(); 5 View view = View.inflate(getApplicationContext(), R.layout.dialog_add_blacknumber, null); 6 dialog.setView(view, 0, 0, 0, 0); 7 8 final EditText et_phone = (EditText) view.findViewById(R.id.et_phone); 9 RadioGroup rg_group = (RadioGroup) view.findViewById(R.id.rg_group); 10 11 Button bt_submit = (Button) view.findViewById(R.id.bt_submit); 12 Button bt_cancel = (Button)view.findViewById(R.id.bt_cancel); 13 14 //监听其选中条目的切换过程 15 rg_group.setOnCheckedChangeListener(new OnCheckedChangeListener() { 16 @Override 17 public void onCheckedChanged(RadioGroup group, int checkedId) { 18 switch (checkedId) { 19 case R.id.rb_sms: 20 //拦截短信 21 mode = 1; 22 break; 23 case R.id.rb_phone: 24 //拦截电话 25 mode = 2; 26 break; 27 case R.id.rb_all: 28 //拦截所有 29 mode = 3; 30 break; 31 } 32 } 33 }); 34 35 bt_submit.setOnClickListener(new OnClickListener() { 36 @Override 37 public void onClick(View v) { 38 //1,获取输入框中的电话号码 39 String phone = et_phone.getText().toString(); 40 if(!TextUtils.isEmpty(phone)){ 41 //2,数据库插入当前输入的拦截电话号码 42 mDao.insert(phone, mode+""); 43 //3,让数据库和集合保持同步(1.数据库中数据重新读一遍,2.手动向集合中添加一个对象(插入数据构建的对象)) 44 BlackNumberInfo blackNumberInfo = new BlackNumberInfo(); 45 blackNumberInfo.phone = phone; 46 blackNumberInfo.mode = mode+""; 47 //4,将对象插入到集合的最顶部 48 mBlackNumberList.add(0, blackNumberInfo); 49 //5,通知数据适配器刷新(数据适配器中的数据有改变了) 50 if(mAdapter!=null){ 51 mAdapter.notifyDataSetChanged(); 52 } 53 //6,隐藏对话框 54 dialog.dismiss(); 55 }else{ 56 ToastUtil.show(getApplicationContext(), "请输入拦截号码"); 57 } 58 } 59 }); 60 61 bt_cancel.setOnClickListener(new OnClickListener() { 62 @Override 63 public void onClick(View v) { 64 dialog.dismiss(); 65 } 66 }); 67 68 dialog.show(); 69 }
【效果】添加不同类型的号码的时候可以相应增加不同的拦截类型;
2.8 黑名单的删除
【说明】先找条目,再找到相关的垃圾桶按钮,然后响应事件;

【源码框架】

【源码逻辑】

【效果】可以删除,并且最后的数据库的数据只剩下两条;


【数据库的访问方式】

3. listView的优化
3.1 存在的bug





【出现问题的原因】该方法被调用了不止100遍;view 对象至少创建了100个;

【优化】

【再优化】直接将返回的值赋值给convertView即可;view在中间没有实际的作用,只是中间变量的替换,没有实际意义;


【复用的机制】

3.2 存在的优化2 Viewholder的使用
【存在的问题】

【解决问题的方法】


【解决办法】相当于一个临时的存储控件,一旦查找好的就可以存在当前的空间ViewHolder中,以便于下次复用;

3.3 ViewHolder的源码编写






【测试效果】内存的剩余比例不改变;一直都是6%;

3.5 优化三


4. 分页查询
4.1 分页加载20条数据
【说明】在用户的需求中,有时候不需要全部加载所有的数据,只需要加载部分的数据;
只需要在加载的时候,读取数据库的时候只读取部分数据即可;




【增加分页查询的源码】


【bug】运行报错-未明确的指定查询的字段;

【修改】指定查询的字段

【效果】只加载了20条数据;再下滑无法出现加载的条目;

4.2 上滑加载更多


【滚动状态的监听】重点是mIsLoad的理解;



【查询数据库中数据的总个数】






【效果】滚动条在不断的减小,因为数据加载更多了;



【源码】/mobilesafe74/src/com/itheima/mobilesafe74/activity/BlackNumberActivity.java
1 package com.itheima.mobilesafe74.activity; 2 3 import java.util.List; 4 5 import com.itheima.mobilesafe74.R; 6 import com.itheima.mobilesafe74.db.dao.BlackNumberDao; 7 import com.itheima.mobilesafe74.db.domain.BlackNumberInfo; 8 import com.itheima.mobilesafe74.utils.ToastUtil; 9 10 import android.app.Activity; 11 import android.app.AlertDialog; 12 import android.app.AlertDialog.Builder; 13 import android.os.Bundle; 14 import android.os.Handler; 15 import android.text.TextUtils; 16 import android.view.View; 17 import android.view.View.OnClickListener; 18 import android.view.ViewGroup; 19 import android.widget.AbsListView; 20 import android.widget.AbsListView.OnScrollListener; 21 import android.widget.BaseAdapter; 22 import android.widget.Button; 23 import android.widget.EditText; 24 import android.widget.ImageView; 25 import android.widget.ListView; 26 import android.widget.RadioGroup; 27 import android.widget.RadioGroup.OnCheckedChangeListener; 28 import android.widget.TextView; 29 30 //1,复用convertView 31 //2,对findViewById次数的优化,使用ViewHolder 32 //3,将ViewHolder定义成静态,不会去创建多个对象 33 //4,listView如果有多个条目的时候,可以做分页算法,每一次加载20条,逆序返回 34 35 public class BlackNumberActivity extends Activity { 36 private Button bt_add; 37 private ListView lv_blacknumber; 38 private BlackNumberDao mDao; 39 private List<BlackNumberInfo> mBlackNumberList; 40 private MyAdapter mAdapter; 41 private int mode = 1; 42 private boolean mIsLoad = false; 43 private int mCount; 44 45 private Handler mHandler = new Handler(){ 46 public void handleMessage(android.os.Message msg) { 47 //4,告知listView可以去设置数据适配器 48 if(mAdapter == null){ 49 mAdapter = new MyAdapter(); 50 lv_blacknumber.setAdapter(mAdapter); 51 }else{ 52 mAdapter.notifyDataSetChanged(); 53 } 54 }; 55 }; 56 57 class MyAdapter extends BaseAdapter{ 58 @Override 59 public int getCount() { 60 return mBlackNumberList.size(); 61 } 62 63 @Override 64 public Object getItem(int position) { 65 return mBlackNumberList.get(position); 66 } 67 68 @Override 69 public long getItemId(int position) { 70 return position; 71 } 72 73 @Override 74 public View getView(final int position, View convertView, ViewGroup parent) { 75 // View view = null; 76 /* if(convertView == null){ 77 view = View.inflate(getApplicationContext(), R.layout.listview_blacknumber_item, null); 78 }else{ 79 view = convertView; 80 }*/ 81 82 //1,复用convertView 83 84 //复用viewHolder步骤一 85 ViewHolder holder = null; 86 if(convertView == null){ 87 convertView = View.inflate(getApplicationContext(), R.layout.listview_blacknumber_item, null); 88 //2,减少findViewById()次数 89 //复用viewHolder步骤三 90 holder = new ViewHolder(); 91 //复用viewHolder步骤四 92 holder.tv_phone = (TextView) convertView.findViewById(R.id.tv_phone); 93 holder.tv_mode = (TextView)convertView.findViewById(R.id.tv_mode); 94 holder.iv_delete = (ImageView)convertView.findViewById(R.id.iv_delete); 95 //复用viewHolder步骤五 96 convertView.setTag(holder); 97 }else{ 98 holder = (ViewHolder) convertView.getTag(); 99 } 100 101 holder.iv_delete.setOnClickListener(new OnClickListener() { 102 @Override 103 public void onClick(View v) { 104 //1,数据库删除 105 mDao.delete(mBlackNumberList.get(position).phone); 106 //2,集合中的删除 107 mBlackNumberList.remove(position); 108 //3,通知数据适配器刷新 109 if(mAdapter!=null){ 110 mAdapter.notifyDataSetChanged(); 111 } 112 } 113 }); 114 115 holder.tv_phone.setText(mBlackNumberList.get(position).phone); 116 int mode = Integer.parseInt(mBlackNumberList.get(position).mode); 117 switch (mode) { 118 case 1: 119 holder.tv_mode.setText("拦截短信"); 120 break; 121 case 2: 122 holder.tv_mode.setText("拦截电话"); 123 break; 124 case 3: 125 holder.tv_mode.setText("拦截所有"); 126 break; 127 } 128 return convertView; 129 } 130 } 131 //复用viewHolder步骤二 132 static class ViewHolder{ 133 TextView tv_phone; 134 TextView tv_mode; 135 ImageView iv_delete; 136 } 137 138 @Override 139 protected void onCreate(Bundle savedInstanceState) { 140 super.onCreate(savedInstanceState); 141 setContentView(R.layout.activity_blacknumber); 142 143 initUI(); 144 initData(); 145 } 146 147 private void initData() { 148 //获取数据库中所有电话号码 149 new Thread(){ 150 public void run() { 151 //1,获取操作黑名单数据库的对象 152 mDao = BlackNumberDao.getInstance(getApplicationContext()); 153 //2,查询部分数据 154 mBlackNumberList = mDao.find(0); 155 mCount = mDao.getCount(); 156 157 //3,通过消息机制告知主线程可以去使用包含数据的集合 158 mHandler.sendEmptyMessage(0); 159 } 160 }.start(); 161 } 162 163 private void initUI() { 164 bt_add = (Button) findViewById(R.id.bt_add); 165 lv_blacknumber = (ListView) findViewById(R.id.lv_blacknumber); 166 167 bt_add.setOnClickListener(new OnClickListener() { 168 @Override 169 public void onClick(View v) { 170 showDialog(); 171 } 172 }); 173 174 //监听其滚动状态 175 lv_blacknumber.setOnScrollListener(new OnScrollListener() { 176 //滚动过程中,状态发生改变调用方法() 177 @Override 178 public void onScrollStateChanged(AbsListView view, int scrollState) { 179 // OnScrollListener.SCROLL_STATE_FLING 飞速滚动 180 // OnScrollListener.SCROLL_STATE_IDLE 空闲状态 181 // OnScrollListener.SCROLL_STATE_TOUCH_SCROLL 拿手触摸着去滚动状态 182 183 if(mBlackNumberList!=null){ 184 //条件一:滚动到停止状态 185 //条件二:最后一个条目可见(最后一个条目的索引值>=数据适配器中集合的总条目个数-1) 186 if(scrollState == OnScrollListener.SCROLL_STATE_IDLE 187 && lv_blacknumber.getLastVisiblePosition()>=mBlackNumberList.size()-1 188 && !mIsLoad){ 189 /*mIsLoad防止重复加载的变量 190 如果当前正在加载mIsLoad就会为true,本次加载完毕后,再将mIsLoad改为false 191 如果下一次加载需要去做执行的时候,会判断上诉mIsLoad变量,是否为false,如果为true,就需要等待上一次加载完成,将其值 192 改为false后再去加载*/ 193 194 //如果条目总数大于集合大小的时,才可以去继续加载更多 195 if(mCount>mBlackNumberList.size()){ 196 //加载下一页数据 197 new Thread(){ 198 public void run() { 199 //1,获取操作黑名单数据库的对象 200 mDao = BlackNumberDao.getInstance(getApplicationContext()); 201 //2,查询部分数据 202 List<BlackNumberInfo> moreData = mDao.find(mBlackNumberList.size()); 203 //3,添加下一页数据的过程 204 mBlackNumberList.addAll(moreData); 205 //4,通知数据适配器刷新 206 mHandler.sendEmptyMessage(0); 207 } 208 }.start(); 209 } 210 } 211 } 212 213 } 214 215 //滚动过程中调用方法 216 @Override 217 public void onScroll(AbsListView view, int firstVisibleItem, 218 int visibleItemCount, int totalItemCount) { 219 220 } 221 }); 222 } 223 224 protected void showDialog() { 225 Builder builder = new AlertDialog.Builder(this); 226 227 final AlertDialog dialog = builder.create(); 228 View view = View.inflate(getApplicationContext(), R.layout.dialog_add_blacknumber, null); 229 dialog.setView(view, 0, 0, 0, 0); 230 231 final EditText et_phone = (EditText) view.findViewById(R.id.et_phone); 232 RadioGroup rg_group = (RadioGroup) view.findViewById(R.id.rg_group); 233 234 Button bt_submit = (Button) view.findViewById(R.id.bt_submit); 235 Button bt_cancel = (Button)view.findViewById(R.id.bt_cancel); 236 237 //监听其选中条目的切换过程 238 rg_group.setOnCheckedChangeListener(new OnCheckedChangeListener() { 239 @Override 240 public void onCheckedChanged(RadioGroup group, int checkedId) { 241 switch (checkedId) { 242 case R.id.rb_sms: 243 //拦截短信 244 mode = 1; 245 break; 246 case R.id.rb_phone: 247 //拦截电话 248 mode = 2; 249 break; 250 case R.id.rb_all: 251 //拦截所有 252 mode = 3; 253 break; 254 } 255 } 256 }); 257 258 bt_submit.setOnClickListener(new OnClickListener() { 259 @Override 260 public void onClick(View v) { 261 //1,获取输入框中的电话号码 262 String phone = et_phone.getText().toString(); 263 if(!TextUtils.isEmpty(phone)){ 264 //2,数据库插入当前输入的拦截电话号码 265 mDao.insert(phone, mode+""); 266 //3,让数据库和集合保持同步(1.数据库中数据重新读一遍,2.手动向集合中添加一个对象(插入数据构建的对象)) 267 BlackNumberInfo blackNumberInfo = new BlackNumberInfo(); 268 blackNumberInfo.phone = phone; 269 blackNumberInfo.mode = mode+""; 270 //4,将对象插入到集合的最顶部 271 mBlackNumberList.add(0, blackNumberInfo); 272 //5,通知数据适配器刷新(数据适配器中的数据有改变了) 273 if(mAdapter!=null){ 274 mAdapter.notifyDataSetChanged(); 275 } 276 //6,隐藏对话框 277 dialog.dismiss(); 278 }else{ 279 ToastUtil.show(getApplicationContext(), "请输入拦截号码"); 280 } 281 } 282 }); 283 284 bt_cancel.setOnClickListener(new OnClickListener() { 285 @Override 286 public void onClick(View v) { 287 dialog.dismiss(); 288 } 289 }); 290 291 dialog.show(); 292 } 293 }
【源码】/mobilesafe74/src/com/itheima/mobilesafe74/db/dao/BlackNumberDao.java
1 package com.itheima.mobilesafe74.db.dao; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import android.content.ContentValues; 7 import android.content.Context; 8 import android.database.Cursor; 9 import android.database.sqlite.SQLiteDatabase; 10 11 import com.itheima.mobilesafe74.db.BlackNumberOpenHelper; 12 import com.itheima.mobilesafe74.db.domain.BlackNumberInfo; 13 14 public class BlackNumberDao { 15 private BlackNumberOpenHelper blackNumberOpenHelper; 16 //BlackNumberDao单例模式 17 //1,私有化构造方法 18 private BlackNumberDao(Context context){ 19 //创建数据库已经其表机构 20 blackNumberOpenHelper = new BlackNumberOpenHelper(context); 21 } 22 //2,声明一个当前类的对象 23 private static BlackNumberDao blackNumberDao = null; 24 //3,提供一个静态方法,如果当前类的对象为空,创建一个新的 25 public static BlackNumberDao getInstance(Context context){ 26 if(blackNumberDao == null){ 27 blackNumberDao = new BlackNumberDao(context); 28 } 29 return blackNumberDao; 30 } 31 32 /**增加一个条目 33 * @param phone 拦截的电话号码 34 * @param mode 拦截类型(1:短信 2:电话 3:拦截所有(短信+电话)) 35 */ 36 public void insert(String phone,String mode){ 37 //1,开启数据库,准备做写入操作 38 SQLiteDatabase db = blackNumberOpenHelper.getWritableDatabase(); 39 40 ContentValues values = new ContentValues(); 41 values.put("phone", phone); 42 values.put("mode", mode); 43 db.insert("blacknumber", null, values); 44 45 db.close(); 46 } 47 48 /**从数据库中删除一条电话号码 49 * @param phone 删除电话号码 50 */ 51 public void delete(String phone){ 52 SQLiteDatabase db = blackNumberOpenHelper.getWritableDatabase(); 53 54 db.delete("blacknumber", "phone = ?", new String[]{phone}); 55 56 db.close(); 57 } 58 59 /** 60 * 根据电话号码去,更新拦截模式 61 * @param phone 更新拦截模式的电话号码 62 * @param mode 要更新为的模式(1:短信 2:电话 3:拦截所有(短信+电话) 63 */ 64 public void update(String phone,String mode){ 65 SQLiteDatabase db = blackNumberOpenHelper.getWritableDatabase(); 66 67 ContentValues contentValues = new ContentValues(); 68 contentValues.put("mode", mode); 69 70 db.update("blacknumber", contentValues, "phone = ?", new String[]{phone}); 71 72 db.close(); 73 } 74 75 /** 76 * @return 查询到数据库中所有的号码以及拦截类型所在的集合 77 */ 78 public List<BlackNumberInfo> findAll(){ 79 SQLiteDatabase db = blackNumberOpenHelper.getWritableDatabase(); 80 81 Cursor cursor = db.query("blacknumber", new String[]{"phone","mode"}, null, null, null, null, "_id desc"); 82 List<BlackNumberInfo> blackNumberList = new ArrayList<BlackNumberInfo>(); 83 while(cursor.moveToNext()){ 84 BlackNumberInfo blackNumberInfo = new BlackNumberInfo(); 85 blackNumberInfo.phone = cursor.getString(0); 86 blackNumberInfo.mode = cursor.getString(1); 87 blackNumberList.add(blackNumberInfo); 88 } 89 cursor.close(); 90 db.close(); 91 92 return blackNumberList; 93 } 94 95 /** 96 * 每次查询20条数据 97 * @param index 查询的索引值 98 */ 99 public List<BlackNumberInfo> find(int index){ 100 SQLiteDatabase db = blackNumberOpenHelper.getWritableDatabase(); 101 102 Cursor cursor = db.rawQuery("select phone,mode from blacknumber order by _id desc limit ?,20;", new String[]{index+""}); 103 104 List<BlackNumberInfo> blackNumberList = new ArrayList<BlackNumberInfo>(); 105 while(cursor.moveToNext()){ 106 BlackNumberInfo blackNumberInfo = new BlackNumberInfo(); 107 blackNumberInfo.phone = cursor.getString(0); 108 blackNumberInfo.mode = cursor.getString(1); 109 blackNumberList.add(blackNumberInfo); 110 } 111 cursor.close(); 112 db.close(); 113 114 return blackNumberList; 115 } 116 117 /** 118 * @return 数据库中数据的总条目个数,返回0代表没有数据或异常 119 */ 120 public int getCount(){ 121 SQLiteDatabase db = blackNumberOpenHelper.getWritableDatabase(); 122 int count = 0; 123 Cursor cursor = db.rawQuery("select count(*) from blacknumber;", null); 124 if(cursor.moveToNext()){ 125 count = cursor.getInt(0); 126 } 127 128 cursor.close(); 129 db.close(); 130 return count; 131 } 132 133 /** 134 * @param phone 作为查询条件的电话号码 135 * @return 传入电话号码的拦截模式 1:短信 2:电话 3:所有 0:没有此条数据 136 */ 137 public int getMode(String phone){ 138 SQLiteDatabase db = blackNumberOpenHelper.getWritableDatabase(); 139 int mode = 0; 140 Cursor cursor = db.query("blacknumber", new String[]{"mode"}, "phone = ?", new String[]{phone}, null, null,null); 141 if(cursor.moveToNext()){ 142 mode = cursor.getInt(0); 143 } 144 145 cursor.close(); 146 db.close(); 147 return mode; 148 } 149 }
5. 黑名单服务的开启
【使用设置中心的选择框确实有效】


【布局文件的增加】

【开启黑名单的服务】




【说明】一行代码的含义可以代表两行代码,更简洁;



【测试效果】


6.拦截短信和拦截电话
6.1 思路分析
【短信的广播】有序广播,在源头进行拦截;


6.2 短信的拦截






【效果测试】先开启拦截服务,发送拦截号码的短信无法接收;


6.3 电话的拦截
6.3.1 aidl 的使用




【源码查看】


【移植源码】

【aidl文件的拷贝】需要拷贝到同名的包下;


【BUG1】需要拷贝另外的一个aidl文件;



拷贝之后没有错误了;
6.3.2 反射的调用



【源码】使用反射

【BUG】


【错误原因】mDao没有赋值;

【解决方法】只要在onCreate一开始就赋值;后期,不管接收短信还是接受来电就都不会是空指针;

【BUG】增加权限


【效果】拨打已经加入黑名单的电话无法来电,直接被挂断;
【说明】如果说做的完美的话应该将通话记录在数据库中也查询到,然后将其删除;

7. 清除通话记录
7.1 找到联系表中的通话记录


7.2 联系人数据库的访问
【说明】需要使用内容解析者;

【在源码中找到对应的内容解析者】查看authorities项对应的设置内容,然后组合Uri的地址;




【源码】

【增加权限】


7.3 BUG
【bug】之前的拨打的8次电话信息抹掉了,但是现在的刚发生的记录没有抹掉;


【解决方法】




【说明】一旦服务关闭,则没有必要再次对数据库的表的内容进行观察;
当然也没有必要对电话进行监听了;

【效果】

浙公网安备 33010602011771号