1.获取版本信息
public static String getVersionName(Context context) {
String versionName;
// 获取包管理器
PackageManager packageManager = context.getPackageManager();
try {
PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
versionName = packageInfo.versionName;
} catch (NameNotFoundException e) {
versionName = "获取版本信息错误";
e.printStackTrace();
}
return versionName;
}
2.获取服务器版本信息
class GetServerVisionRunnable implements Runnable {
@Override
public void run() {
InputStream is = null;
BufferedReader br = null;
try {
// 创建连接
HttpURLConnection connection = (HttpURLConnection) new URL(
"http://192.168.129.102:8080/version.json").openConnection();
// 设置连接超时时间
connection.setConnectTimeout(5000);
// 设置读取超时时间
connection.setReadTimeout(5000);
// 连接
connection.connect();
String result = "";
if (connection.getResponseCode() == 200) {
is = connection.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
String readlline;
while ((readlline = br.readLine()) != null) {
result += readlline;
}
JSONObject json = new JSONObject(result);
int serverVersionCode = json.optInt("versioncode");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
CommonUtils.CloseStream(is);
CommonUtils.CloseStream(br);
}
}
}
3.下载、安装apk
class DownloadRunnable implements Runnable {
private InputStream inputStream;
private FileOutputStream fos;
private ProgressDialog pd;
public DownloadRunnable(ProgressDialog pd) {
this.pd = pd;
}
@Override
public void run() {
try {
// 初始化
HttpURLConnection connection =
(HttpURLConnection) new URL(downUrl).openConnection();
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
connection.connect();
// 连接成功
if (connection.getResponseCode() == 200) {
// 创建文件
File file = new File(Environment.getExternalStorageDirectory(), "test.apk");
inputStream = connection.getInputStream();
// 获取文件总长度
int totalLength = connection.getContentLength();
// 设置进度条的总大小
pd.setMax(totalLength);
fos = new FileOutputStream(file);
int len;
byte[] buffer = new byte[1024];
int current = 0;
while ((len = inputStream.read(buffer)) != -1) {
fos.write(buffer, 0, len);
current += len;
// 设置进度条的进度
pd.setProgress(current);
}
// 隐藏进度条
pd.dismiss();
// 安装应用
Intent intent = new Intent();
intent.setAction("android.intent.action.VIEW");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addCategory("android.intent.category.DEFAULT");
intent.setDataAndType(Uri.parse("file:" + file.getAbsolutePath()),
"application/vnd.android.package-archive");
startActivityForResult(intent, REQ_CODE_INSTALL_APP);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
CommonUtils.CloseStream(inputStream);
CommonUtils.CloseStream(fos);
}
}
}
4.动画
//沿Y轴旋转的属性动画
ObjectAnimator animator = ObjectAnimator.ofFloat(iv_icon, "rotationY", 0, 45, 90, 135, 180, 225, 270, 315, 360);
// 时常
animator.setDuration(2000);
// 重复次数
animator.setRepeatCount(ObjectAnimator.INFINITE);
// 重复模式
animator.setRepeatMode(ObjectAnimator.REVERSE);
animator.start();
5.按钮按压效果选择器
在res/drawable/目录下新建一个正常状态下的shape
1
2
3
4
5
6
7
8
9
10
11
12
13<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
<!-- oval: 椭圆 -->
<!-- 半径 -->
<corners android:radius="16dp" />
<!-- 宽高 -->
<size
android:height="32dp"
android:width="32dp" />
<!-- 背景色 -->
<solid android:color="#99ffffff" />
</shape>在res/drawable/目录下新建一个按压状态下的shape
1
2
3
4
5
6
7
8
9
10
11
12<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
<!-- 半径 -->
<corners android:radius="16dp" />
<!-- 宽高 -->
<size
android:height="32dp"
android:width="32dp" />
<!-- 背景色 -->
<solid android:color="#33ffffff" />
</shape>在res/drawable/目录下新建一个selector
1
2
3
4
5
6
7
8<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:enterFadeDuration="300" android:exitFadeDuration="300">
<!-- 按压状态使用的背景图 -->
<item android:drawable="@drawable/setting_pressed" android:state_pressed="true"/>
<!-- 默认状态使用的背景图 -->
<item android:drawable="@drawable/setting_normal"/>
<!-- 代码执行的时候会从上向下匹配背景图,一旦有一行执行了,下面的就不会再执行.所以一定要将按压状态的背景图放在默认状态的背景图上方,否则背景图永远都是默认状态的 -->
</selector>为setting按钮设置 android:background属性,值为新建的selector
6.自定义属性
声明自定义属性,参考sdk/platforms/res/values/attrs
<attr name="sivText" format="reference|string" /> </declare-styleable>布局文件使用自定义属性
添加命名空间
xmlns:baidu="http://schemas.android.com/apk/res/com.baidu.demo" 使用 <com.baidu.demo.view.SettingItemView android:layout_width="match_parent" baidu:siv_text="设置1" android:layout_height="wrap_content"/>接收属性值
TypedArray ta = context.obtainStyledAttributes(set, R.styleable.SettingItemView);
//获取属性值 String sivText = ta.getString(R.styleable.SettingItemView_siv_text); //赋值 mTvSettingItem = (TextView) findViewById(R.id.tv_setting_item); mTvSettingItem.setText(sivText);
7.自定义其他属性
设置item背景的自定义属性:枚举类型,参考TextView ellipsize属性
1
2
3
4
5<attr name="sivBackground">
<enum name="start" value="0" />
<enum name="middle" value="1" />
<enum name="end" value="2" />
</attr>
获取枚举类型属性:参考TextView源码读取ellipsize属性,a.getInt()
1
int sivBackground = ta.getInt(R.styleable.SettingItemView_sivBackground,SETTING_ITEM_BACKGROUND_START);
自定义控件什么常量,对应枚举的value值
1
2
3private final static int SETTING_ITEM_BACKGROUND_START = 0;
private final static int SETTING_ITEM_BACKGROUND_MIDDLE = 1;
private final static int SETTING_ITEM_BACKGROUND_END = 2;赋值
switch (sivBackground) {
case SETTING_ITEM_BACKGROUND_START: mRlItemView.setBackgroundResource(R.drawable.setting_item_first_selector); break; case SETTING_ITEM_BACKGROUND_MIDDLE: mRlItemView.setBackgroundResource(R.drawable.setting_item_middle_selector); break; case SETTING_ITEM_BACKGROUND_END: mRlItemView.setBackgroundResource(R.drawable.setting_item_last_selector); break; }
8.自定义Dialog
1 | AlertDialog.Builder builder = new AlertDialog.Builder(this); |
9.Activity界面间的跳转动画(需要在基类中设置Activity进出的动画)
1 | 设置Activity跳转:公共style中添加onClick方法(clickNext、clickPre),对应Activity实现方法 |
10.手势识别器滑动效果的实现
//手势识别器
GestureDetector mDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener(){
/**手势滑动e1:起点、e2:终点、velocityX:X轴速率、velocityY:Y轴速率*/
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,float velocityX, float velocityY) {
float x1 = e1.getRawX();
float x2 = e2.getRawX();
float y1 = e1.getRawY();
float y2 = e2.getRawY();
//速率判断
if(Math.abs(velocityX) < 200){
Log.d(TAG, "速率低");
return true;
}
//垂直方向判断
if(Math.abs(y2-y1) > Math.abs(x2-x1)){
Log.d(TAG, "垂直方向");
return true;
}
if(x1 > x2){//向左滑动:下一步,x1>x2
doNext();
LogUtils.d("下一步");
}else{//向右滑动:上一步,x1<x2
doPre();
LogUtils.d("上一步");
}
Log.d(TAG, "x2-x1="+(x2-x1));
return super.onFling(e1, e2, velocityX, velocityY);
}
});
@Override
public boolean onTouchEvent(MotionEvent event) {
//必须调用手势监听
mDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
11.获取手机sim卡信息
1 | //获取sim卡信息 |
12.手机联系人
内容解析者:ContentResolver
需求:一个联系人可能有多个号码,比如有2个,就有2个item,对应2个联系人
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI
名称:ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME
号码:ContactsContract.CommonDataKinds.Phone.NUMBER
联系人id:ContactsContract.CommonDataKinds.Phone.CONTACT_ID
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20ContentResolver resolver = context.getContentResolver();
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String[] projection = new String[]{ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID}; //查询内容
String selection = null; //查询条件
String[] selectionArgs = null;//查询条件对应参数
String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME+" desc"; //排序
Cursor cursor = resolver.query(uri, projection, selection, selectionArgs, sortOrder);
if(cursor != null){
while(cursor.moveToNext()){
Contact contact = new Contact();
contact.name = cursor.getString(0);
contact.number = cursor.getString(1);
contact.id = cursor.getLong(2);
list.add(contact);
}
cursor.close();
}
return list;
通过id获取联系人头像
单独封装一个方法,通过id获取头像bitmap
ContactsContract:联系人协议
content://contacts 所有联系人uri,content://contacts/id 指定联系人id的uri ContentResolver cr = context.getContentResolver();
1
2
3
4
5// content://contacts/id 对应id联系人uri
Uri contactUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI,
String.valueOf(contactId));
InputStream stream = ContactsContract.Contacts.openContactPhotoInputStream(cr, contactUri );
return BitmapFactory.decodeStream(stream);
13.监控手机卡的变化
创建广播接收者监听sim卡变化
清单文件注册上述广播
1
2
3
4
5
6<receiver android:name="com.baidu.BootCompleteReceive" >
<intent-filter android:priority="1000" >
<!-- 手机重启 -->
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>添加权限:android.permission.RECEIVE_BOOT_COMPLETED
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24class BootCompleteReceive extends BroadcastReceiver{······
@Override
public void onReceive(Context context, Intent intent) {
LogUtils.d("手机重启...");
String newSim = PhoneUtils.getSimSerialNumber(context) + "123";
String sim = SharePreferenceUtils.getString(context, SharePreferenceUtils.KEY_BIND_SIM);
if(newSim.equals(sim)){
LogUtils.d("手机sim卡没变...");
return;
}
boolean protecting = SharePreferenceUtils.getBoolean(context, SharePreferenceUtils.KEY_SAFE_PROTECTED, false);
if(!protecting){
return;
}
LogUtils.d("手机丢失了,sim卡变了...");
//安全号码
String number = SharePreferenceUtils.getString(context, SharePreferenceUtils.KEY_SAFE_NUMBER);
//发送报警短信
SmsManager manager = SmsManager.getDefault();
//需要添加发送短信权限
manager.sendTextMessage(number, null, "手机已丢失!", null, null);
LogUtils.d("发送报警短信...");
}
14.屏蔽短信
创建新广播接收者
清单文件注册上述广播,权限android.provider.Telephony.SMS_RECEIVED
1
2
3
4
5
6<receiver android:name=".receiver.SmsBroadcastReceiver">
<!-- 接收短信 -->
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>注意:上述action在高版本被谷歌隐藏,真实情况该api还可以使用,为了使用可先降低版本,添加action在还原高版本
onReceive接收短信
1
2
3
4
5
6
7
8
9
10
11
12class SmsBroadcastReceiver extends BroadcastReceiver{·······
Object[] objs = intent.getExtras.get("pdus");
for(Object obj : objs){
SmsMessage sms = SmsMessage.createFromPdu((byte[]) obj);
//String sender = sms.getOriginatingAddress();//发送者
String content = sms.getMessageBody();//短信内容
//判断内容
if("广告短信".equals(content)){
abortBroadcast();//屏蔽,不让用户看到该条短信
}
}
15.手机播放音乐
存放本地的res/raw目录下
代码:
1
2
3
4MediaPlayer player = MediaPlayer.create(context, R.raw.music);
player.setLooping(true);//无限播放
player.setVolume(1f, 1f);//设置最大声音
player.start();//开始播放
16.手机定位
1 | 1.getSystemService获取LocationManager |
17.火星座标系转真是座标
1 | //火星坐标系转成正式数据:收费 |
18.设备管理员(源码DeviceAdminReceiver )
使用的一般步骤
1 | 1.新建广播接受者:继承DeviceAdminReceiver |
避免手机防盗的代码
1 | DevicePolicyManager mDevPolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); |