Android 其他问题点

关注
Android 其他问题点www.shan-machinery.com1 Serializable与Parcelable 区别 Sericalizable 是java 提供的进行序列化的方式,对对象整体序列化,更适合网络数据进行序列化的时候使用。Parcelable 是android提供的一种序列化的方式,可以将一个完整的对象进行分解,对部分分别序列化,效率更高,更适合内存中进行数据传输的时候使用。 2 Android为什么使用Bundle 传输数据,为啥不是hashMap

2个原因: (1)小的数据量:Bundle 内部封装了ArrayMap进行的存储,ArrayMap本身就是适合小数据量的存储的,Bundle的数据传递不能超过1M,刚好也是小数据量传输,HashMap适合大数据传输,因此Bundle更合适

(2)序列化方式: Intent传递数据的时候,需要的是基本数据类型或者是序列化的数据,而序列化的数据必须是通过Parcelable序列化的,Bundle就是实现的Parcelable的序列化,而HashMap则实现的是Serializable

Bitmap的大小计算

不考虑分辨率作用:长X宽X4 考虑分辨率及每个像素点占用的字节: 长x宽x字节数* targetDpi/ 图片所在目录分辨率(比如我target是xh 320的,但图片放在mdpi下面则是 320/160) ps:ARGB-8888—32位–4字节、RGB-565----16位-----2字节 在这里插入图片描述

aapt作用

Android Asset Packing Tool (Android资源打包工具) 编译Android下的资源resource文件。 AAPT2 支持通过增量编译实现更快的资源编译,资源处理拆分为2个步骤:编译+链接 编译:将资源文件编译为二进制格式文件(.flat) 链接:将编译后的所有文件合并,打包成一个单独文件 在这里插入图片描述

讲下Context

类结构:Context可以理解为“上下文”:它贯穿整个应用;Activity切换,Service启动都需要Context。 Context 是一个抽象类,它的实现分成ContextImpl 和ContextWrapper ,其中ContextWrapper又有3个实现类:Application、Service、ContextThemeWrapper,ContextThemeWrapper的实现类是Activity。

关系:所有Context都是在应用的主线程ActivityThread中创建的,由于 Application,Service,Activity的祖先都是Context抽象类,所以在创 建它们的同时也会为每一个类创建一个ContextImpl类,ContextImpl 是Context的之类,真正实现Context功能方法的类。因此 Application,Service,Activity都关联着一个ContextImpl对象。

可能存在的问题: 尽量少用Context对象去获取静态变量,静态方法,以及单例对象。 以免导致内存泄漏

Context内存泄漏问题 静态资源导致的内存泄漏 单例模式导致内存泄漏

LayoutInflate 相关参数

LayoutInflater 有好几个inflate方法,但内部最终都会调用到三个参数的inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot的方法。这里需要解释2个点,root,和 attachToRoot root 不为null 的时候,会调用generateLayoutParams生成相关LayoutParam参数 attachToRoot=true ,会调用addView的方法

apk打包流程

在这里插入图片描述 (1)打包资源文件。 (2)处理aidl文件,生成相应java 文件。对于没有使用到aidl的android工程,可以跳过此步骤。 (3)编译工程源代码,生成相应class 文件。 这一步调用了javac编译工程src目录下所有的java源文件,生成的class文件位于工程的bin\classes目录下,上图假定编译工程源代码时程序是基于android SDK开发的,实际开发过程中,也有可能会使用android NDK来编译native代码,因此,如果可能的话,这一步还需要使用android NDK编译C/C++代码,当然,编译C/C++代码的步骤也可以提前到第一步或第二步。通过Java Compiler编译R.java、Java接口文件、Java源文件,生成.class文件。 (4)转换所有class文件,生成classes.dex文件。Android虚拟机的可执行文件为dex格式,所以需要此步骤。 (5)打包生成apk。打包后的res文件夹(除res/raw资源被原装不动地打包进APK之外)、打包后类文件(.dex文件)、libs文件(包括.so文件,当然很多工程都没有这样的文件,如果你不使用C/C++开发的话)、resources.arsc、assets、AndroidManifest.xml打包成apk文件。 (6)对apk文件进行签名。 (7)对签名后的apk文件进行对其处理。在 Android SDK 中包含一个名为 “zipalign” 的工具,它能够对打包后的 app 进行优化。 即对签名后的apk进行对齐处理。

app启动优化 Android 黑白屏优化 (1)修改AppTheme,设置系统取消预览(空白窗体)为true,或者设置空白窗体颜色为透明色 (不被推荐,在不同手机上可能会有不同的效果)

falsetrue

(2) 自定义继承AppTheme的主题,将Activity的theme 设置为自定义的主题,在Activity的onCreate方法中在super.onCreate 和 setContentView 方法之前调用setTheme方法,将主题设置为最初的AppTheme 1 自定义继承AppTheme的主题(drawble设置的是layer-list的xml)

@drawable/abc_vector_testtruetrue

2 将Activity的theme 设置为自定义的主题

3 在Activity的onCreate方法中在super.onCreate 和 setContentView 方法之前调用setTheme方法,将主题设置为最初的AppTheme

class SplashActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {setTheme(R.style.AppTheme_LauncherTheme)super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)}}}

(3)Application、Activity的onCreate方法中减少耗时操作或不必要的三方初始化( 可以通过异步线程或者懒加载的方式,减少onCreate方法中的耗时操作)。 (查看耗时时间: 方式1:可以通过adb 命令 查看启动耗时adb shell am start -W com.example.SplashActivity, 会显示三个信息:ThisTime: 最后一个Activity启动时间 totalTime:一系列Activity启动时间 waitTime:总启动时间,包括了系统在冷启动时,需要加载的app信息到内存的时间, 这里只需要看totalTime即可

方式2 : val file=File(Environment.getDataDirectory().toString(),"time.trace"); Debug.startMethodTracing(file.absolutePath); init() Debug.stopMethodTracing())

进程保活 进程保活的关键点有两个, 1、是进程优先级的理解,优先级越高存活几率越大。 2、是弄清楚哪些场景会导致进程会 kill。 所以我们需要 (1)让进程优先级提高(oom_adj数值越大优先级越低,oom_adj 存储在 proc/PID/oom_adj 文 件中,直接 adb shell 进入手机根目录查看这个文件即可) (2)在进程被kill之后能够唤醒 ps:进程优先级:前台进程(Foreground process)、可见进程、服务进程、后台进程、空进程,优先级依次降低。

看下进程被kill的场景

场景一

1.点击 home 键使 app 长时间停留在后台,内存不足被 kill。 这种情况下,需要你的app至少运行一个service,通过service启动的时候调用Service.startForground() 设置成前台服务。 startForground的方式在Android4.3 之后会在通知栏弹出一个通知,解决这个问题可以同时再开启一个service,然后新启动的service stop掉后,通知栏也会消失 Android 7.1 之后google修复了这个bug,暂时没有好的解决方案。

场景二

2、锁屏后,为节约资源,省电机制会kill掉后台进程。 可以注册广播通过对锁屏(ACTION_SCREEN_OOF)解锁(ACTION_USER_PRESENT)事件监听,锁屏后开启一个1px的透明Activity,让这个进程优先级最高,解锁后销毁这个Activity

场景三

3、手机自带清理工具的清理。 加入手机白名单

其他方式

开启双进程守护

如何缩减 APK 包大小? 1、代码

不使用的代码及时删除

使用 proguard 混淆代码,它会对不用的代码做优化,并且混淆后也能够减少安装包的大小。

native code 的部分,大部分只支持 armabi 与 x86 的架构即可

2、资源

使用lint 工具查找没使用到的资源,去除不使用的图片、string、xml等

图片资源可以使用webp 格式图片代替,另外还可以使用tinypng对图片进行压缩预处理

so库

so库可以只支持armabi-v7a即可

进程保活

当前业界的 Android 进程保活手段主要分为** 黑、白、灰 **三种,其大致的实现思路如下: 黑色保活:不同的 app 进程,用广播相互唤醒(包括利用系统提供的广播进行唤醒) 白色保活:启动前台 Service 灰色保活:利用系统的漏洞启动前台 Service

黑色保活

所谓黑色保活,就是利用不同的 app 进程使用广播来进行相互唤醒。举个 3 个比较常见的场 景:

场景 1:开机,网络切换、拍照、拍视频时候,利用系统产生的广播唤醒 app

场景 2:接入第三方 SDK 也会唤醒相应的 app 进程,如微信 sdk 会唤醒微信,支付宝 sdk 会唤醒支付宝。由此发散开去,就会直接触发了下面的 场景 3

场景 3:假如你手机里装了支付宝、淘宝、天猫、UC 等阿里系的 app,那么你打开任意一个 阿里系的 app 后,有可能就顺便把其他阿里系的 app 给唤醒了。(只是拿阿里打个比方,其 实 BAT 系都差不多)

白色保活

白色保活手段非常简单,就是调用系统 api 启动一个前台的 Service 进程,这样会在系统的 通知栏生成一个 Notification,用来让用户知道有这样一个 app 在运行着,哪怕当前的 app 退到了后台。如LBE 和 QQ 音乐这样

灰色保活

灰色保活,这种保活手段是应用范围最广泛。它是利用系统的漏洞来启动一个前台的 Service 进程,与普通的启动方式区别在于,它不会在系统通知栏处出现一个 Notification,看起来就 如同运行着一个后台 Service 进程一样。这样做带来的好处就是,用户无法察觉到你运行着 一个前台进程(因为看不到 Notification),但你的进程优先级又是高于普通后台进程的。那 么如何利用系统的漏洞呢,

大致的实现思路和代码如下:

(1):API < 18,启动前台 Service 时直接传入 new Notification();

(2):API >= 18 && API =25 暂无解决方案

//设置 service 为前台服务,提高优先级 if (Build.VERSION.SDK_INT < 18) {//Android4.3 以下 ,此方法能有效隐藏 Notification 上的图标service.startForeground(GRAY_SERVICE_ID, new Notification()); } else if(Build.VERSION.SDK_INT>18 && Build.VERSION.SDK_INT//Android7.1 google 修复了此漏洞,暂无解决方法(现状:Android7.1 以上app 启动后通知栏会出现一条"正在运行"的通知消息) service.startForeground(GRAY_SERVICE_ID, new Notification());}

熟悉 Android 系统的童鞋都知道,系统出于体验和性能上的考虑,app 在退到后台时系统并 不会真正的 kill 掉这个进程,而是将其缓存起来。打开的应用越多,后台缓存的进程也越多。 在系统内存不足的情况下,系统开始依据自身的一套进程回收机制来判断要 kill 掉哪些进程, 以腾出内存来供给需要的 app。这套杀进程回收内存的机制就叫 Low Memory Killer ,它是 基于 Linux 内核的 OOM Killer(Out-Of-Memory killer)机制诞生。

其他(加入白名单)

有些手机厂商把这些知名的 app 放入了自己的白名单中,保证了进程不死来提高用户体验 (如微信、QQ、陌陌都在小米的白名单中)。如果从白名单中移除,他们终究还是和普通 app 一样躲避不了被杀的命运

** Intent Service 有什么用**

Intent Service 可用于执行后台耗时的任务,当任务执行完成后会自动停止,同时由于IntentService是服务的原因,不同于Service,IntentService 可自动创建子线程来执行任务,导致它的优先级比单纯的线程要高,不容易被系统杀死,所以IntentService 比较适合执行一些高优先级的后台任务

** App 启动流程图**

在这里插入图片描述

https://www.shan-machinery.com