-- 在application的oncreate方法前
StrictMode.setThreadPolicy(new StrictModel.ThreadPolicy.Builder().detectAll().penaltyLog().build());
线程检测策略; 虚拟机检测策略-- ANR典型的分析情况
1.如果TOTAL的和接近100,有可能是因为当前使用的app占用的cpu太高,导致系统将你的杀死。
2.如果TOTAL很小,则说明线程被阻塞了,主线程在等待下条消息的进入,任务在等待时anr。
3.如果ioWait很高,则说明是io操作导致的ANR一般有三种类型:
1:KeyDispatchTimeout(5 seconds) --主要类型
按键或触摸事件在特定时间内无法得到响应
2:BroadcastTimeout(10 seconds)
BroadcastReceiver在的onRecieve运行在主线程中,短时间内无法处理完成导致
3:ServiceTimeout(20 seconds) --小概率类型
Service的各个声明周期在特定时间内无法处理完成1.ANR关键点:ioWait很高,ContentResolver in AsyncTask onPostExecute
首先看到total中ioWait很高,说明是io操作导致的;
具体原因,可以看到关键词sqlite,ContentResolver
2.ANR关键词OSNetworkSystem.receiveStream,net
3.ANR关键词:VMWAIT,VMRuntime.trackExternalAllocation-- Service导致的ANR
Service binderService与ANR?
Service 里面开启一个线程处理网络数据,不要用ipc bindService的方式,用广播通知数据更新。
问题出在onStartCommand方法中.
Service也是运行在主线程的,你在里边做耗时操作肯定会anr的 你应该在service 里边在开一个子线程去做耗时的操作呀.
service anr关键方法.
Android O StartService的 anr timeout 流程分析- binderService需要context上下文;跨进程时,只能用StartService(),因为上下文对象对其无用?
写native的binder service- https://github.com/cloudchou/NativeBinderTest
内联函数模版。
startForegroundService是同步的(阻塞),startService是异步的(命令一次性下发,不阻塞)。-- AppOpsManager.checkOpNoThrow()
判断应用在前后台的方法-https://github.com/wenmingvs/AndroidProcess
AppLock应用锁,保护你的隐私- https://github.com/lizixian18/AppLock使用UsageStatsManager需要获取权限相关代码:
/**
* 判断是否已经获取 有权查看使用情况的应用程序 权限
*
* @param context
* @return
*/
public static boolean isStatAccessPermissionSet(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
PackageManager packageManager = context.getPackageManager();
ApplicationInfo info = packageManager.getApplicationInfo(context.getPackageName(), 0);
AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, info.uid, info.packageName);
return appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, info.uid, info.packageName) == AppOpsManager.MODE_ALLOWED;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} else {
return false;
}
}
/**
* 查看是存在查看使用情况的应用程序界面
*
* @return
*/
public static boolean isNoOption(Context context) {
PackageManager packageManager = context.getPackageManager();
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}
/**
* 转跳到 有权查看使用情况的应用程序 界面
*
* @param context
*/
public static void startActionUsageAccessSettings(Context context) {
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
context.startActivity(intent);
}获取栈顶包名的方法有好几个,根据不同的android版本方法也不一样,在android5.0以上,推荐使用UsageStatsManager来获取,具体方法:
public String getLauncherTopApp(Context context, ActivityManager activityManager) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
List<ActivityManager.RunningTaskInfo> appTasks = activityManager.getRunningTasks(1);
if (null != appTasks && !appTasks.isEmpty()) {
return appTasks.get(0).topActivity.getPackageName();
}
} else {
//5.0以后需要用这方法
UsageStatsManager sUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
long endTime = System.currentTimeMillis();
long beginTime = endTime - 10000;
String result = "";
UsageEvents.Event event = new UsageEvents.Event();
UsageEvents usageEvents = sUsageStatsManager.queryEvents(beginTime, endTime);
while (usageEvents.hasNextEvent()) {
usageEvents.getNextEvent(event);
if (event.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) {
result = event.getPackageName();
}
}
if (!android.text.TextUtils.isEmpty(result)) {
return result;
}
}
return "";
}-- Android 5.0 应用使用情况统计信息
要使用android.app.usage API ,首先必须要在AndroidManifest.xml中声明权限,如下:
<uses-permission Android:name="android.permission.PACKAGE_USAGE_STATS" />
然后需要打开允许查看使用情况的应用界面,引导用户授权,如下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { try { startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)); } catch (Exception e) { e.printStackTrace(); }}@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static boolean checkUsagePermission(Context context) {
AppOpsManager appOpsManager = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, android.os.Process.myUid(),ontext.getPackageName());
return mode == AppOpsManager.MODE_ALLOWED;
}-- Android权限管理与AppOpsManager,在SDK 19中Google引入了AppOpsManager
值得一提的是这个api是在19新加入的,所以要注意加个判断,其实 Android 官方一直有这个设置权限的入口,Setting---Security---AppOps 只是一直被google隐藏了。
Android权限管理与AppOpsManager-
知权限管理的功能AppOpsManager,信息的储存在“data/system/appops.xml”文件中
if (Build.VERSION.SDK_INT >= 19){} 而AppOps所管理的是所有可能涉及用户隐私和安全的操作,包括 access notification, keep weak lock, activate vpn, display toast 等等,有些操作是不需要Manifest里申请权限的。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { //KITKAT 19
appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
int checkResult = appOpsManager.checkOpNoThrow(
AppOpsManager.OPSTR_FINE_LOCATION, Binder.getCallingUid(), context.getPackageName());
if(checkResult == AppOpsManager.MODE_ALLOWED){
Toast.makeText(context,"有权限",Toast.LENGTH_LONG).show();
Log.e("jijiaxin","有权限");
}else if(checkResult == AppOpsManager.MODE_IGNORED){
// TODO: 只需要依此方法判断退出就可以了,这时是没有权限的。
Toast.makeText(context,"被禁止了",Toast.LENGTH_LONG).show();
Log.e("jijiaxin","被禁止了");
}else if(checkResult == AppOpsManager.MODE_ERRORED){
Toast.makeText(context,"出错了",Toast.LENGTH_LONG).show();
Log.e("jijiaxin","出错了");
}else if(checkResult == 4){
Toast.makeText(context,"权限需要询问",Toast.LENGTH_LONG).show();
Log.e("jijiaxin","权限需要询问");
}
}public boolean selfPermissionGranted(Context context, String permission) {
boolean ret = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (targetSdkVersion >= Build.VERSION_CODES.M) {
ret = context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
} else {
ret = PermissionChecker.checkSelfPermission(context, permission) == PermissionChecker.PERMISSION_GRANTED;
}
}
return ret;
}在Android5.0,即Lollipop(api level 21)之前,大家都幸福的使用如下代码来获得当前运行的app,即所谓的top Activity:
ActivityManager activityManager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = activityManager.getRunningTasks(1).get(0).topActivity;Marshmallow(api level 23),M = 23;
//检测用户是否对本app开启了“Apps with usage access”权限
private boolean hasPermission() {
AppOpsManager appOps = (AppOpsManager)
getSystemService(Context.APP_OPS_SERVICE);
int mode = 0;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
android.os.Process.myUid(), getPackageName());
}
return mode == AppOpsManager.MODE_ALLOWED;
}if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
final AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
android.os.Process.myUid(), context.getPackageName());
if (mode == AppOpsManager.MODE_ALLOWED) {
return true;
} else {
if (viewWrapper != null) {
openPermissonActivity(viewWrapper);
}
}
}获取栈顶Activity-https://github.com/apkkids/GetTopActivity
在实际开发中,经常需要在程序中打开一些物理资源,如数据库连接,网络连接,磁盘文件等,打开这些资源之后必须显示关闭,否则将会引起资源泄露。 JVM不是提供了垃圾回收机制吗?JVM的垃圾回收机制不会回收这些资源吗?答案是不会,垃圾回收机制属于Java内存管理的一部分,它只是负责回收堆内存中分配出来的内存,至于程序中打开的物理资源,垃圾回收机制是无能为力的。
IO流关闭顺序。
一般情况下是:先打开的后关闭,后打开的先关闭
另一种情况:看依赖关系,如果流a依赖流b,应该先关闭流a,再关闭流b,例如处理流a依赖节点流b,应该先关闭处理流a,再关闭节点流b
其实Java方法的返回值,跟参数的传递一样,都是基本类型返回值,而非基本类型,则返回引用.GradientDrawable.setColor
private void setGradientDrawableColor(int[] colors) {
GradientDrawable drawable = null;
if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
drawable = new GradientDrawable();
//俩设置方法其实就是对应着带参构造参数的那俩参数
drawable.setOrientation(GradientDrawable.Orientation.TOP_BOTTOM);
drawable.setColors(colors);
}else{
drawable = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, colors);
setBackgroundDrawable(drawable);
}
}GradientDrawable gd = (GradientDrawable) getBackground();
int[] colors = {0xFFFF0000, 0xFFCC0099};
if (android.os.Build.VERSION.SDK_INT >= 16) {
gd = gd.mutate(); // For safe resource handling
gd.setColors(colors);
} else {
// Fallback for APIs under 16.
GradientDrawable ngd = new GradientDrawable(/* Orientation variable */, colors);
// You may have to set other qualities of `ngd` here to make it match.
setBackgroundDrawable(ngd);
}if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
activity.getWindowManager().getDefaultDisplay().getRealMetrics(metric);
LogUtil.d(TAG, "####### dumpScreenInfo RealMetrics (width, height) = ( "
+ metric.widthPixels + " , " + metric.heightPixels + " )");
}-- synchronized(Lock)与Lock.notify()
在并发量比较小的情况下,使用synchronized是个不错的选择,但是在并发量比较高的情况下,其性能下降很严重,此时ReentrantLock是个不错的方案。
需要注意的是,wait()和notify()必须在synchronized代码块中调用。 --
Android4.0之后开始支持WifiDirect技术,即Wifi直连,做为一种通讯方式,它的优势在于传输速度快传输距离远。 if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
setBackgroundDrawable( null );
}
else {
setBackground( null );
}int space = 0;
int columWidth = 0;
int newSpace = 0;
int newColumWidth = 0;
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
space = gridView.getVerticalSpacing(); // 统计所有子项的总高度
} else {
space = 0;
} if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
columWidth = gridView.getColumnWidth();
} else{
Field field = GridView.class.getDeclaredField("mColumnWidth");
field.setAccessible(true);
Integer value = (Integer) field.get(this);
field.setAccessible(false);
columWidth = value.intValue();
}
} catch (Exception ex) {
newSpace = space;
newColumWidth = columWidth;
}-- Android SDK 升级到 23 之后,getDrawable和getColor方法提示过时。
getResources().getColor 替换成 ContextCompat.getColor
getResources().getDrawable 替换成 ContextCompat.getDrawable例子如下:
int colorInt = getResources().getColor(R.color.colorAccent);//返回的是color的int类型值:-49023
int colorInt2 = ContextCompat.getColor(this, R.color.colorAccent);//返回的是color的int类型值:-49023Drawable drawable = getResources().getDrawable(R.mipmap.ic_launcher);
Drawable drawable2 = ContextCompat.getDrawable(this,R.mipmap.ic_launcher);-- BigDecimal的构造函数 public BigDecimal(double val) 损失了double 参数的精度.使用BigDecimal的以String为参数的构造函数:public BigDecimal(String val) 来替代。
-- Handler延迟
if (isPausedBy50() && mRecorderHandler != null) {
mRecorderHandler.postDelayed(new Runnable() {
@Override
public void run() {
}
}, 300);
}
android中多语言适配不同ui
转载本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
多语言适配
ar-阿拉伯语de -德语es 西班牙hi 印地语in 印度语fr 法
System xml 读入一行