目录
-
创建svn仓库步骤(创业公司需要): 5
-
使用插件将项目和svn关联步骤: 5
-
将项目提交到svn仓库步骤: 5
-
代码包结构划分: 5
-
Splash页面 5
-
给TextView加阴影颜色 5
-
去掉标题栏,隐藏系统通知栏 5
-
获取应用程序版本号 6
-
连接服务器(HttpURLConnection方式的网络请求) 6
-
写xml/json形式接口的步骤 6
-
两种调试接口方式的步骤 6
-
获取服务器返回的数据步骤 6
-
将流信息转化为字符串的工具StreamUtils的步骤 6
-
使用JSONObject解析json数据 7
-
子线程中要更新主线程UI时会用的2种方式 7
-
对话框功能步骤(弹出,取消,升级) 7
17.SystemClock.sleep(2000)和Thread.sleep(2000)的区别
18.保证用户总共只能看2秒钟Splash界面的实现(根据时间差决定睡几秒)
19.在主界面HomeActivity点击返回键返回SplashActivity的解决
20.源于afinal的xUtils框架 -
下载最新版本(完整的后台+移动端的下载最新版本步骤) 8
18.下载进度的实现(当前进度/总进度)
19.ADB server didn’t ACK, * failed to start daemon *的解决 -
安装最新版本(调用PackageInstaller.apk帮助安装) 8
20.用户应用和系统应用区别
21.查看android系统应用PackageInstaller.apk源码
22.Android系统源码和第三方sdk开发平台
23.使用隐式意图打开其他应用的activity(其中可选内容提供者content或文件file形式)
24.setData和setType相互覆盖的冲突解决(intent.setDataAndType)
25.setDataAndType(Uri data,String type)第一个参数选用Uri.parse或Uri.fromFile
26.点击PackageInstallerActivity的cancel按钮后跳转到SplashActivity的解决(改用startActivityForResult,并重写onActivityResult)
27.没有最新版本即版本号相同不升级时splash界面停留2s后跳转到主界面的实现
28.连接失败后的处理(提示服务器异常并跳转到主界面的实现)
29.对捕获的3个异常分别细化处理,方便定位异常(URL异常,IO异常,JSON异常) -
4种上下文区别: 8
30.凡是跟Dialog对话框有关的操作,必须使用activity.this,不能使用getApplicationContext
31.在自定义控件或单元测试中使用的是getContext()
32.getApplicationContext是父类,this是子类
33.编译问题和运行时问题 -
给apk打包签名的目的和步骤 8
34.查看一款apk是否打包签名过的方法 -
使用GridView的步骤 8
-
动态设置GridView条目的图片+文字步骤(用两个数组来存放图片和文字,根据position从两个数组中分别获取对应的图片和文字,) 8
23.view.findViewById和findViewById的区别 -
TextView跑马灯效果的两种实现方式(给textview设置属性或自定义textView控件) 8
-
GridView条目点击事件 9
24.怎样知道一个方法或参数是什么意思 -
创建一个Activity的步骤: 9
-
自定义组合控件实现“提示更新”条目布局的步骤 9
27.自定义组合控件添加布局文件的两种方式
28.实现一条线的效果 -
自定义组合控件的点击事件实现(通过自定义组合控件提供的方法来更改自定义组合控件中控件的值)
-
根据CheckBox状态展示不同描述信息 9
-
CheckBox拦截“获取焦点和点击事件”的解决 9
-
使用Sharedpreferences保存状态,回显状态 9
31.关闭提示更新,返回主界面,再次进入设置中心,提示更新又变成打开的解决(使用sp保存状态,回显状态)
32.关闭提示更新,退出应用,再次打开应用,更新版本对话框还会弹出的解决(根据提醒更新的状态决定更新版本对话框是否弹出)
33.sp的edit.commit()和edit.apply()区别
34.改用自定义属性来设置自定义组合控件中控件的值 ***(上边是通过自定义组合控件提供的方法来更改自定义组合控件中控件的值) -
实现设置密码对话框功能(dialog中添加密码输入框editText) 10
35.View.OnClickListener和DialogInterface.OnClickListener(“密码对话框”按钮和版本升级对话框的按钮,位置不同)
36.为实现密码对话框的隐藏对话框功能,显示对话框时选择builder.create().show();方式
37.TextUtils.isEmpty可判断2种情况的空 -
保存密码,回显密码的操作 10
-
将设置密码的对话框进行低版本UI兼容 10
-
用MD5对保存的密码进行加密实现防盗作用 10
-
InputType属性实现隐藏或显示密码 11
-
复杂的界面跳转逻辑 11
38.判断是否第一次进入页面
39.使用系统图片好处 -
selector状态选择器 11
-
style样式抽取 12
40.使用.9图片时报NullPointerException
41.使用了样式抽取后的下一步按钮改成设置完成按钮
42.复杂界面切换逻辑处理 (finish(),上一步下一步抽取,onKeyDown)*** -
界面切换动画overridePendingTransition(必须在startActivity或者finish之后执行)
-
使用手势识别器来滑动页面(靠手指滑动来切换这4个界面) 14
43.解决点击第四个界面的设置完成后跳转到第一个界面的问题(应该跳转到手机防盗界面) -
使用shape画圆角矩形白色图片 14
-
给shape图片设置状态选择器 14
-
绑定SIM卡 15
-
重启手机,发送报警短信 15
47.保存输入的手机号码并在上个页面进行回显 -
使用内容提供者contentProvider获取系统联系人 15
48.对获取系统联系人的功能进行单元测试 -
选择联系人界面获取联系人并展示 16
50.两个Activity之间传递数据的操作(必须将StartActivity改用StartActivityForResult) 16
51.onActivityResult获取数据后需为空判断,避免物理返回键程序崩溃(因为物理返回键功能中没有new intent去存储数据)
52.空指针异常的两种情况(null.方法或参数为null)
51.耗时操作放在主线程中出现卡顿现象的处理(将加载联系人数据库操作放到子线程执行)
耗时操作放在子线程后出现的空指针异常处理(使用handler,将setAdapter放到handler的handleMessage中)
53.重开子线程导致空白界面的用户体验处理(使用进度条显示正在加载,掩盖耗时操作导致的用户不良体验,在子线程之前显示,显示数据之后隐藏) ***
54.使用XUtils以注解方式初始化控件
55.异步加载框架实现子线程之前,之中,之后的功能(通过模板设计模式封装子线程之前,之中,之后执行的方法)
56.异步加载框架原理 面试常问,要会写框架
57.查看系统怎么定义进度条样式
52.自定义样式步骤 (修改进度条样式) 18
53.使用intent的隐式意图打开系统联系人界面(固定写法,需要可复制)
54.checkbox状态未保存的处理----设置回显操作(已开启/关闭防盗保护功能)*** -
指令发送的2种方式:消息推送 短信 19
55.手机重启之后SIM不一致时发送报警短信的实现
56.SmsReceiver中的onReceive中接收解析短信的实现
57.android中3种定位方式(ip,基站,gps定位) -
定位功能:GPS追踪的实现 19
58.国家保密插件火星坐标
56.播放报警音乐的实现(调整音量到最大,重复播放问题) 20
58.重复发送指令出现重复播放解决(把MedioPlayer声明成成员变量并加static静态) -
远程锁屏一键锁屏的实现 20
59.超级管理员权限与root权限区别
60.根据api文档实现获取超级管理员权限
61.用代码激活超级管理员权限(直接跳转到设置中心激活超级管理员界面,方便用户)
62.注销超级管理员权限的实现(不注销时app无法卸载,用户体验差)
63.远程删除数据的实现(写完远程删除数据或远程锁屏记得判断发件人sender是不是安全号码,否则别人恶意给你发条远程删除数据指令,手机就会恢复出厂设置) -
根据号码查询号码归属地数据库操作(拷贝数据库,打开数据库,查询号码归属地)
59.根据号码查询号码归属地数据库的单元测试
60.使用Xutils的IOUtils处理关流异常
59.用正则表达式匹配电话号码,身份证是否分别相同的逻辑 -
正则表达式语法
-
动态显示号码归属地操作(监听输入框输入状态变化的操作 addTextChangedListener(watcher))
61.参数CharSequence就是一个String类型 -
EditText抖动效果
-
让手机震动的效果(按摩器功能)
-
来电显示号码归属地(通过TelephoneManager实现监听来电显示操作)
-
自定义一个Toast (查看Toast源码,自定义样式) 21
64.toast中View.inflate和LayoutInflater.from(context)的区别 -
在设置中心实现显示/隐藏号码归属地条目功能 21
-
动态获取服务是否开启(解决显示号码归属地条目进行回显时不能用sp的问题) 21
-
拨打电话时显示号码归属地的实现(代码注册广播接收者) 22
-
动态修改归属地提示框的风格(颜色半透明,活力橙,卫士蓝,金属灰,苹果绿) 22
69.实现单选框功能以及单选框回显操作 -
更改归属地提示框显示位置(params.x的含义) 22
-
随着手指移动而移动之设置触摸监听事件 *** 22
-
动态设置号码归属地提示框位置 *** 23
72.归属地提示框位置回显(回显位置) ***
73.判断控件是否移出屏幕 *** -
多击事件(双击事件)*** 23
-
电话界面控件随着手指移动而移动 *** 23
-
发射小火箭功能(触摸setOnTouchListener 帧动画 渐变动画)
-
创建黑名单数据库
76.对黑名单数据库的单元测试 -
对黑名单数据库的操作(增删改查) 24
-
bean类和map集合保存数据的优缺点 24
78.ListView复用缓存(重用convertView,复用findViewById,固定写法要会) 24 -
在dialog对话框中添加输入框和单选按钮 25
-
ListView的分批加载数据(复用缓存(重用convertView复用findViewById),分批加载同时使用比较好)
-
打开/关闭黑名单拦截(短信拦截)*** 26
-
拦截电话(会写反射机制,会写AIDL远程服务)*** 26
-
同一刻对数据库读/写操作,数据库报错了 *** 26
-
删除通话记录(知道内容观察者怎么去用)*** 26
84.获取应用程序信息 26
85.软件管理界面(MyAsyncTask,ListView复用缓存) 26
86.用户程序和系统程序拆分 26
87.浮动显示程序多少个(ListView的滑动监听) 27
88.气泡PopWindow 27
89.给气泡添加缩放动画和渐变动画 27
90.卸载应用程序(对比安装,都是隐式意图) 28
91.启动应用程序 28
92.详情(隐式意图) 28
93.短信分享(隐式意图) 28
95.获取可用空间 28
96.获取正在运行的进程的信息 28
97.进程管理界面(和软件管理界面基本一样) 28
98.刷新界面两种方式 28
99.全选/反选/清理 29
100.获取正在运行的进程个数,空闲内存信息,总内存信息 29
101.根据sdk版本不同重载不同的方法 29 -
Widgets桌面控件(就是一个广播接收者) 29
103.反编译 (获取apk源码的方式) 30
104.“每隔一段时间”的实现方式 30 -
锁屏清理进程 31
-
屏幕适配常用的两种方式 31
-
创建快键方式 31
-
launcher桌面应用 31
-
软件锁功能 32
-
时时刻刻的2种实现方式 32
-
关于软件锁的数据库操作 32
-
ListView长按点击事件 32
-
点击物理返回键,又进入输入密码界面的bug 32
-
Activity给Service传递数据 33
-
Activity4种启动模式 33
-
让app不在手机的最近列表显示 33
-
解锁的数据库优化操作 33
-
短信备份/还原短信 33
-
将数据保存到文件中的步骤 34
-
两种进度条 34
-
回调方法 34
-
ExpandableListView(可扩展的ListView) 35
-
抽屉效果的两种实现方式 35
124.自定义ProgressBar样式(图层layer-list) 35
125.展示列表信息的方式(ListView,ScrollView) 35
126.扫描效果 36 -
旋转动画 36
-
给服务发送消息或数据的方式 36
-
获取签名信息 36
-
拷贝数据库,查询数据库 36
-
用命令行将apk运行到模拟器中 36
-
扫描病毒,杀死病毒(卸载apk) 36
-
Fragment的使用 37
-
进度条的操作 37
-
写入缓存,获取缓存,显示缓存(aidl远程通信,反射),清理缓存 37
-
在Fragment中用ListView显示缓存 37
-
SD卡清理 37
-
全局bug收集 37
-
代码混淆 38
-
广告 38
-
创建svn仓库步骤(创业公司需要):
定位:安全卫士Day01 02课
2.使用插件将项目和svn关联步骤:
定位:安全卫士day01 02课
3.将项目提交到svn仓库步骤:
定位:安全卫士day01 02课
4.代码包结构划分:
定位:安全卫士第1天 03课
5.Splash页面
定位:安全卫士第1天 有demo
6.给TextView加阴影颜色
定位:安全卫士第1天 04课
实现:
<TextView
android:id=“@+id/textView1”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_centerInParent=“true”
android:text=“版本号:1.0”
android:shadowColor="#ffff00"
android:shadowDx="1"
android:shadowDy="1"
android:shadowRadius="2"
/>
7.去掉标题栏,隐藏系统通知栏
定位:安全卫士第1天 04课
去掉标题栏实现:
在清单文件中的application的theme属性中使用本地的样式文件,
在本地的样式文件style.xml中添加一个item
在清单文件的application中添加:
android:theme=“@android:style/theme.Black.NoTitleBar.Fullscreen”
NoTitleBar是将标题栏隐藏掉
Fullscreen是将标题上边的系统通知栏也隐藏掉
8.获取应用程序版本号
定位:安全卫士第1天 05课
9.连接服务器(HttpURLConnection方式的网络请求)
定位:安全卫士第1天 06课
10.写xml/json形式接口的步骤
定位:安全卫士第1天 07课
11.两种调试接口方式的步骤
定位:安全卫士第1天 07课
12.获取服务器返回的数据步骤
定位:安全卫士第1天 08课
使用HttpURLConnection方式请求网络时,返回的是InputStream流信息
需要用BufferReader读取流信息转化为字符流(BufferReader)
再转化为String类型的数据(也就是json串)
再解析json数据后获取到每个字段数据
13.将流信息转化为字符串的工具StreamUtils的步骤
定位:安全卫士第1天 08课
涉及到读流写流的操作
字符流读取流BufferReader和字符流写入流StringWriter
以及使用StringWriter的好处: sw.toString()直接就会得到存放在StirngWriter流里的字符串信息
14.使用JSONObject解析json数据
定位:安全卫士第1天 08课
15.子线程中要更新主线程UI时会用的2种方式
定位:安全卫士第1天 09课
调用RunOnUiThread方法
用Handler发送一个消息,然后在Handler里边去处理
这里选用了Handler方式:
1.在子线程的run方法中获取一个消息载体
Message message = Message.obtain();
2.在需要的地方设置标识,并将标识声明成成员变量
protected static final int MSG_UPDATE_DIALOG = 1;
message.what = MSG_UPDATE_DIALOG;
3.在成员变量处new一个Handler,在它的handleMessage方法中判断msg的标识是否和 相应的标志MSG_UPDATE_DIALOG一致,如果一致,在这里实现弹出对话框功能
4.最后在finally里让Handler去给主线程发送消息,更改相应的UI
16.对话框功能步骤(弹出,取消,升级)
定位:安全卫士 第1天 09,10课
1.new一个AlertDialog.Builder
AlertDialog.Builder builder = new Builder(this);
2.通过builder分别去:
setTitle 设置标题
setIcon 设置图标
setMessage 设置描述信息
setPositiveButton 设置升级按钮
setNegativeButton 设置取消按钮
show() 显示对话框
细节处理:
1)设置点击空白处时对话框不可消失
setCancelable(false)
2)延迟两秒显示对话框
SystemClock.sleep(2000)
3)保证用户总共只能看2秒钟
3.1在连接服务器之前获取开始时间
long startTime = System.currentTimeMillis();
3.2在Handler发送消息之前,获取结束时间endTime
long endTime = System.currentTimeMillis();
3.3根据时间差决定睡几秒
时间差dTime如果小于2秒钟,就让它去睡2000-dTime时间
17.下载最新版本
定位:day01 10课
开源框架:1.afinal-master
2.xUtils-master (源于afinal框架)
这里采用了XUtils框架来实现下载功能
完整的后台+移动端使用Xutils框架实现下载最新版本的步骤:(7,8步属于后台的步骤)
1)拷贝Xutils的jar包
2)new一个HttpUtils()
3)用httpUtils调用download(url,target,callback)方法
4)在回调监听RequestCallBack中重写onSuccess,onFailure,onLoading方法
5)在onLoading方法中显示下载进度
6)要将下载的apk保存到sd卡中,需要添加用户权限,还要保证sd卡已经挂载
7)写接口地址apkurl
8)生成2.0的最新版本apk并放到服务器中
18.安装最新版本
定位:day01 11课
打开其他应用的Activity,一般是通过隐式意图实现
- 4种上下文的区别:
定位:day01 13课
20.打包签名步骤:
定位:day01 14课
21.使用GridView的步骤
定位:day01 15课 day02 02课
1.在布局文件中添加GridView控件
2.初始化控件,并给它设置Adapter为MyAdapter
3.创建MyAdapter
4.给GridView去setOnItemClickListener增加条目点击事件OnItemClickListener
22.动态设置GridView条目的图片+文字步骤:
定位:day01 15课
23.TextView跑马灯效果的两种实现方式
定位:day02 02课
1.在布局文件中通过给TextView增加属性,来实现滚动的效果
2.自定义TextiView实现自动获取焦点功能,并在布局文件中使用自定义控件
24.GridView条目点击事件
定位:day02 03课
涉及setOnItemClickListener,switch判断,创建一个activity的步骤
25.创建一个Activity的步骤:
定位:day02 03课
26.自定义组合控件实现“提示更新”条目布局的步骤:
定位:day02 04课
还涉及添加布局的两种方式
27.自定义组合控件的点击事件实现
定位:day02 05课
28.根据CheckBox状态展示不同描述信息
定位:day02 05课
根据系统提供的isChecked()进行判断
29.CheckBox拦截“获取焦点和点击事件”的问题
checkbox控件中添加两个属性:
android:clickable=“false”
android:focusable=“false”
30.使用Sharedpreferences保存状态,回显状态
定位:day02 06课
1.创建sp
2.使用sp保存状态
3.根据回显的状态重新动态设置初始化状态
31.根据提醒更新的状态决定更新版本对话框是否弹出
定位:day02 06课
1.创建sp
2.使用sp回显状态,根据回显的状态判断是否弹出版本更新对话框
32.以自定义属性的方式设置自定义组合控件中控件的值
定位:day02 07课
1.在values目录下建一个attrs.xml文件(固定写法)
2.到布局文件activity_setting.xml中使用自定义属性
3.在自定义组合控件settingView.java代码中获取指定属性的值,设置给相应的控件,使自定义属性有意义
4.在SettingActivity的unpdate()方法中注释掉相应“初始化自定义组合控件中的控件的值”的代码
33.实现设置密码对话框功能
定位:day02 08课
1.Dialog里边没法设置输入框EditText,但是有builder.setView(view)
可以用View.inflate()加载包含EditText的布局文件,给我们返回View对象
然后将view对象传递给setView
2.这里给按钮设置点击事件用的是View.OnClickListener而不是DialogInterface.OnClickListener
通过builder.setPositiveButton设置按钮,是在dialog中创建了一个按钮
这里是通过btn_cancel.setOnClickListener设置按钮,按钮在dialog_setpassword.xml中,是在View对象中创建了一个按钮
3.用了View.OnClickListener会导致dialog.dismiss()时,没有dialog这个参数,所以隐藏对话框这里不用builder.show(),而用了builder.create().show()的分步形式,即:
private AlertDialog dialog;
dialog = builder.create();
dialog.show();
这样就可以用这个dialog去dismiss()
34.保存密码,回显密码的操作
定位:day02 08课09课
保存密码,其实就是保存到SharedPrefrences中
回显密码,就是TextUtils.isEmpty(sp.getString(“password”, “”))
35.将设置密码的对话框进行低版本兼容
定位:day02 10课
1.将高版本中的界面背景刻意改成白色,这样在低版本时,界面也就是白色了
2.解决低版本中对话框上部黑色的凸起
将builder.setView(view)改成dialog.setView();
效果一样,但是dialog.setView()有个重载的方法
即:
dialog.setView(view, viewSpacingLeft, viewSpacingTop, viewSpacingRight, viewSpacingBottom)
viewSpacingLeft:表示距离对话框内左边框的距离
viewSpacingTop:表示距离对话框内上边框的距离
viewSpacingRight:表示距离对话框内右边框的距离
viewSpacingBottom:表示距离对话框内底边框的距离
都改成0即可,即:
dialog.setView(view, 0, 0, 0, 0);
将其他四个参数全部设置为0,即可解决黑色凸起
36.用MD5对保存的密码进行加密
Day02 11课
防盗作用
在sharedpreference中保存密码时,不能直接保存成明文,应该用MD5加密,保存成密文
使用MD5Utils工具类,
在保存密码的地方
将edit.putString(“password”,password);
改成edit.putString(“password”,MD5Utils.digestPassword(password));
在判断两个密码是否一致处
将:
if(password.equal(sp_password))
改成if(MD5Utils.digestPassword(password).equals(sp_password))
因为保存的密码已经用MD5设置成了密文,所以输入的密码也需要MD5加密一次,两个密文去比较,所以需要在两个地方都加密
37.隐藏或显示输入的密码
Day02 12课,13课,14课
定义计数器int count =0;
如果count对2求余恒等于0,setInputType(1)显示密码,否则setInputType(129)隐藏密码
最后计数器count++累加一下
对2求余是否等于0只有两种可能,正好对应显示隐藏状态,还可用true/flase等好几种方式
Inputtype属性值为十六进制的0
Textpassword属性值为十六进制的129
显示/隐藏密码原理:
实际上是对setInputType属性的值进行动态的修改
38.复杂的界面跳转逻辑
定位:Day02 15课
工作中有类似手机防盗模块的功能及界面跳转逻辑的流程功能时,可仿照
即:管家助手中的很多流程都可使用
39.状态选择器
定位:Day02 16课
使用步骤:
1.在res下 -> 新建drawable ->新建 button.xml
2.找到布局文件中的button按钮,将状态选择器button.xml设置成背景图片即可(创建状态选择器后,任何需要用到的按钮,都可以将状态选择器button.xml设置成背景图片使用)
android:background="@drawable/button"
function_greenbutton_pressed 按下时显示的图片
function_greenbutton_normal 默认的图片
40.样式抽取
定位:Day03 02课
下一步按钮在很多地方使用到了,相同的操作可以向上抽取,简化代码
样式抽取步骤:
1.打开res -> values -> styles(对比下一步按钮,将属性抽取到styles中形成样式抽取)
Button按钮:
<Button
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:text=“下一步”
android:layout_alignParentRight=“true”
android:layout_alignParentBottom=“true”
android:drawableRight=“@drawable/next”
android:background=“@drawable/button”
android:padding=“5dp”
android:οnclick=“next” >
在styles.xml中形成的样式抽取:
<style name="next">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:text">下一步</item>
<item name="android:layout_alignParentRight">true</item>
<item name="android:layout_alignParentBottom">true</item>
<item name="android:drawableRight">@drawable/next</item>
<item name="android:background">@drawable/button</item>
<item name="android:padding">5dp</item>
<item name="android:onClick">next</item>
</style>
2.在布局文件的Button控件中使用(找到每一个被样式抽取的button按钮,将其中属性全部删除后,添加如下)
41.界面切换动画
定位:day03 05课
步骤:
1.res -> anim ->创建 xxxx.xml,创建的时候选择平移动画translate
setup_enter_next.xml
<?xml version="1.0" encoding="utf-8"?>
setup_exit_next.xml
<?xml version="1.0" encoding="utf-8"?>
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"
android:toXDelta="-100%"
android:duration="500"
>
<!-- fromXDelta : 从哪个位置开始移动
toXDelta : 移动到哪个位置
duration : 持续时间
-->
</translate>
2.在代码中调用
// 跳转到第三个界面
Intent intent = new Intent(this, SetUp3Activity.class);
startActivity(intent);
finish();
overridePendingTransition(R.anim.setup_enter_next, R.anim.setup_exit_next);
注意:
必须在startActivity或者finish方法之后执行
enterAnim : 新界面进入的动画
exitAnim : 旧界面退出的动画
42.手势识别器
定位:day03 06课
实现了界面的切换动画效果之后,还想实现靠手指滑动来切换界面的效果
用手势识别器实现步骤:
1.在基类的onCreate中new一个GestureDetector
2.创建一个监听MyOnGestureListener,在它里边实现手势
3.重写界面的触摸事件onTouchEvent方法,将手势识别器添加到界面触摸事件中
//界面的触摸事件
@Override
public boolean onTouchEvent(MotionEvent event) {
detector.onTouchEvent(event);//将手势识别器添加到界面的触摸事件中
return super.onTouchEvent(event);
}
43.使用shape画一个圆角矩形白色图片
用代码去画一张图片,也就是用shape去画一张图片
步骤:
在res/drawable目录下创建shape_drawable.xml, 选择shape
shape_drawble.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<!-- shape:图片的形状 rectangle : 矩形 oval : 椭圆 line:线 ring:环形-->
<!-- corners : 圆角的角度 -->
<corners android:radius="10dp"/>
<!-- solid : 颜色-->
<solid android:color="#ff0000"/>
<!-- stroke : 边框 dashWidth : 点的宽度 dashGap : 点与点之间的距离
<stroke android:width="3dp" android:color="#00ff00" android:dashWidth="3dp" android:dashGap="5dp"/>
-->
<!-- gradient : 渐变 angle :旋转的角度-->
<gradient android:startColor="#00ff00" android:centerColor="#ff0000" android:endColor="#0000ff"/>
</shape>
44.给shape图片设置状态选择器
定位:day02 08课
只要图片都能使用状态选择器,所以还可以给shape图片增加状态选择器:
1.在drawable下创建一个shape_drawable_press.xml按下的图片
设置开始颜色换成红色,右边颜色换成绿色
2.在drawable下创建一个shape_drawable_button.xml(shape_drawable_press就是按下的图片)
3.给activity_lostfind.xml的“重新进入设置向导”的textview设置背景为shape_drawable_button便可将shape图片的状态选择器设置上去
45.绑定SIM卡
定位:day02 09课
1.初始化自定义组合控件SettingView
2.给自定义组合控件SettingView添加点击事件
3.获取电话的管理者TelephonyManager
4.获取SIM卡序列号,唯一标示,返回的就是sim卡
5.保存SIM卡
代码:
//绑定SIM卡
//1.获取电话的管理者
TelephonyManager tel = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
//获取SIM卡序列号
String sim = tel.getSimSerialNumber();
//2.保存SIM卡
edit.putString(“sim”, sim);
这里需要添加权限:获取电话的状态
46.重启手机,发送报警短信
Day03 10课
要重启手机时发现SIM卡是否发生了变化,要用广播接收者监听系统重启手机的广播事件
1.创建一个广播接收者BootCompletedReceiver
2.在清单文件中配置广播接收者时,在action属性中添加监听手机重启的广播事件
3.在onReceive方法执行观察SIM是否发生变化,发送报警短信的操作
4.监听手机重启的广播事件是侵犯用户隐私的,需要添加权限,即:
android permission RECEIVE_BOOT_COMPLETED
还需要android permission.SEND_SMS
android permission.READ_PHONE_STATE
注意:
通过TelephonyManager.getSimSerialNumber获取sim卡
通过SmsManager.getDefault().sendTextMessage(sp.getString(“safenum”, “5556”), null, “da ge wo bei dao le,help me!!!”, null, null)发送短信
47.获取联系人操作
点击“选择联系人”按钮,进入选择联系人界面,用户点击一个联系人,就把联系人号码显示到EditText输入框,点击下一步时,保存联系人
系统联系人是一个系统应用,所有联系人都保存在contacts2.db数据库中,要想获取联系人,就需要去查询这个数据库,但这个数据库的权限“–rw–rw----”,是不可读不可写
如何获取另外一个应用程序的数据?通过内容提供者去查询数据
1.获取内容解析者
2.将内容提供者的地址生成查询地址
3.通过内容解析者查询数据,返回一个cursor
4.解析cursor
5.根据contact_id查询view_data表中的数据,返回一个cursor
6.解析新cursor
7.根据mimetype判断data1的类型
8.将数据添加到集合中,分别关闭两个cursor
9.清单文件中添加权限:
android permission.READ_CONTACTS
48.选择联系人界面
定位:Day03 13课
将上边获取的联系人全部展示到我们写的选择联系人界面
用listview展示联系人
使用注解初始化控件,相当于通过反射实现findviewbyid的形式
AsyncTask异步框架
49.打开系统联系人界面
定位:Day04 05课
系统当中也有一个联系人界面,介绍下怎么打开系统联系人界面来获取相应操作
也是通过intent去跳转的,只不过这个跳转到的是我们系统的联系人界面
这种方式用的不多,一般用的比较多的是47.48
50.两个Activity之间传递数据的操作
Day03 14课
要想实现的操作是:
点击SetUp3Activity中的“选择联系人”按钮,
跳转到ContactsActivity,点击“某个联系人”,
然后把ContactsActivity销毁掉,同时返回并把号码传递到setUp3Activity
然后把号码回显到安全号码输入框中
这个涉及到两个activity之间传递数据的操作:
1.在SetUp3Activity中使用startActivityForResult跳转到ContactsActivity
//跳转到选择联系人界面
//Intent intent = new Intent(this,ContactsActivity.class);
//在当前的activity退出的时候,会调用之前activity的onActivityResult方法
startActivityForResult(intent, 0);
2.在ContactsActivity中,给listview增加条目点击事件,并进行数据设置传递
//回传数据
Intent intent = new Intent();
intent.putExtra(“num”, list.get(position).get(“phone”));
//设置结果的方法,会将结果返回给调用它的SetUp3Activity
setResult(0, intent);
//移出界面
finish();
3.重写setup3activity中onActivityResult方法,获取传递过来的数据
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (data!=null) {
//获取ContactsActivity传递过来的数据,null.方法 参数为null
String num = data.getStringExtra(“num”);
//将获取的数据显示到输入框中
et_setup3_safenum.setText(num);
}
}
51.耗时操作放在主线程中出现卡顿现象的处理
Day04 02课 03课
解决方式1:用子线程+handler方式
问题1:在ContactActivity中获取联系人操作是耗时操作,不应该放到主线程里边
解决:
可以将加载数据库的操作放到子线程中执行
新问题:
但是在子线程中去获取联系人list时,下边setAdapter就不能在原来那里去写了,因为在Myadapter中的getCount方法中,用到了一个return list.size();
当我们把获取联系人list的操作放到子线程中去执行,在原来的地方去setAdapter时,我们这的list.size()会报空指针异常,提示这个list还没有填充完数据
新解决:
在ContactsActivity中的成员变量处重写一个Handler
在子线程中获取完联系人list之后,用handler去发送一个消息
然后将setAdapter放到handler中的handleMessage中
问题2:重开子线程导致空白界面的用户体验处理
跳转到选择联系人界面内容部分一片空白,过了3秒才显示出联系人
解决2:使用进度条显示正在加载,来掩盖耗时操作导致的用户不良体验
在子线程运行之前,让这个进度条显示出来,然后在子线程中获取完联系人之后,在handleMessage中显示数据(setAdapter)之后隐藏进度条
总结:
loading.setVisibility(View.VISIBLE)这个是在子线程之前执行的
获取联系人操作,即:
list = ContactsEngine.getAllContacts(getApplicationContext());是在子线程之中执行的
执行完之后,发送了一个消息给Handler,在Handler之中显示完数据之后,隐藏进度条, 那handler这个操作其实是在子线程之后执行的
解决方式2:异步加载框架AsyncTask(模板设计模式,相当于将子线程+handler进行了封装)
写一个AsyncTask.java,在这里边分别创建抽象方法preTask,doinBack,postTask,代表在子线程之前执行的方法,在子线程之中执行的方法,在子线程之后执行的方法
创建一个方法execute方法,代表执行,在execute方法中:调用一下在子线程之前执行的方法preTask,创建一个子线程,子线程中调用doinBack方法并给handler发送一个消息
创建一个handler,handleMessage中调用postTask方法
面试题:
异步加载框架的原理:
其实它内部就是用了子线程来实现,封装了在子线程之前执行的方法onPreExecute,在子线程之中执行的方法doInBackground,在子线程之后执行的方法onPostExecute,通过在execute方法中调用onPreExecute,然后在创建子线程来执行我们要实现的耗时操作,其实就是在子线程中调用doInBackground实现耗时操作,最后通过给handler发送一个消息,到handler中去执行onPostExecute
百度的面试:异步加载框架在运行几个之后就跟new线程一样了? 5个
有些面试的时候,让你写一个异步加载框架,其实就是让你写个MyAsyncTask.java
52.自定义样式步骤 (自定义ProgressBar样式)
Day04 04课
修改进度条样式步骤:
1.在res/drawable中 新建progressbar_drawable.xml来写我们的自定义样式
progressbar_drawable.xml
<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/shenmabg"
android:pivotX="50%"
android:pivotY="50%"
/>
2.在控件中使用相应的属性,覆盖系统样式文件中的属性,即修改ProgressBar的样式
activity_contact.xml
android:indeterminateDrawable=“@drawable/progressbar_drawable”
53.CheckBox的使用步骤:
Day04 06课
实现第4个界面“4.恭喜您,设置完成”
这个界面就是一个checkbox,点击checkbox,变成“你已经开启防盗保护”,再点击就是“你没有开启防盗保护”,我们只需要保存状态就可以了
1.通过findViewById找到checkbox控件
2.给checkbox设置点击事件setOnCheckedChangeListener
3.在onCheckedChanged方法中根据状态isChecked进行相应的设置
isChecked为true,开启防盗保护,设置checkbox的文本"您已经开启了防盗保护",给checkbox设置setChecked为true,调用edit.putBoolean(“protected”, true)保存状态为true
为false,关闭防盗保护,“您还没有开启了防盗保护”,给checkbox设置setChecked为false,调用edit.putBoolean(“protected”, false)保存状态为false
4.根据保存的防盗保护状态在onCreate中进行回显操作
54.指令发送的2种方式:消息推送 短信
Day04 07课 08课
涉及广播接收者BroadCastReceiver
步骤:
1.服务器发送,客户端接收,这种方式就叫做消息推送,用通知栏形式来展示
2.通过短信的方式接收指令,接收解析短信来实现相应的操作
1)创建一个广播接收者SmsReceiver.java
要接收解析短信,需要去设置一个“短信到来的广播接收者”,接收我们的短信
2)清单文件中注册时,action设置为监听“短信到来的广播接收者”
3)在onReceive方法中接收解析短信,如果短信内容是指令,就拦截这条短信,根据短信内容不同的指令实现各自操作
55.定位功能:GPS追踪的实现
Day04 09课 10课
涉及服务service
步骤:
1.获取位置的管理者locationManager
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
2.获取定位方式
//2.1获取所有的定位方式,true:返回可用的定位方式
List providers = locationManager.getProviders(true);
//2.2获取最佳的定位方式
Criteria criteria = new Criteria();
//设置可以定位海拔,true:表示可以定位海拔
criteria.setAltitudeRequired(true);//只有gps可以定位海拔
String bestProvider = locationManager.getBestProvider(criteria, true);
3.定位
locationManager.requestLocationUpdates(bestProvider, 0, 0, new MyLocationListener());
4.创建MyLocationListener,并实现四个方法
这里需要的是“获取精确的位置,获取海拔,获取经纬度”,即:
//定位位置发生变化的时候调用
//location : 当前的位置
@Override
public void onLocationChanged(Location location) {
location.getAccuracy();//获取精确的位置
location.getAltitude();//获取海拔
double latitude = location.getLatitude();//获取纬度,平行
double longitude = location.getLongitude();//获取经度
tv_main_location.setText("longitude:"+longitude+" latitude:"+latitude);
}
GPS定位操作属于耗时操作,四大组件都是在主线程当中,所以不能直接写在广播接收者的onReceive方法中,创建一个服务GPSService,将定位的操作移植到这个GPSService中
在SmsReceiver.java中接收到GPS追踪指令后,开启服务GPSService.java,接收定位操作
56.播放报警音乐
Day04 13课
1.拷贝ylzs.mp3到res/raw文件夹下
2.获取音量的管理者AudioManager
3.调用setStreamVolume将系统的音量调整到最大
3.获取MediaPlayer
4.调用start()方法播放报警音乐
57.远程锁屏 一键锁屏
Day04 14课
1.在布局文件中给button按钮增加点击事件的属性android:onClick=“locknow”
2.在activity中创建这个点击方法locknow
3.在lock方法中获取一个设备的管理者DevicePolicyManager,并调用系统的lockNow锁屏方法
获取超级管理员权限步骤:
1.创建一个广播接收者Admin.java,继承自DeviceAdminReceiverDeviceAdminReceiver
2.到清单文件中配置
3.在res这个目录下,创建一个device_admin_sample.xml
这个文件中就是超级管理员能执行的操作,密码,锁屏,禁用摄像头等都有
最后,超级管理员权限你想用,必须得去激活,打开模拟器的设置中心Settings/Security/Device administrators,找到mobilesafexian02,点击点击Activate即可激活
58.查询号码归属地数据库操作
定位:Day05 02,03,04,05课
1.将数据库address.db导入项目的assets目录
2.然后将assets目录下的address.db数据库拷贝到手机file目录中
3.AddressDao中打开并查询数据库
59.用正则表达式匹配电话号码,身份证
定位:Day05 06课
60.动态显示号码归属地操作
定位:Day05 07课
监听输入框EditText输入状态变化的操作
输入电话号码,点击查询按钮可以查询出号码归属地
用户体验不好,改为:用户输入完号码之后,直接显示出号码归属地
监听输入框输入状态变化的操作addTextChangedListener(watcher)
onTextChanged 当输入内容改变完成的时候调用
beforeTextChanged 输入之前调用
afterTextChanged 输入之后调用
在onTextChanged方法中,根据输入的内容直接查询下号码归属地数据库,就可以将归属地查询出来,然后再显示到textView上
61.EditText抖动效果
定位:Day05 07课
借鉴自源码APIDemos
62.让手机震动的效果
定位:Day05 08课
vibrator.vibrate(100);//振动100毫秒
63.来电显示号码归属地
定位:Day06 10课
需要监听来电显示状态,一般监听什么什么状态,都用的是广播接收者,这里例外,可以用TelephoneManager监听电话的来电显示状态
监听是时时刻刻都去监听,那就要写在服务中,开启服务,不管什么时候来电,都能显示出号码归属地
telephonyManager.listen(myPhoneStateListener,PhoneStateListener.LISTEN_CALL_STATE)
要时时刻刻监听,接下来就到SplashActivity.java中的onCreate方法中去开启服务,即:
// 开启服务
Intent intent = new Intent(this,AddressService.class);
startService(intent);
64.自定义一个Toast (自定义样式)
定位:Day05 11课 12课
65.显示/隐藏号码归属地
定位:Day05 12课
将SplashActivity中开启服务的代码注释,在SettingActivity中去开启/关闭AddressService服务
和设置中心已经做过的打开/关闭提示更新一模一样
66.动态获取服务是否开启
定位:Day05 12 13课
对设置中心的“显示号码归属地”条目进行回显操作
以前都保存在sp里边,这次不能保存在sp里边了
因为在settings/apps/running/手机卫士西安2号处有个stop,点击stop可以把服务关闭掉
需要动态获取服务是否开启(进程管理者ActivityManager)
并将在onCreate方法中调用的address()方法移动到onStart方法中调用
onStart方法是界面可见的时候调用
67.拨打电话时显示号码归属地(代码注册广播接收者)
定位:Day06 02课
在服务中用代码注册广播接收者去监听外拨电话:
1.在addressservice.java中,创建一个广播接收者MyOutGoingCall
2.在oncreate方法中new一个广播接受者,同时创建一个intentfilter,并注册广播接受者
3.在ondestory方法中注销广播接受者
4.在广播接受者的onreceive方法中执行相应的操作
68.动态修改归属地提示框的风格(颜色)
定位:Day06 03课
单选框也是对话框
设置单选按钮的操作setSingleChoiceItems(items,checkedItem,listener)
参数items:单选按钮的文本数组,即:
String[] items = { “半透明”, “活力橙”, “卫士蓝”, “金属灰”, “苹果绿” };
参数checkedItem:写成sp.getInt(“which”,0)
参数listener:new DialogInterface.OnClickListener()
69.更改归属地提示框显示位置
定位:Day06 04课
params.x的含义:
//设置控件的显示位置, | 表示前后两个属性都有效果,两个相对应的属性,默认是左边和上边
params.gravity = Gravity.LEFT | Gravity.TOP;
params.x = 100;//x表示的不是坐标,而是距离边框的距离,根据Gravity来设置的,LEFT就是距离左边框的距离,ringht就是距离右边框的距离
params.y = 100;//y和x是相同的含义,根据top或者bottom来时设置距离顶部或者底部的距离
70.随着手指移动而移动之设置触摸监听事件
定位:Day06 06,07课
第一步:按住控件,记录开始x和y的坐标,startX,startY,这个坐标是手指按住的坐标
第二步:移动,获取移动到的新位置的x和y的坐标,newX,newY
第三步:计算移动的偏移量 dX = newX - startX,dY=newY-startY;(计算移动的偏移量,其实就是计算移动的距离)
第四步:让控件移动相应的偏移量,重新绘制控件
第五步:更新开始的x和y的坐标 startX=newX,startY=newY
给控件设置触摸监听事件setOnTouchListener在onTouch方法中用swith判断 MotionEvent.ACTION_DOWN(按下)
MotionEvent.ACTION_MOVE(移动)
MotionEvent.ACTION_UP(抬起)
71.动态设置号码归属地提示框位置
定位:Day06 08课
1.在DragViewActivity中的setTouch方法中的onTouch方法中抬起事件ACTION_UP中用sp去保存控件的坐标x,y
2.到AddressService中showToast方法中回显x,y,即:
params.x = sp.getInt(“x”, 100);
params.y = sp.getInt(“y”, 100);
72.多击事件(双击事件)
Day06 08课
73.电话界面控件随着手指移动而移动
Day06 09课
用到的也是触摸事件setOnTouchListener
当坐标移出屏幕,就给坐标设置极限值
74.发射小火箭功能
Day06 13课
小火箭发射是一个触摸事件
火焰是一个帧动画animationDrawable,小火箭发射之后出来的云是一个渐变动画AlphaAnimation
帧动画使用步骤:
1.res -> anim -> rocket.xml
2.控件使用
android:background=“@anim/rocket”
3.代码中使用
animationDrawable = (AnimationDrawable) iv_rocket.getBackground();
//开启动画
animationDrawable.start();//在低版本中不太兼容
渐变动画使用步骤:
1.创建一个渐变动画
alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setDuration(2000);
2.开启动画
iv_rocket_m.startAnimation(alphaAnimation);//开始执行动画
3.清除动画
iv_rocket_t.clearAnimation();//消除动画
75.创建数据库
定位:Day07 02课
创建黑名单数据库BlacNunOpenHelper.java
76.数据库的操作(增删改查)
定位:Day07 03 04课
getReadableDatabase()也可以进行写入操作,只不过是不加锁的操作,线程不安全,好处是效率很高,所以它一般是读取数据库用,对数据库操作一般不会使用它
getWritableDatabase() 加锁的,线程安全的,但效率比较低,因为它一般都是对一条数据进行操作,相对于查询会有很多条来说的话,一般用来写入或修改,一般用于对数据库进行操作使用
对数据库的操作增,删,改,一般用getWritableDatabase()方法来获取数据库
查不是对数据库的操作,一般用getReadableDatabase()方法来获取数据库
77.bean类和map集合保存数据的优缺点
查询出来的全部数据一般都是存放到集合中,所以这里返回值写成 List,注意,这里E需要一个类型,查询出来包括blacknum,mode类型,既然全部数据两个字段都要查询出来,那在开发中一般会来个bean类来存储这个数据
bean对象就是用来存放数据用的,这个数据存放进去之后还要拿出来去用,要为后边考虑,如果后边去执行设置数据操作,比如在activity中用到了这个list集合,里边存放的是这个数据,拿出这个集合之后,点击一个条目跳转到另一个界面时要把数据带过去,如果用map怎么带过去,如果用bean对象形式,可以直接拿过去用,写成bean类这种形式是为了我们操作数据用
右键source,选择Generate Constructors from SuperClass,把它的构造方法拿过来
右键Source,选择Generate Constructor using Fields…,将它两个参数的构造方法也拿过来
是为了方便添加数据用
右键source,选择Generate toString()…将它的toString方法也拿过来,toString方法是为了后边方便后边测试打印数据使用
78.ListView复用缓存
Day07 05 06 07课
在通讯卫士条目中有:添加黑名单到数据库,并展示黑名单号码到ListView中
数据库操作属于耗时操作,所以这里用到了MyAsyncTask异步加载框架
preTask方法中加载进度条,来掩饰耗时操作
doinBack方法中获取黑名单耗时操作
postTask方法中setAdater刷新界面显示数据,并隐藏进度条
ListView复用缓存步骤总结如下:
1.创建一个盒子ViewHolder,并在盒子中声明出布局文件中的控件
2.在getView中声明盒子
3.判断是否能够复用缓存(判断convertView是否为null)
4.当convertView为null的时候创建盒子 5.同时将view.findviewbyid封装到盒子中 6.将盒子绑定到view对象中
(4,5,6步是判断不能够复用缓存时的操作)
7.如果能复用缓存,将盒子从复用的view中拿出来去用
8.复用盒子中的view对象进行相应的操作,其实就是将前一个条目的控件值覆盖调用
(7,8是复用缓存)
79.在dialog对话框中添加输入框和单选按钮
Day07 08课
主要是点击删除的图片按钮后,弹出一个对话框的操作,属于比较好的用户体验
刷新界面的方式:
myadapter.notifyDataSetChanged();
这里dialog的操作和手机防盗条目处的输入密码对话框相似,可拷贝复制
输入的是电话号码而不是密码,所以将EditText的inputType属性值由textPassword改为text,同时将提示文字hint属性值改为:请输入拦截号码
拦截模式的三个单选框可以用RadioGroup包裹3个RadioButton来实现
将每次输入的黑名单号码添加到listView的第一个item上:
1.List集合的add方法有个重载的方法,即:
list.add(location, object);
参数1:location : 将参数2添加到哪个位置,
参数2:object:添加的数据
要把电话号码添加到第一个位置,那list集合第一个位置是啥?就是0
所以参数1写0,参数2直接用上边添加的数据,即:
list.add(0, new BlackNuminfo(blacknum, mode));
2.查询时应该倒序查询
因为添加完数据再次进入通讯卫士界面,添加的数据显示在最下方,解决办法:在查询全部数据库的操作中的query中,将最后一个参数orderBy由null改为倒叙查询
一般我们是根据id来倒序查询,即: “_id desc”, 默认写成null就是升序查询
Cursor cursor = database.query(BlacNunOpenHelper.DB_NAME, new String[]{“blacknum”,“mode”}, null, null, null, null, “_id desc”);//desc倒序查询
80.ListView的分批加载数据
BlacknumDao中创建查询部分数据的方法getPartBlackNum(),同样用BlackNuminfo这个bean类来保存查询出来的数据,方法的查询语句中的查询条件参数selectionArgs
直接new一个String数组,将查询子段的条数limit放进来,起始位置offset放进来,并分别加个空的字符串巧妙的转化为string类型
//查询部分数据
Cursor cursor = database.rawQuery(“select blacknum,mode from info order by _id desc limit ? offset ?”, new String[]{maxnum+“”,startindex+“”});
这样哪里调用getPartBlackNum()方法,哪里就需要给我传递这两个参数过来
要实现当用户滑动到最后一条数据时,再加载20条数据,就要去监听下listView的滑动状态,给ListView添加滑动事件setOnScrollListener
在listview滚动状态改变的时候调用的方法onScrollStateChanged(AbsListView view, int scrollState)中,参数AbsListView就是listView,参数scrollState: 是滚动的状态
listView滚动的状态有:
SCROLL_STATE_IDLE : 空闲,不滚动的时候状态(在打电话那块见过IDLE)
SCROLL_STATE_TOUCH_SCROLL : 缓慢滚动状态
SCROLL_STATE_FLING : 惯性滚动
81.打开/关闭黑名单拦截
这里的短信拦截功能和前边SmsReceiver.java中讲的“接收解析短信"最后打印出发件人sender,一模一样
打开/关闭黑名单拦截的布局和设置中心的“显示号码归属地”一样
短信拦截的广播要用代码注册,设置中心的“显示号码归属地”也是用代码注册的广播
82.拦截电话
要想拦截电话,首先要知道电话的状态
前边在AddressService中的onCreate方法中设置过监听电话的状态,可参考
1.在blacknumservice中的onCreate方法中去监听电话的状态
2.拦截电话
3.挂断电话(通过反射去实现)
83.同一刻对数据库读/写操作,数据库报错了
定位:Day08 01课
使用同步锁synchronized(b)解决
83.删除通话记录(知道内容观察者怎么去用)
定位:Day08 02课
和获取联系人操作一致,都是用内容提供者对数据库contact2.db进行操作
解决删除的只是以前的通话记录,无法删除新打进来的通话记录
用内容观察者:内容观察者的onChange方法,当内容变化时会调用它,所以将delete操作放到这个onChange方法中执行
84.获取应用程序信息
定位:Day08 03课
85.软件管理界面(MyAsyncTask,ListView复用缓存)
定位:Day08 04课
获取应用程序信息属于耗时操作,用以前自己封装的异步加载框架MyAsyncTask
1.在activity中使用异步加载框架MyAsyncTask去加载数据
2.在adapter使用listview缓存复用操作,并填充数据
86.用户程序和系统程序拆分
Day08 04课
1.在异步加载框架中,将list分拆成userappinfos和systemappinfos,分别存放用户程序和系统程序
2.在adapter的getcount中将原来的list.size()改成userappinfos.size+systemappinfos.size
3.因为用户程序和系统程序要从不同的集合中去拿,所以在getview中要根据显示的条目数据去判断是从userAppInfos去拿数据还是从systemAppInfos中去拿数据
4.将数据分别显示了,但是还要添加textiview显示
1)在getcount中添加两个条目的长度
2)在getview中添加textview条目
3)因为添加了两个条目,所以要改变获取数据的方式
87.浮动显示程序多少个(ListView的滑动监听)
Day08 05课
在工作中也会用到,是比较常见的用法,一般都是分类显示用
给listview添加滑动监听setOnScrollListener
滑动状态改变时调用的方法
onScrollStateChanged(AbsListView view, int scrollState)
滑动的时候调用的方法
onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount)
//view : listview
//firstVisibleItem : 界面可见的第一个条目的位置
//visibleItemCount : 界面可见条目的个数,多少可见
//totalItemCount : 总条目数 包含可见和不可见所有条目,listview的所有条目个数
88.气泡PopWindow
Day08 07课
View contentView = View.inflate(getApplicationContext(), R.layout.popu_window, null);
//3.1.创建气泡
popupWindow = new PopupWindow(contentView, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
//3.3.获取条目位置,同时将气泡显示在条目位置上
int[] location = new int[2];//保存x和y的坐标
view.getLocationInWindow(location);//获取x和y的坐标,将x和y的坐标保存到int数组中
//获取坐标
int x = location[0];
int y = location[1];
//3.2.显示气泡
popupWindow.showAtLocation(parent, Gravity.LEFT|Gravity.TOP, x+50, y);
89.给气泡添加缩放动画和渐变动画
Day08 08课
popwindow不能执行动画,要想执行只能是popwindow里边的布局去执行,popwindow效果相当于在这个布局的外边又包裹了一层布局
android中动画是经过一些算法去执行,必须让执行动画的控件有背景才能执行,但popupwindow默认没有背景,所以控件执行才没有效果
90.卸载应用程序(对比安装,都是隐式意图)
Day08 09课
点击事件的3种写法
卸载和安装是一样的操作,都是打开系统的一个安装界面或卸载界面
91.启动应用程序
Day08 10课
主要是用getLaunchIntentForPackage(packageName)来获取下应用程序的意图,拿到这个意图intent之后就可以去startActivity(intent)启动这个应用了
92.详情(隐式意图)
Day08 11课
其实就是跳转到系统设置中的详细信息界面
93.短信分享(隐式意图)
Day08 12课
其实就是跳转到发送短信界面
想让谁去实现这种接收分享信息的操作,就给它的清单文件中把上边那个intent-filter意图添加到它的清单文件中,当然这里边有很多intent-filter,你想接收哪一种,就添加哪一种
95.获取可用空间
Day08 13课
内存可用:152MB,SD卡可用:196.80MB
借鉴了源码
步骤:
1.创建获取SD卡/手机内存可用空间的工具类AppUtils
2.调用
96.获取正在运行的进程的信息
Day09 01课
获取正在运行的进程的信息的操作和前边讲的获取软件信息的操作如出一辙,只不过改成用ActivityManager加上PackageManager去实现的
97.进程管理界面(和软件管理界面基本一样)
Day09 02课
进程管理界面和软件管理界面基本一样,软件管理界面又是拷贝修改的选择联系人界面
在复用checkbox时也把checkbox状态给复用了
解决:在bean类中添加isChecked,然后给checkbox保存设置状态
98.刷新界面两种方式
Day09 02课
//第一种方式
myAdapter.notifyDataSetChanged();
//第二种方式,刷新单个条目
ViewHolder viewHolder = (ViewHolder) view.getTag();
viewHolder.cb_itemtaskmanager_ischecked.setChecked(appInfo.isChecked());
第二种方式,刷新单个条目,即通过setTag去给条目增加控件,然后通过getTag的方式获取到控件,然后去刷新这个控件,这里刷新这个控件的方式是setChecked(appInfo.isChecked())
99.全选/反选/清理
Day09 03课 04课
全选:全选的操作是让checkbox的条目都变成true
反选:就是如果是true改为false,false改为true
清理:这个清理其实就是要杀死进程
主要是killBackgroundProcesses(packageName)这个方法
100.获取正在运行的进程个数,空闲内存信息,总内存信息
Day09 06课
1.创建一个工具类,创建获取进程数和内存的方法
2.使用 (着重掌握根据sdk执行不同方法操作)
获取总的内存时,在ProcessUtils中写了两个相同的方法getTotalRam
一个是在低版本中用,一个是在高版本上用
101.根据sdk版本不同重载不同的方法
Day09 07课
获取总的内存时,在ProcessUtils中写了两个相同的方法getTotalRam
一个是在低版本中用,一个是在高版本上用
这个“根据sdk的版本执行相应的方法,来避免程序出错”的方式,在开发中经常要用到
因为在高版本中有一些效果是特别炫的,但是在低版本中用的时候就报错,那所以说为了兼容低版本
在开发时都会根据sdk的版本来实现不同效果,比如在高版本中你的效果特别炫,在低版本中我就不要效果了,直接实现功能,先满足用户的需求,然后再考虑其他的,保证程序不会出错
102.Widgets桌面控件(就是一个广播接收者)
Day10 02,03,04 05 06 08课
创建widgets步骤:02课
1.创建一个广播接收者MyWidgets,继承自AppWidgetProvider(是广播接受者不是内容提供者,只是名字起错了)
2.清单文件中配置广播接收者MyWidgets
3.res/xml下创建example_appwidget_info.xml布局
4.layout下创建布局process_widget.xml
更新widgets中的文本的步骤:05课
1.创建一个widgetsService
2.在WidgetsService中的oncreate方法中获取widget管理者appWidgetManager,并调用updatesWidgets方法来更新widgets
3.在widgetsService中创建这个更新widgets的方法updatesWidgets
4.在清单文件中注册服务widgetsService
5.在Mywidgets的onEnabled方法中开启服务,在onDisabled方法中关闭服务
widgets点击事件:06课 用到了延迟意图pendingIntent
1.在timer中执行: views.setOnClickPendingIntent(R.id.btn_clear, pendingIntent);
2.需要一个延迟意图
3.因为发送了一个广播,所以在WidgetsService的Oncreate中去用代码注册一个广播
a.创建一个广播接受者WidgetReceiver
b.在WidgetsService的oncreate中注册
c.在WidgetsService的ondestory中注销
d.在广播接受者WidgetReceiver的onreceive方法中执行清理进程的操作
用户从设置中心关闭服务,造成widgets无法更新的问题
updatePeriodMillis 更新时间到了之后就会去调用onUpdate方法
处理方式:将开启服务的操作移植到onUpdate方法
凡是源码中带@RemoteView(远程视图)注解的控件都可以显示在widgets控件的布局里面,没有就不能显示
1)远程布局不能通过findViewById去初始化控件的,远程布局文件提供了另外一种方式:views.setTextViewText(viewId,text)
参数viewId:是要更新的远程布局的控件的id,参数text:是要更新的内容
2)远程布局是不能直接去进行点击操作的,必须通过PendingIntent去执行操作
views.setOnClickPendingIntent(viewId, pendingIntent)
参数viewId:是执行点击事件的控件的id 参数pendingIntent:是一个延迟意图
onEnabled,onReceive onUpdate onDeleted onDisabled
总结:
1.第一次创建的时候会调用 onEnabled
2.每次创建都会调用 onUpdate
3.不管什么操作都会调用onReceive
4.每次删除都会调用onDeleted
5.删除最后一个调用onDisabled
103.反编译 (获取apk源码的方式)
Day10 04课
获取apk源码的方式:
1.改apk后缀名为zip解压(适用于没有反编译的apk)
2.反编译 (适用于反编译后的apk)
3.dex转jar (适用于反编译后的apk,比2反编译apk更易读)
104.“每隔一段时间”的实现方式
Day10 05课
1.new一个线程然后再来一个while(true),在里边让它睡上几秒钟(用的比较少)
2.timer,这个是java中的定时器
105.锁屏清理进程
Day10 06课
锁屏和解锁的广播接收者不能在清单文件中注册,必须使用代码进行注册
锁屏和解锁的广播接收者实现步骤相同,即:
a.在服务WidgetsService中创建一个广播接受者
b.在服务WidgetsService的Oncreate方法中注册广播接受者
c.在服务WidgetsService的ondestory方法中注销广播接受者
d.在广播接受者的onreceive方法实现各自的功能
106.屏幕适配常用的两种方式
Day10 09课
三种屏幕中显示时出现差别是因为用px代替dp去设置了,android中使用的是dp
所以要将px转化为dp去设置
有些同学搞不清什么时候该用dip2px,什么时候该用px2dip,这个一定要搞清楚 在代码中用到的全部都是像素px,这个一定要记住
dp转化成px的操作一般是在坐标处会用到,像素转化dp的操作一般是在要设置控件的宽高时用到
密度工具类DensityUtil
1.使用DensityUtils工具类去适配
2.像再增加item条目就看不到了,去适配时是通过ScrollView控件去适配的
107.创建快键方式
Day10 10课
其实就是发送一个广播,然后在intent里边进行设置快键方式的名称,图标,拨打电话操作
一般这个快键方式在创建时,都是在应用刚打开时去创建,所以一般都是在SplashActivity里的onCreate方法里边调用shortCut()方法,然后创建出这个方法,这个就是创建快键方式的操作
108.launcher桌面应用
Day10 10课
工作中公司可能会让你做一个launcher桌面应用,这个要注意了,别到时候说让你做一个launcher应用,你说不会,其实就是做一个app
然后在清单文件中加一些属性,这个app就是launcher桌面应用了
如何让你的应用变成launcher桌面应用:
在注册activity时加如下属性即可
即:
launcher其实就是一个应用,就是在清单文件中注册activity时,添加了如上属性,尤其是category.HOME这个属性
就把你的应用变成了一个launcher应用
109.软件锁功能
Day10 11 12 13课 Day11 02课
110.时时刻刻的2种实现方式
Day10 11课
1.Timer
2.new一个子线程,在run方法中来一个while(true)循环
//时时刻刻监听用户打开的程序
new Thread(){
public void run(){
while(true){
}
};
}.start();
在服务中跳转activity必须给要跳转的activity指明一个任务栈,这样才能跳转
111.关于软件锁的数据库操作
Day10 12课
关于软件锁的数据库操作和黑名单的数据操作一模一样,不想写就直接拷贝修改
关于软件锁的数据库中存放的只是一个字段,应用程序的包名packagename
加锁就是将对应的包名packagename保存到数据库
解锁就是将对应的packagename从数据库中删除
112.ListView长按点击事件
Day10 13课
listview.setOnItemLongClickListener(new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int position, long id) {
return true;
}
});
113.点击物理返回键,又进入输入密码界面的bug
Day10 14课
解决:在输入密码界面重写onkeydown方法
114.Activity给Service传递数据
Day11 02课
startActivityForResult是activity给activity传递数据时用
activity给service传递数据一般会发送广播来处理
在activity中发送广播时通过intent.setAction(“content://cn.itcast.mobliesafexian02.unlock”);
传递包名
在service中写一个广播来接收广播事件,在onReceive方法中就可以通过intent.getStringExtra(“packagename”)获取到传递过来包名
115.Activity4种启动模式
Day10 03课
standard: 默认的启动模式,就是平时怎么启动,就怎么启动
singleTop:如果这个activity在任务栈顶,就不去创建新的了
singleTask:如果任务栈中有这个activity,调用时,就会把它上边的其他activity给移除掉
singleInstance:单独给一个activity设置一个任务栈
注意singleInstance在项目中的实际应用解决的bug
116.让app不在手机的最近列表显示
Day11 03课
excludeFromRecents属性是不在最近列表中显示,true表示不显示,false表示显示
但是在哪个activity中设置,哪个acitivity调用之后才会生效
117.解锁的数据库优化操作
Day11 04课
1.将数据库中数据全部放到集合中,改为从集合中查询数据
1)查询全部数据返回到集合List中
2)list.contains(packagename)判断是否加锁
3)将频繁查询数据库的代码改用boolean类型的islock
2.更新集合,在加锁和解锁时都要更新集合,用到内容观察者
1)注册一个内容观察者
2)在内容观察者的onChange方法中查询全部数据到集合
3)加锁解锁时通知内容观察者内容变化了
118.短信备份/还原短信
Day11 05课
短信备份:
1.使用内容提供者来获取短信
1)获取内容解析者
2)获取内容提供者地址sms
3)生成查询的地址
4)查询数据
2.将获取到的短信保存到数据库或文件中
这里选用保存到文件中
还原短信:
还原短信的操作,其实就是解析xml
这里重点讲解析完数据之后,怎么把数据添加到手机中
把数据添加到手机中主要就是用内容解析者ContentResolver把数据insert添加给手机短信的数据库
119.将数据保存到文件中的步骤
Day11 06课
1.获取xml序列器
2.设置文件保存位置及保存的编码格式
3.设置文件头信息
4.设置根标签
5.设置每条短信的标签
6.将数据保存到对应标签中
7.刷新数据到文件中
120.两种进度条
Day11 07 08课Day12 01课
1.ProgressBar
在布局文件中添加progressbar控件,在onCreate方法中初始化,然后将它传递给getAllSMS方法并接收
2.ProgressDialog
在代码中new出来,分别set各种设置,然后将它传递给getAllSMS方法并接收
3.这里直接在子线程中调用了progressDialog.dismiss()去让这个dialog消失
这是在子线程中执行了更改UI的操作,以前都要new一个Handler,在主线程中去执行更改UI的操作
但是注意:凡是和progress相关的操作,都可以在子线程中去执行
ProgressDialog,ProgressBar都可以在子线程中进行UI更新,这个大家一定要注意
progressbar里边封装了一个handler,所以才能直接在子线程中去更新它的UI(pb_antivirus_progress.setProgress(progress)),而不像textview,要去setText更新UI时,还要放在runOnUiThread里边去
121.回调方法
Day11 07课
用一个回调方法来解决频繁去修改业务类的问题
步骤:
1.在处理的业务类(SmsEngine.java)中,编写一个接口,同时声明出要使用的方法
2.将接口以参数的形式,传递给要调用的业务方法,并在其中执行相关的接口的方法
3.在调用业务方法的时候(AToolsActivity中),在方法中实现接口操作,在实现方法中去实现相应的操作
在开发中用广播也可以处理频繁去修改业务类的问题
122.ExpandableListView(可扩展的ListView)
Day11 09课
主要看的是adapter中实现的四个方法:
1.getGroupCount:获取组的个数
2.getChildrenCount:获取每组有多少个孩子
3.getGroupView:获取组的样式
4.getChildView:获取组的孩子的样式
123.抽屉效果的两种实现方式
Day11 10课
1.SlidingDrawer
handle : 抽屉的把手
content : 抽屉的内容
handle,content属性,要的都是一个id
SlidingDrawer控件缺点:只能从下往上,从右往左拉出抽屉,你要从左往右,从上到下拉出抽屉,这个是不可能的
2.DrawerLayout(V4包下的DrawerLayout控件)
重要的是dl.openDrawer(Gravity.LEFT)方法,它可以控制打开左边还是右边的抽屉
第二种方式DrawerLayout是比较流行的一种,而第一种方式SlidingDrawer,它是以前用的比较多,但是现在基本上已经被淘汰了
抽屉效果最常用的是用来做菜单栏,你点击它就跳转到哪个界面去
124.自定义ProgressBar样式(图层layer-list)
Day11 12课
属性progressDrawable:设置ProgressBar图片的,它是一个progress_horizontal.xml文件
文件中跟标签是图层layer-list
layer-list,类似于framlayout和RelativeLayout,可以让控件一个控件叠着另一个控件,最下面的显示的时候是在最上边
自定义ProgressBar样式步骤如下:
1.在res-> drawable ->新建xxx.xml 注意:id不可以变
2.在布局文件activity_antivirus.xml的progressBar控件中使用xxx.xml即可
125.展示列表信息的方式(ListView,ScrollView)
显示扫描的每个应用程序名称的方式:
1.用listview不断的去更改界面,这个很简单前边也做过
2.scrollView,你可以不断的给里边添加textview,这是没问题的
这里选用第2种方式ScrollView
126.扫描效果
Day11 13课
让ScrollView自动从下往上滑动到显示的位置
1.要让它自动滑,需要拿到ScrollView,每一次都去计算它的位置
2.可以让它每次都从上往下添加应用的名称
这个就涉及到重载的方法,将给ll_antivirus_safeapk去addView()时,使用两个参数的,即addView(textview,index)
这个index我写个0,index的意思是将这个view添加到哪个位置,0就表示添加到第0个位置
那它每次添加都是添加到最上边,那每次都从上往下添加应用的名称
124.旋转动画
Day11 13课
RotateAnimation
125.给服务发送消息或数据的方式
Day12 01课
比如说要给服务发送一个消息或数据
1.一般常用的就是广播
2.当然也可以用回调
但是一般首先想到的就是广播,用广播去进行操作
126.获取签名信息
Day12 02课
1.添加标签
2.获取应用程序的签名信息
使用MD5Utils工具将签名信息转化为了特征码
127.拷贝数据库,查询数据库
Day12 03课
拷贝病毒数据库antivirus.db和查询号码归属地时拷贝address.db数据库操作一样
128.用命令行将apk运行到模拟器中
Day12 04课
129.扫描病毒,杀死病毒(卸载apk)
Day12 04课
杀死病毒就是将带有病毒的apk卸载掉
130.Fragment的使用
Day12 04课
1.创建两个fragment,继承v4包下的fragment
2.给两个Fragment分别设置布局布局文件,并加载
3.将clearcacheactivity,由继承自Activity改为继承自V4包下的fragmentActivity
4.修改ClearCacheActivity的布局activity_clearcache.xml
我一般喜欢用RelativeLayout占位,你也可以用FrameLayout,LinearLayout占位都可以
5.在ClearCacheActivity的oncreate方法中添加这两个Fragment
6.缓存清理按钮和SD卡清理按钮的操作
131.进度条的操作
缓存清理中进度条的操作完全可以模仿手机杀毒模块的进度条功能
132.写入缓存,获取缓存,显示缓存(aidl远程通信,反射),清理缓存
Day12 05课
获取缓存步骤:
1.反射获取相应的方法
2.获取缓存大小
aidl远程通信和反射
显示缓存:
在Fragment中用listview显示的缓存
清理缓存:
点击缓存清理,扫描完之后,立即清理按钮(清理全部缓存)就弹出来了
系统不允许我们清理单个应用的缓存,但是允许清理总缓存
所以清理单个应用的缓存时,是用隐式意图跳转到手机系统的应用详情页面,让系统帮我们清理
清理总缓存时,用aidl和反射我们自己去清理的
133.在Fragment中用ListView显示缓存
Day12 05课
134.SD卡清理
Day12 05课
这里只说了思路,自己实现
135.全局bug收集
Day12 10课
收集用户使用app时产生的bug到服务器上
在MyApplication中进行异常捕获
136.代码混淆
Day12 11课
不管哪个应用,在开发完了之后,都要进行“bug收集”,“代码混淆”,“打包签名apk”,“上架”
137.广告
Day12 13课
和使用其他第三方sdk一样简单