![Android项目实战:手机安全卫士](https://wfqqreader-1252317822.image.myqcloud.com/cover/676/31728676/b_31728676.jpg)
2.5 设置向导功能
设置向导主要用于展示手机防盗模块,以及绑定SIM卡、设置安全号码、开启防盗保护功能等,本节将针对设置向导功能进行详细讲解。
2.5.1 滑屏动画
在Android系统中,通过手势识别切换界面时,通常会在界面切换时加入动画,以提高用户的体验效果,这种动画一般都采用平移动画,当下一个界面进入时,上一个界面移出屏幕,如图2-14所示。
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00070002.jpg?sign=1739479281-gWQeC0PH55uNujg45n9trCjw2v3V6zFd-0-8e058acd8e38842f2b0cb44e50fe22d7)
图2-14 动画效果图
从图2-14可以看出,屏幕左上角的坐标为(0,0),进入屏幕的界面坐标为(100%p,0),从屏幕切出界面的坐标为(-100%p,0)。需要注意的是,p是指屏幕,100%p表示整个屏幕,切入界面和切出界面都是以整个屏幕为单位计算的。
界面切换的平移动画有四个,分别是下一个界面进入与切出效果,以及上一个界面进入与切出效果,接下来分别定义这四个动画文件。
1.下一个界面进入、切出动画
在res目录中添加一个anim文件夹,在该文件夹中定义下一个界面进入的动画效果(next_in.xml),具体代码如【文件2-23】所示。
【文件2-23】res/anim/next_in.xml
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00070003.jpg?sign=1739479281-GUp1aK1MPO48lSv9spCsCubK7VvPFpsJ-0-b44a9d48d69a1748b5b2c1a1522bce80)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00071001.jpg?sign=1739479281-bBSVApSmGlCFA7LjO6Hz8r5g3WLvDHDZ-0-8dfb0538aa7745d5451bc2fa37a77cd9)
上述代码中,android:fromXDelta="100%p",android:toXDelta="0"属性表示当前界面从X轴坐标100%p移动到0,android:duration="500"表示动画执行时长为500毫秒,repeatCount="0"表示动画不重复执行。
在anim文件夹下创建下一个界面切出的动画效果(next_out.xml),具体代码如【文件2-24】所示。
【文件2-24】res/anim/next_out.xml
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00071002.jpg?sign=1739479281-WkCu4gxiqBJlpGZK2nAG97vHqQuJy2FK-0-20543d697ebc12ce912f16a4877f1bb4)
下一个界面进入效果与切出效果代码类似,只不过当前界面是从X轴坐标0位置移动到-100%p,时长为0.5秒,动画不重复执行。
2.上一个界面进入、切出动画
上一个界面的进入、切出动画与上面的代码非常类似,只不过是X轴坐标的起始位置与结束位置的变化而已。下面在anim文件夹下创建上一个界面进入的动画效果(pre_in.xml),具体代码如【文件2-25】所示。
【文件2-25】res/anim/pre_in.xml
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00071003.jpg?sign=1739479281-gQIxSRY2WTXChyvdMOJBI53pC8Dm4Ijj-0-fac8e4e5d586bf67a0fc7f8833919d9f)
在anim文件夹下创建上一个界面切出的动画效果(pre_in.xml),具体代码如【文件2-26】所示。
【文件2-26】res/anim/pre_out.xml
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00072001.jpg?sign=1739479281-K4LJ6JZRbxYYtjQRYWgbcE1l5rKeC1Mz-0-99a37f9cf9f58892541bace0ca0f88bb)
至此,所有的动画效果已经创建完成,只需在切换屏幕时引入即可。
2.5.2 手势滑动
设置向导中最核心的内容就是通过手势识别切换界面,当手指落在手机屏幕上按住屏幕快速滑动屏幕即可切换。为了更生动形象地展示切换效果,通过一个图例进行展示,具体如图2-15所示。
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00072002.jpg?sign=1739479281-iALQyp6JSVZI4yozDgvnoU327hDXAi2O-0-589a9c04e94dca61ea93ba31e80a46ab)
图2-15 屏幕切换效果图
从图2-15可以看出,当手指在左侧按下向右快速滑动时,上一屏进入当前界面,当手指在右侧按下快速向左侧滑动时,下一屏进入当前界面。需要注意的是,在滑动过程中需要过滤一些无效的动作(如滑动太慢)。
从功能介绍中可知,设置向导的每一个界面都需要进行滑动,也就是说每个Activity都要有手势识别器。为了避免代码的重复编写,可以定义一个父类实现手势识别功能,其他类继承该类即可。设置向导界面的父类如【文件2-27】所示。
【文件2-27】BaseSetUpActivity.java
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00072003.jpg?sign=1739479281-Cu7TGvBPt9VM1CD6RKkeFXEwdnCBEruW-0-7d7916057bd9ab359c93d3aa65ea3247)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00073001.jpg?sign=1739479281-4P0bEdpRFbLlf1cNUgivXW1kH6x1YKuW-0-b6f8bd90b8cc5c0c498392df4a807882)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00074001.jpg?sign=1739479281-xnVgWkNR8IgqAswFAa4xQuZjIkfxOnA8-0-a38b5d45cd465b0c17c0844c555aea5c)
代码说明:
●第10~37行代码用于初始化手势识别器,并实现onFling()方法,在该方法中通过if语句对手势的滑动效果进行判断,如果if(Math.abs(velocityX)<200)时表示1秒移动小于200像素,移动速度太慢界面不切换;如果if((e2.getRawX()-e1.getRawX())>200)时,则从左向右滑动屏幕显示上一个界面并显示动画效果;如果if((e1.getRawX()-e2.getRawX())> 200)时,则从右向左滑动屏幕,显示下一个界面并显示动画效果。
●第38~39行代码定义了一个showNext()方法和一个showPre()方法,分别用于展示下一个页面和上一个页面。这两个方法都是抽象的,需要子类重写。
●第42~46行重写了onTouchEvent()方法,并通过手势识别器分析屏幕上的手势事件。
●第51~55行的startActivityAndFinishSelf(Class<?> cls)方法用于在当前界面开启一个新的Activity时,把当前的Activity关闭,其中传入的参数Class<?> cls可以是一个Activity。
2.5.3 向导功能(一)
当父类创建好之后接下来实现设置向导第一个界面的逻辑,由于第一个界面只是单纯的用于展示,因此逻辑较为简单,具体代码如【文件2-28】所示。
【文件2-28】SetUp1Activity.java
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00074002.jpg?sign=1739479281-NlCwN76J47Y27fuJgFNfrSmtbZhlO1Jf-0-17c3997a84546a49676e8a5666b161c5)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00075001.jpg?sign=1739479281-gZNIKdSGZiJtgVQzWqoiRIJ7OMRcE7gQ-0-9cda17e08f3dbc03fdfd4d38c91b487d)
代码说明:
●第8~11行的initView()方法用于初始化控件,将界面小圆点的状态置为选中状态,此时小圆点的颜色为紫色。
●第13~15行的showNext()方法重写了BaseSetUpActivity中的showNext()方法,用于开启SetUp2Activity并关闭当前Activity。
●第17~19行showPre()方法重写了BaseSetUpActivity中的showPre()方法,当手指在屏幕上从左向右滑动时用于弹出提示信息,说明当前页面是第一页不能显示前一页。
2.5.4 向导功能(二)
设置向导第二个界面主要用于绑定SIM卡,相比第一个界面来说逻辑较为复杂,具体代码如【文件2-29】所示。
【文件2-29】SetUp2Activity.java
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00075002.jpg?sign=1739479281-z91bIYMNB2VFSZkEEnrTrdLAHUd0dMqA-0-b7a617c8b6510067342153cb89eefa1f)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00076001.jpg?sign=1739479281-CX58j6425NZkKMMe75JurI41AC2pUztc-0-0f0c74be51d03f38cf25a9bfe838fb90)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00077001.jpg?sign=1739479281-X8JLNiCfD18BPlSrmczR2NOhpUoh9TRx-0-e32965e3cc09867cf7f1c2558ee96095)
代码说明:
●第12~22行的initView()方法用于初始化控件,指定第2个小圆点被选中,并判断SIM卡是否绑定,如果已绑定则将该Button按钮设置为不可用。
●第54~67行的bindSIM()方法用于绑定SIM卡,通过if语句判断如果当前SIM卡没有绑定,则获取手机的SIM卡串号,并存入SharedPreferences对象中,如果绑定了则弹出Toast进行,并将按钮设置为不可用。
在检测SIM卡是否发生变化时,可以使用Application类。该类是Android框架的一个系统组件,当Android程序启动时系统会创建Application对象(单例模式的一个类,需要在application标签增加name属性,并添加Application名字即可)。正是由于它的这种特性,可以将检测SIM卡是否变更的方法放在Application的onCreate()方法中,当程序启动时就会检测SIM卡是否变更。接下来创建一个Application子类App,具体代码如【文件2-30】所示。
【文件2-30】App.java
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00077002.jpg?sign=1739479281-0CYxhm0gvXrqRYoKvRXcmomKDXTvHX92-0-0d67d337f7e1f2425d4cd86c0e31ea61)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00078001.jpg?sign=1739479281-6TQL45xKEdvCNhXwFaPa6QPoOsvUTLrn-0-9279c3fd9682c8eb34680a4ede6e0d3a)
代码说明:
●第9~12行代码用于获取当前手机防盗保护的状态。
●第13~33行代码用于判断手机SIM卡是否更换,当防盗保护开启时,获取绑定的SIM卡串号,然后获取当前手机SIM卡串号进行比对,如果一致则代表SIM卡未发生变化,如果不一致则代表SIM卡发生变化,此时需要向安全号码发送短信,提示手机SIM卡已更换。
多学一招:Application类
Application和Activity、Service一样是Android框架的一个系统组件,当Android程序启动时系统会创建一个Application对象(只创建一个,所以Application可以说是单例模式的一个类),用来存储系统的一些信息,如全局变量,全局变量相对静态类更有保障,直到应用的所有Activity全部被销毁之后才会被释放。
通常情况下Application是不需要手动指定的,系统会自动创建。如果需要自己创建Application,也很简单,只需创建一个类继承Application,并在AndroidManifest.xml文件中的application标签进行注册即可(只需要给application标签增加name属性,并添加自己的Application名字)。
当Application启动时,系统会创建一个PID,即进程ID,所有的Activity都会在此进程上运行。也就是说,当Application创建时会初始化全局变量,同一个应用的所有Activity都可以取得这些全局变量的值,换句话说,在某一个Activity中改变了这些全局变量的值,那么在同一个应用的其他Activity中值也会改变。
Application对象的生命周期是整个程序中最长的,它的生命周期就等于整个程序的生命周期。由于它是全局的单例的,在不同的Activity、Service中获得的对象都是同一个对象,因此可以通过Application来进行一些数据传递、数据共享和数据缓存等操作。
在Android系统中,有些手机SIM卡更换后,需要重新启动手机识别新的SIM卡,因此,为了最大限度地知道SIM卡变化,还需要创建一个开机启动的广播接收者,监听手机开机事件,并调用App中的correctSIM()方法判断SIM卡是否变更,开机启动的广播接收者如【文件2-31】所示。
【文件2-31】BootCompleteReciever.java
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00079001.jpg?sign=1739479281-0vIA6z7m2O6IiYuc0jxw83BypwzbSN3t-0-514177d728137f571c5aa3177bced0af)
在AndroidManifest.xml文件中,注册开机启动的广播接收者以及配置权限信息,具体代码如下所示:
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00079002.jpg?sign=1739479281-56Q0DnzCDn25Qu1JyhsU1o2VKQGtPIDZ-0-ed467ab508591c2e6d3e33e1e92bfb2f)
2.5.5 向导功能(三)
设置向导第三个界面用于选择或输入安全联系人,当手机SIM卡变更后会向安全号码发送短信通知,具体如【文件2-32】所示。
【文件2-32】SetUp3Activity.java
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00079003.jpg?sign=1739479281-CaYcZUnjdm4atqiiTlmFNz5QRWvDVtgb-0-ea7e871b1e2c817ed4ea380d442b06a7)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00080001.jpg?sign=1739479281-SjpsRNVqgRnVZOOBDC6DX2B2bCHZYGy8-0-8d27f3c6f09841f4de8263580e22e468)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00081001.jpg?sign=1739479281-R7tBFHvrmv8fksZJG5jAX2FvKKtEIMcV-0-d5706edf6556314416a4c824a0b0388f)
代码说明:
●第13~21行的initView()方法用于初始化控件,指定第三个小圆点被选中,并判断是否指定过安全号码,如果指定过则会显示在当前文本编辑框中。
●第23~34行的showNext()方法用于判断文件编辑框中是否有输入了安全号码,如果没有则弹出提示让用户输入号码,否则将号码保存在SharedPreferences对象中,然后开启SetUp4Activity进入下一个界面,并关闭当前Activity。
●第40~46行的onClick()方法用于响应按钮的点击事件,当点击添加联系人按钮时,会跳转到ContactSelectActivity中选择要添加的安全号码(查询联系人功能会在下一小节实现)。
●第48~55行的onActivityResult()方法用于接收联系人界面中选中的联系人信息,并将联系人号码展示到安全号码中。
2.5.6 获取联系人
在设置向导第三个界面中,当点击“添加联系人”按钮时,需要跳转到联系人列表界面。获取联系人功能相对来说比较独立,因此将其作为一个单独小节进行讲解。
1.联系人列表UI
由于联系人信息是以条目依次展示的,因此,在界面中可以使用ListView控件,联系人列表的图形化界面如图2-16所示。
图2-16所示联系人列表界面对应的布局文件如【文件2-33】所示。
【文件2-33】activity_contact_select.xml
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00081002.jpg?sign=1739479281-kFnVL2ail8dSfyUgfu3tXzpV7vk37sbO-0-fa40d0105c6a3c523f039ff8d0d5eea4)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00082001.jpg?sign=1739479281-Jq1NnFDMGN09unBvEkSARxHTEV2yXaUq-0-51d4dde8a150b285461d2eeab004aaef)
上述布局文件中,引入了一个titlebar.xml布局,该布局是一个标题栏,用于展示“选择联系人”的标题,以及在左侧放置一个返回按钮,当点击返回按钮时返回到设置向导第三个界面。
下面开发联系人列表的Item布局,用于填充activity_contact_select.xml布局,Item布局的图形化界面如图2-17所示。
图2-17中Item对应的布局文件如【文件2-34】所示。
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00082002.jpg?sign=1739479281-uGCk4OyJxYeIbZzjvDXbEtHmX4vIVJeg-0-28da0018a38c000f282ba905da2d37fb)
图2-16 联系人
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00082003.jpg?sign=1739479281-e8y63hst9OOfEDFWVhTjfMBF7Y25ENWI-0-d7455d0a1b52cad9a02f670c960ad751)
图2-17 Item布局
【文件2-34】item_list_contact_select.xml
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00082004.jpg?sign=1739479281-2KnCYsuIH0XAgpHwoKTt0Aup8drDIHf5-0-00a888d2cc88e2b9901796e137c04fad)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00083001.jpg?sign=1739479281-Eipny6Dj1LooZFFhDeRnNghUtOQShXjo-0-599f4a7af5f4df4946ab09f18cfe1574)
上述布局文件中,定义了一个View控件以及两个TextView控件,其中View控件用于显示联系人图标,TextView控件分别用于显示联系人姓名、电话号码。
2.联系人的实体类
接下来开发一个ContactInfo类,该类用于封装联系人信息,如姓名、手机号码等,具体代码如【文件2-35】所示。
【文件2-35】ContactInfo.java
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00083002.jpg?sign=1739479281-Xe2qocIo64I2j8zXvpT42B9uDByvk2zB-0-c7f70925bcaaf9df2de316984b9dd581)
3.解析联系人
联系人信息都存储在SQLite数据库中,因此需要先获取到联系人的id,根据id在data表中查询联系人名字以及电话号码,并封装到ContactInfo中,然后存入List集合,具体代码如【文件2-36】所示。
【文件2-36】ContactInfoParser.java
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00084001.jpg?sign=1739479281-KRXBEQDrWsBzZE6Ign2rdmrvetaqRZDN-0-398c665c7a2b7d52c26a168f233a64d4)
4.数据适配器
从数据库查询出的联系人信息,需要通过数据适配器填充到ListView中,接下来定义联系人列表的数据适配器ContactAdapter,具体代码如【文件2-37】所示。
【文件2-37】ContactAdapter.java
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00085001.jpg?sign=1739479281-J51JYjjXZa0dzm5TetmRMorKDl2gUTQI-0-d4760698a17431f7cb9c675bb53b1f18)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00086001.jpg?sign=1739479281-h1bUYj0itKO5M7TPydZqx5utNMvN3mUF-0-8e130c4d77758c603bca30b6367ff1fe)
多学一招:ListView优化
在使用ListView控件的过程中,由于加载条目过多在滑动时可能造成卡顿。这是因为ListView在当前屏幕显示多少个条目,就会创建多少个对象,每一个条目都是一个对象。在滑动时,滑出屏幕的条目对象会被销毁,新加载到屏幕上的条目会创建新的对象,这样在ListView快速滑动时就会不断地创建对象→销毁对象→创建对象,并且每一个条目都需要加载一次布局,加载布局时会不断进行findViewById()操作初始化控件,而布局XML文件是以树形结构进行加载,每次加载一个条目都需要从根节点进行初始化,这样对内存消耗也比较大,并且浪费时间。如果每个条目都有图片,图片加载的时间比较长,就会造成内存溢出异常。为此就需要对ListView进行优化,优化的目的是在滑动时不会重复创建对象,减少内存消耗和屏幕渲染处理。具体步骤如下:
(1)创建静态类
创建一个静态类,将需要加载的控件变量放在该静态类中,保证所有控件只创建一次对象,不会重复创建对象,具体代码如下:
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00086002.jpg?sign=1739479281-FAcZwVyfgefI3T9vVpPsm3wqZwxdARiB-0-2281c0203f0ac2cf06dfef3e5350079a)
(2)复用缓存View对象
在Adapter的getView(int position,View convertView,ViewGroup parent)方法中,第二个参数convertView代表的就是之前滑出屏幕的条目对象。如果是第一次加载该方法,会创建新的View对象,如果滑动ListView,滑动出屏幕的View对象会以缓存的形式存在,而convertView就是缓存的View对象,可以复用缓存该对象减少新对象的创建。在加载布局时先判断convertView是否存在,如果convertView==null说明没有缓存的View对象,则使用View.inflate()方法加载布局,进行布局的初始化,否则复用缓存的View对象,具体代码如下:
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00086003.jpg?sign=1739479281-T7ZSXpwDzmI64YpvYvpgMzgeJ4rISjj0-0-ee7f10ff161701f09207119de710b16b)
多学一招:ListView优化
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00087001.jpg?sign=1739479281-kc227ro52mpj7q8qC5ZVoAOVE3GJg42l-0-b5dfb5e5fc143427ec84f2c9ce51ceaf)
需要注意的是,通常情况下getView()方法中最后的返回值都是View,但如果复用了convertView,最后的返回值一定要改为convertView,这样才会将布局显示到页面中。
至此ListView的优化已经完成,通过以上几个步骤便可保证ListView滑动时,无论有多少个条目或者滑动速度多快,ListView只会创建一屏的条目对象,不会创建多余对象,对滑动的流畅度和内存占用都进行了优化。在进行项目开发中,都会采用该方法对ListView进行优化。
5.联系人Activity
获取联系人所需的文件都已开发完成,接下来在ContactSelectActivity类中将数据填充到界面中即可,具体代码如【文件2-38】所示。
【文件2-38】ContactSelectActivity.java
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00087002.jpg?sign=1739479281-PEcQFCeka83pTFflPQLYt7MxGApdVenj-0-c4ad786a2c651938c0efbe9d0094f3eb)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00088001.jpg?sign=1739479281-fJ6jXYuAtsgDeEYIdyzyWO0RDfEOCGUx-0-e2f7eafb9c13c7fc555f297d98bf74f4)
代码说明:
●第25~54行的initView()方法用于初始化控件,并注册ListView的条目点击事件,然后通过Adapter将联系人信息添加到界面中。
●第56~62行的onClick()方法用于响应返回按钮的点击事件,当点击该按钮时关闭当前窗口。
2.5.7 向导功能(四)
设置向导第四个界面用于展示设置完成界面,并默认开启防盗保护功能(可以手动关闭防盗保护),具体代码如【文件2-39】所示。
【文件2-39】SetUp4Activity.java
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00089002.jpg?sign=1739479281-IsQzpVNtovZAop96qYiJqeOE0rWWVM3D-0-cf4428e3a069c46fcc3e40a44e601b1e)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00090001.jpg?sign=1739479281-oLb3Ft3AlYgxdzLp9pFFI0klGuODe1i1-0-a3f8d60dd05523a8d59a95a0c2410ab6)
代码说明:
●第10~38行的initView()方法用于初始化控件,设置第四个小圆点被选中,并为ToggleButton按钮注册onCheckedChanged事件,当按钮为被选中状态时,显示“防盗保护已经开启”,反之则显示“防盗保护没有开启”,然后将按钮的状态存储到SharedPreferences对象中。其中第27~34行代码用于判断防盗保护是否开启,如果已经开启则将按钮设置为被选中状态,否则将按钮设置为未被选中状态。
●第40~46行的showNext()方法用于将设置过向导的状态存储到SharedPreferences中,然后关闭当前界面并跳转到LostFindActivity类中。
●第48~50行的showPre()方法用于将显示上一个界面,并关闭当前界面。
2.5.8 防盗指令
防盗指令界面可以控制防盗保护功能的开启和关闭、重新进入设置向导界面,以及展示当前可通过哪些指令来远程操控手机,具体代码如【文件2-40】所示。
【文件2-40】LostFindActivity.java
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00090002.jpg?sign=1739479281-m5YQ6Jv0L5MYjwtQ0xGTGHRpmrHYuNEb-0-f37e2e4371b0df838feea4dde98e97d1)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00091001.jpg?sign=1739479281-3y5XfCnd8OF1HLxibfECJyyrF39PUPiG-0-a9be4ec17ef3e7c7c56250f0d7b03df2)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00092001.jpg?sign=1739479281-spwdohcMHNZ0iIK4JAakV3biK8XvZI2D-0-5a8b15a4b0ffc3948c717186c6c4068f)
代码说明:
●第18~20行的isSetUp()方法用于获取SharedPreferences存入的isSetUp是否为true,用来判断是否设置过向导。
●第37~44行代码用于查询手机防盗是否开启(默认状态为开启),如果已经开启,则将文字展示为“防盗保护已经开启”,并将ToggleButton按钮设置为true;如果没有开启,则将文字展示为“防盗保护没有开启”,并将ToggleButton按钮设置为false。
●第45~60行代码是为ToggleButton按钮注册状态改变的监听事件,当按钮被选中时,则当前文字显示“防盗保护已经开启”,否则显示“防盗保护没有开启”,最后将防盗保护状态是否开启存入SharedPreferences对象中。
●第62~73行的onClick()方法用于响应“重新进入设置向导”按钮以及标题栏返回按钮的点击事件,当点击重新进入设置向导按钮时,进入设置向导第一个界面,当点击返回按钮时,则关闭当前Activity,返回主界面。
●第74~78行的startSetUp1Activity()方法用于跳转到SetUp1Activity界面重新进入设置向导,并关闭当前界面。
为了监听安全号码发送的防盗指令,需要创建一个广播接收者,根据收到的防盗指令来执行不同的操作,具体代码如【文件2-41】所示。
【文件2-41】SmsLostFindReciver.java
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00093001.jpg?sign=1739479281-p5v0hH5qlnWljSx9tW4AYgoqrwOjnsFU-0-1eaaba02da249854cae95aef49b127ab)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00094001.jpg?sign=1739479281-2apYxH6y15bDgaleZAZP4OGun7S2KtOo-0-bbb627c21ef2e78b6a0500adf5cf08a9)
代码说明:
●第6~8行代码用于获取SharedPreferences对象中存入的key为protecting(表示防盗保护是否开启)的值,如果开启则执行if语句中的操作。
●第11~12行代码用于获取超级管理员权限,只有超级管理员才能完成远程清除数据和远程锁屏功能,超级管理员权限需要在清单文件中配置。
●第13~17行代码用于遍历数据库中的短信,获取发件人以及发送的短信内容。
●第18~44行代码用于获取安全联系人的号码,并判断发送短信的号码中是否有安全联系人发送的,如果有则执行下面的if语句,分别根据发送的防盗指令返回位置信息、播放报警音乐、远程清除数据、远程锁屏功能。其中第35行清除数据代码和第40行锁屏代码是必须要有超级管理员权限的,并且当调用这段代码时,必须开启超级管理员权限,否则系统会崩溃。
值得一提的是,开启超级管理员权限有两种方式,一种是手动开启,另一种是通过代码开启。手动开启相对来说比较简单,通过“设置”→“安全”→“设备管理器”选中手机安全卫士项目即可。代码开启相对比较麻烦,不过在程序开发中大部分都是通过代码开启超级管理员权限。
在Android系统中,为了信息安全,普通用户是无法随意删除系统中数据的,因此在执行远程锁屏和删除数据时,需要获得超级管理员权限,接下来定义一个超级管理员的广播接收者,具体代码如【文件2-42】所示。
【文件2-42】MyDeviceAdminReciever.java
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00095001.jpg?sign=1739479281-TNH30gRzS4P5rfo66BVNs0CO0N6nKnps-0-662eaa4d22f15bb76e890533069401e7)
在AndroidManifest.xml文件中,注册超级管理员的广播接收者,具体代码如【文件2-43】所示。
【文件2-43】AndroidManifest.xml
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00095002.jpg?sign=1739479281-0FdjjelDkuvihjMje520oRPFr5xHCFIu-0-56c11a589318d16e480e27924c8caa8f)
上述代码中,定义了一个描述信息description以及label,这些信息是放置在strings.xml文件中的,还添加了一个权限android:permission="android.permission.BIND_DEVICE_ADMIN",用于指定绑定超级管理员的权限。
<meta-data>标签表示超级管理员的元数据,其中的resource属性表示资源,用于指定安全策略,在此将安全策略放置在device_admin_sample.xml文件中,具体代码如【文件2-44】所示。
【文件2-44】res/xml/device_admin_sample.xml
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00095003.jpg?sign=1739479281-VA91SEtoGdHijElqkVB3q8k0zXxeiRgM-0-8fea8282bca0347b3666cb94788e0981)
下面创建防盗指令中使用的定位服务(GPSLocationService),该服务用于获取手机的经度、纬度、移动速度、精确度等,具体代码如【文件2-45】所示。
【文件2-45】GPSLocationService.java
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00096002.jpg?sign=1739479281-mg3pZxJWws6BUFk7Qj62bC2iur4hQfB2-0-5bd7ac220dd99dab3a698484cd0123ed)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00097001.jpg?sign=1739479281-bYsSUE02gvOdVK4RiB0z2E0spnJHPwDO-0-3f032e80d4d3f13e29e55e889a63ba2d)
代码说明:
●第10~22行的onCreate()方法用于位置提供者,首先获取系统的位置管理器,然后通过Criteria对象返回可用的位置提供者,通过lm.getBestProvider(criteria,true)获取最好的位置提供者,最后通过lm.requestLocationUpdates(name,0,0,listener)使用位置提供者。
●第23~50行定义了一个位置监听器MyListener,并实现了位置变化的四个方法,其中onLocationChanged()方法是当手机位置发生变化时调用,因此可以在该方法中获取手机的精确度、移动速度、纬度、经度,然后拼接成一个字符串发送给安全号码。onStatusChanged()方法表示当前位置提供者位置发生变化时调用。onProviderEnabled()方法表示当前位置提供者可用的时候调用,onProviderDisabled()方法表示当前位置提供者不可用时调用。
●第52~56行onDestroy()方法用于注销当前的位置监听器。接下来在AndroidManifest.xml文件中注册GPSLocationService服务,具体代码如下所示:
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00097002.jpg?sign=1739479281-p0MejSngTE2NAx8N0CioM8ILT1iCQrGt-0-885fc661cae71c7ef8498c9ad56884c7)
2.5.9 修改HomeActivity文件
手机防盗模块代码已编写完成,接下来需要在HomeActivity中进行调用,在调用该模块代码时,首先需要调用设置密码对话框代码,在这段代码中判断两次输入的密码是否一致,是否设置过密码等,如果设置过密码则调用输入密码对话框代码,判断密码是否正确,具体代码如【文件2-46】所示。
【文件2-46】HomeActivity.java
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00098001.jpg?sign=1739479281-ZppvSHd3ZL5dmM4NuLfjchM6tr3bjpx2-0-99ee5bf2c10599ecc57732b4bada8382)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00099001.jpg?sign=1739479281-lOn1KyREAv5eErmFkiROYxQ8LE3mKXR9-0-c66c9a4d17dda4e91774cea3399019a3)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00100001.jpg?sign=1739479281-DThDTIOjjGSs4oFqtQITidwmjWVnUyWb-0-3f7331d94ad126a9422eecddadefac2b)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00101001.jpg?sign=1739479281-4GCuL748P3IQGj3jBDwn0tJ0Dzco5bZ6-0-6b868d368975b0c5edc42f432d2a2d05)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00102001.jpg?sign=1739479281-QNUivFtYm9UbxvybeZhjFsSEDl10LPcX-0-16646a3faecd6c9a0587212fc52841da)
![](https://epubservercos.yuewen.com/42DD75/17180239704450606/epubprivate/OEBPS/Images/img00103001.jpg?sign=1739479281-AyjkeRSSHZLkv7xFX2L3Lcxlqs2jsSsU-0-85addfc94a958a30bb4902fdeb20bd1f)
代码说明:
●第22~64行代码用于响应GridView条目的点击事件,当点击第一个功能图标时,也就是switch语句中的case等于0时,会进入手机防盗功能模块。点击其他的图标会进入相应模块,在此将其跳转代码全部实现。
●第66~78行代码用于获取设备的超级管理员权限,首先得到PolicyManager对象,然后通过该对象申请超级管理员权限。在程序启动时这段代码就会执行,方便后期通过管理员权限锁屏以及清除数据。
●第83~117行的showSetUpPswdDialog()方法用于弹出设置密码对话框,首先在setUpPasswordDialog.setCallBack()回调方法中创建SetUpPasswordDialog.MyCallBack(){}对象,实现该回调接口中的ok()方法及cancle()方法,并通过if语句判断两次输入的密码是否一致。
●第121~149行的showInterPswdDialog()方法用于弹出输入密码对话框,同样在mInPswdDialog.setCallBack()方法中创建InterPasswordDialog.MyCallBack(){}对象,实现confirm()方法以及cancle()方法,当点击“确定”按钮时判断输入的密码是否正确,当点击“取消”按钮时关闭对话框。
●第154~159行的savePswd()方法用于将加密过的密码保存到SharedPreferences对象中。
●第164~171行的getPassword()方法用于从SharedPreferences对象中获取保存的密码。
●第173~179行的isSetUpPassword()方法用于判断用户是否设置过手机防盗密码。