android开发踩坑记

oppo手机无法在后台启动activity

在做im语音通话功能时,应用切到后台无法收到呼叫,排查发现信令已收到,启动activity的方法已经调用,但是呼叫页面无法启动. 最开始怀疑是因为新插件化引起的,后来发现旧插件化的工程也无法换气呼叫页,最后在无插件化的demo中发现也无法唤起. 最后发现是oppo手机本身限制,试了华为,小米可以唤起.网上说需要开启自启动权限,实际开启了悬浮窗权限即可唤起.

网上解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//获取ActivityManager

ActivityManager mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);

//获得当前运行的task

List<ActivityManager.RunningTaskInfo> taskList = mAm.getRunningTasks(100);

for(ActivityManager.RunningTaskInfo rti : taskList) {

    //找到当前应用的task,并启动task的栈顶activity,达到程序切换到前台

    if(rti.topActivity.getPackageName().equals(context.getPackageName())) {

        Intent LaunchIntent =new Intent(Intent.ACTION_MAIN);

        ComponentName cn =new ComponentName(Constant.PACKAGE,rti.topActivity.getClassName());

        LaunchIntent.setComponent(cn);

        startActivity(LaunchIntent);

        break;

    }

}

使用这段代码的时候最好是判断app在后台之后才使用,在前台的时候调用这段代码,会导致这部分代码之后的程序不执行! 使用

1
2
3
4
5
Intent resultIntent =newIntent(context,Class.forName(rti.topActivity.getClassName()));

            resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK| Intent.FLAG_ACTIVITY_SINGLE_TOP);

            context.startActivity(resultIntent);

仍无法正常唤起.

上述方案暂未尝试.

OPPO 在R9系列以上的手机,除非用户开启了“自启动”权限,否则你会在日志中看到一条拦截信息

1
OppoAppStartupManager: InterceptInfo com.gx.dfttsdk com.gx.dfttsdk com.gx.dfttsdk.MainActivity com.moban.baidu true

可以看OPPO ColorOS官方社区的帖子:http://bbs.coloros.com/forum.php?mod=viewthread&tid=527188

这是OPPO 系统更新后的拦截操作,禁止应用私自唤起后台应用,除非获得用户允许!

华为手机mlastsrvview导致内存泄露

反射设置这个字段为null应该是可以的,关于这个字段自己经过测试发现是华为手机特有的一个字段,google原生系统并没有这个字段。这个字段的作用到底是什么,自己写了测试demo得出的结论就是该字段是用来存储上一个页面view的,举个简单的例子ABC三个页面当你从C页面回退到B页面时,此时mlastsrvview保存这的就是C的decorview,当从B退回到A页面此时mlastsrvview保存的就是B的decorview。 所以想要发生内存泄露很简单,当从B回到A页面后停留一段时间leakcanary就会报出文章第二张图中的泄露问题,因为decorview一直被mlastsrvview引用着无法释放内存,知道原因后那么解决方法就很简单了,就是通过反射在页面销毁的时候通过反射将mlastsrvview设置为null就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class FixMemLeak {

private static Field field;
private static boolean hasField = true;

public static void fixLeak(Context context) {
if (!hasField) {
return;
}
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) {
return;
}

String[] arr = new String[]{"mLastSrvView"};
for (String param : arr) {
try {
if (field == null) {
field = imm.getClass().getDeclaredField(param);
}
if (field == null) {
hasField = false;
}
if (field != null) {
field.setAccessible(true);
field.set(imm, null);
}
} catch (Throwable t) {
t.printStackTrace();
}
}
}
}
坚持原创技术分享,您的支持将鼓励我继续创作!