本帖最后由 小鲁哥哥 于 2016-12-29 19:49 编辑
【济南中心】Android课程同步笔记day04:Android应用之安全卫士
ListView的Adapter优化在使用ListView 控件的过程中,由于加载条目过多在滑动时可能造成卡顿。这是因为ListView 在当前屏幕显示多少个条目,就会创建多少个对象,每一个条目都是一个对象。在滑动时,滑出屏幕的条目对象会被销毁,新加载到屏幕上的条目会创建新的对象,这样在ListView 快速滑动时就会不断的【创建对象】->【销毁对象】->【创建对象】,并且每一个条目都需要加载一次布局,加载布局时会不断进行findViewById()操作初始化控件,而布局xml 文件是以树形进行加载,每次加载一个条目都需要从根节点进行初始化,这样对内存消耗也比较大,并且浪费时间。如果每个条目都有图片,图片加载的时间比较长,就会造成内存 溢出异常。为此就需要对ListView 进行优化,优化的目的是在滑动时不会重复创建对象,减少内存消耗和屏幕渲染处理。具体步骤如下:
1.创建一个静态类,将需要加载的控件变量放在该静态类中: static class ViewHolder{
} 2. 复用缓存View 对象 在Adapter 的getView(int position, View convertView, ViewGroup parent)方法中,第二个参数convertView代表的就是之前滑动出屏幕的条目对象。如果是第一次加载该方法时,会创建新的View 对象,如果滑动ListView 时,滑动出屏幕的View 对象会以缓存的形式存在,而convertView就是缓存的View 对象,我们可以复用缓存该对象减少新对象的创建。在加载布局时先判断convertView 是否存在, 如果convertView==null 说明没有缓存的View 对象,则使用View.inflate()方法加载布局,进行布局的初始化,否则复用缓存的View 对象,具体代码如下所示: [Java] 纯文本查看 复制代码 @Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(null == convertView){
//没有可以复用的对象
convertView = View.inflate(ContactSelectActivity.this,
R.layout.item_contact, null);
holder = new ViewHolder();
holder.ivIcon = (ImageView) convertView
.findViewById(R.id.item_contact_iv_icon);
holder.tvName = (TextView) convertView
.findViewById(R.id.item_contact_tv_name);
holder.tvNumber = (TextView) convertView
.findViewById(R.id.item_contact_tv_number);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
ContactBean contactBean = mDatas.get(position);
holder.tvName.setText(contactBean.name);
holder.tvNumber.setText(contactBean.number);
holder.ivIcon.setImageBitmap
(ContactProvider.getContactPhoto(ContactSelectActivity.this, contactBean.contactId));
return convertView;
}
手机重启广播当手机电池拿掉取出sim 卡后插入电池重启时,手机会发出重启手机的广播,定义一个全局侦听器来监听这个广播,然后我们可以进行一定的手机防护功能。首先,定义广播接收者我们需要在清单文件中配置,配置信息如下所示。 [Java] 纯文本查看 复制代码 <receiver android:name="com.itheima.zphuanlove.receiver.BootCompletedReceiver" >
<intent-filter android:priority="1000" >
<!-- 重启手机 -->
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
手机重启需要加一个权限<uses-permissionandroid:name="android.permission.RECEIVE_BOOT_COMPLETED" />创建手机重启的广播接收者BootCompletedReceiver 继承BroadcastReceiver,代码中我们需要获取用户是否绑定sim 卡信息,具体的代码如下所示
[Java] 纯文本查看 复制代码 public class BootCompletedReceiver extends BroadcastReceiver {
private static final String TAG = "BootCompletedReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "手机重启了....");
// 1. 判断是否开启防盗保护
boolean protecting = PreferenceUtils.getBoolean(context,
Config.KEY_SJFD_PROTECTING);
if (!protecting) {
// 没有开启防盗保护
Log.d(TAG, "没有开启防盗保护....");
return;
}
Log.d(TAG, "开启了防盗保护....");
// 2. 比对sim卡
// 1) 存储的sim
String sim = PreferenceUtils.getString(context, Config.KEY_SJFD_SIM);
// 2) 当前手机的sim
TelephonyManager tm = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
String currenSim = tm.getSimSerialNumber() + "xxx";// 模拟丢失
if (sim.equals(currenSim)) {
// 存储的和当前的是一致的,手机没有丢失
Log.d(TAG, "手机没有丢失....");
return;
}
// 手机丢失了
Log.d(TAG, "手机丢失了....");
// 3. 给安全号码发送报警短信
Log.d(TAG, "发送报警短信....");
String number = PreferenceUtils.getString(context,
Config.KEY_SJFD_NUMBER);
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(number, null, "mobile is lost!!!sos", null,
null);
}
}
当设置了这个广播之后,首先获取用户之前绑定的sim 卡信息,其次获取当前手机中的sim 信息,当二者不一致时,手机重启后就会向用户设置的安全号码中发送报警短信。实现该功能还需要加入一些权限,如下所示
<uses-permission android:name="android.permission.SEND_SMS"/> <uses-permission android:name="android.permission.RECEIVE_SMS" />
短信接收广播之指令分析
定义一个广播SmsReceiver。首先,需要在清单文件中配置信息,priority=1000这是为了保证当前广播具有最高优先权接收信息[Java] 纯文本查看 复制代码 <receiver android:name="com.itheima.zphuanlove.receiver.SmsReceiver" >
<intent-filter android:priority="1000" >
<!-- 接收短信的 -->
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver> [Java] 纯文本查看 复制代码 接收GPS 跟踪、发送报警音乐等功能的代码如下所示。
public class SmsReceiver extends BroadcastReceiver {
private static final String TAG = "SmsReceiver";
@Override
public void onReceive(Context context, Intent intent) {
// 接收短信
Object[] objs = (Object[]) intent.getExtras().get("pdus");
for (Object obj : objs) {
SmsMessage sms = SmsMessage.createFromPdu((byte[]) obj);
// 发送者
String sender = sms.getOriginatingAddress();
// 发送的内容
String content = sms.getMessageBody();
String number = PreferenceUtils.getString(context,
Config.KEY_SJFD_NUMBER);
// 判断发送者是否是安全号码
if (sender.equals(number)) {
// 安全号码发送的
// 判断内容,是否是指令
if ("#*location*#".equals(content)) {
// TODO:
Log.d(TAG, "GPS追踪");
} else if ("#*wipedata*#".equals(content)) {
// TODO:
Log.d(TAG, "远程消除数据");
} else if ("#*alarm*#".equals(content)) {
// TODO:
Log.d(TAG, "播放报警音乐");
} else if (!"#*lockscreen*#".equals(content)
&& content.startsWith("#*lockscreen*#")) {
Log.d(TAG, "远程锁屏");
} else if ("#*lockscreen*#".equals(content)) {
Log.d(TAG, "远程锁屏");
}
// 不让用户看到短信内容
abortBroadcast();
}
}
}
} 播放报警音乐
在res下创建一个raw文件夹用于放资源文件alram.mp3. 当发送一个特殊指令之后,无论手机是否处于静音状态,丢失的手机会立即播放这个报警音乐。具体的代码在短信接收广播中进行修改,如下所示
[Java] 纯文本查看 复制代码 if ("#*alarm*#".equals(content)) {
MediaPlayer player = MediaPlayer.create(context,
R.raw.alarm);
player.setLooping(true);// 无限播放
player.setVolume(1f, 1f);// 设置声音
player.start();
Log.d(TAG, "播放报警音乐");
}
手机定位
GPS 跟踪是通过启动一个位置服务GPSService.java 实现的,GPSService的代码如下
[Java] 纯文本查看 复制代码 public class GPSService extends Service {
private LocationManager mLocationManager;
private GPSListener mListener;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
super.onCreate();
// 获得手机的经纬度
// 1.获得位置管理者
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// 2. 注册位置监听
mListener = new GPSListener();
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
0, 0, mListener);
}
@Override
public void onDestroy() {
super.onDestroy();
// 4. 注销位置监听
mLocationManager.removeUpdates(mListener);
// 5. 注册权限
}
// 3. 实现listener
private class GPSListener implements LocationListener {
@Override
public void onLocationChanged(Location location) {
double latitude = location.getLatitude();// 纬度
double longitude = location.getLongitude();// 经度
// 拿到纬度和精度
// 1. 转换为经度
double[] result = GPSUtils.parse(GPSService.this, latitude,
longitude);
// 2. 将转换后的经纬度发送给安全号码
SmsManager smsManager = SmsManager.getDefault();
String number = PreferenceUtils.getString(GPSService.this,
Config.KEY_SJFD_NUMBER);
String text = "longitude:" + result[0] + " latitude:" + result[1];
smsManager.sendTextMessage(number, null, text, null, null);
// 3. 停止服务
stopSelf();
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
@Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
}
}
解析到对应的指令后: [Java] 纯文本查看 复制代码 if ("#*location*#".equals(content)) {
Log.d(TAG, "GPS追踪");
Intent service = new Intent(context, GPSService.class);
context.startService(service);
} 注意在清单文件中注册service,以及添加定位的权限: <uses-permissionandroid:name="android.permission.ACCESS_FINE_LOCATION" />
手机设备管理员
应用具备手机设备管理员的权限才能清除手机中的数据、锁屏及修改密码的操作首先在清单文件中,需要这样的一段代码
[XML] 纯文本查看 复制代码 <!-- 设备管理员 -->
<receiver
android:name=".receiver.SjfdAdminReceiver"
android:description="@string/sample_device_admin_description"
android:label="@string/sample_device_admin"
android:permission="android.permission.BIND_DEVICE_ADMIN" >
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin_sample" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
手机设备管理员是一个广播接受者继承了DeviceAdminReceiver 具体的代码如下
[Java] 纯文本查看 复制代码 public class SjfdAdminReceiver extends DeviceAdminReceiver {
} device_admin_sample 文件是在res 目录创建的xml 文件夹下的一个xml 文件,具体的代码如下
[XML] 纯文本查看 复制代码 <device-admin xmlns:android="http://schemas.android.com/apk/res/android" >
<uses-policies>
<!-- 重置密码 -->
<reset-password />
<!-- 锁屏 -->
<force-lock />
<!-- 擦除数据 -->
<wipe-data />
</uses-policies>
</device-admin>
|