Android开发

1.安卓概述

AOT&JIT

安卓历史版本

安卓6.0推出墓碑机制

安卓历史与发展

安卓版本历史的优化更新

安卓的发展历史分为三个阶段

jit→aot→jit+aot

JIT即just-in-time动态(即时)编译,边运行边编译;AOT,ahead of time 指的是运行前编译,jit和aot是两种程序的编译方式。这两中编译方式的区别在于是否在“运行时”进行编译。

优劣比较

JIT优点:

  1. 可以根据当前硬件情况实时编译生成优机器指令
  2. 根据当前程序的运行状态生成最优的机器指令序列
  3. 当程序需要支持动态链接时,只能使用JIT
  4. 根据进程中内存的实际情况调整代码,使内存能够更充分的利用

JIT缺点:

  1. 编译需要占用运行时资源,会导致进程卡顿
  2. 由于编译时间需要占用运行时间,对某些代码的编译优化不能完全支持,需要在程序流畅和编译时间之间做权衡。
  3. 编译准备和识别频繁使用的方法需要占用时间,使得初始编译不能达到最高性能。

AOT优点

  1. 在程序运行前编译,可以避免在运行时的编译性能消耗和内存消耗
  2. 可以在程序运行初期就达到最高性能
  3. 可以显著加快程序的启动

AOT缺点

  1. 在程序运行前编译会使程序安装的时间增加
  2. 牺牲java的一致性
  3. 将提前编译的内容保存会占用更多的存储空间

安卓在2.2版本引入JIT,在kitkat时引入ART(Android Run Time),在安卓L时使用ART完全代替了Dalvik作为默认的虚拟机环境。

Dalvik

Dalvik使用JIT,使用.dex字节码,是针对安卓设备优化后的DVM所使用的运行时编译字节码。.odex是对dex的优化,deodex在系统第一次开机时会提取所有apk内的dex文件,odex优化及那个dex提前提取出,加快了开机的速度和程序运行速度

ART

ART使用AOT,在安装apk时会进行预编译,生成OAT文件,仍以odex保存,但是与Dalvik下不同,这个文件是可执行文件。dex、odex均可通过dex2oat生成oat文件以实现兼容性。在大型应用安装时需要更多时间和空间。

Android N引入混合编译

在Android N中引入了一种新的编译模式,同时使用JIT和AOT。新的ART在安装程序时使用JIT,在JIT编译了一些代码后将这些代码保存到本地,等到设备空闲的时候将保存的这些代码使用AOT编译生成可执行文件保存到本地,待下次运行时直接使用,并且不断监视代码的更新,在代码有更新后重新生成可执行文件。

  • 安卓6.0墓碑机制

    墓碑机制让处于后台的应用程序进入休眠状态结束对资源的占用。

  • 安卓7.0

  • 安卓8.0奥利奥

    • 优化硬件加速,优化画中画
    • 新的AOT(jit+aot
    • 自动填充框架、可下载字体、自适应图标、广色域色彩、webview、java8等方面支持。
  • 安卓9.0

  • 安卓10

  • 安卓11

    • 短信更新机制
    • 应用滥用权限限制
    • 增加屏幕录制内置工具
  • 安卓12.0

    • 重构底层系统
    • 全新的设计语言Material You
    • 投影优化
    • 多任务处理功能
    • 分屏模式下测试应用
  • 安卓13.0提拉米苏

    • 屏幕适配优化
    • 支持在锁屏界面添加QR扫描二维码
    • 更安全的权限管理

Android架构

android架构

Linux内核

ART(android runtime)依靠linux内核来执行底层功能,例如线程和底层内存管理。使用Linux内核可让android利用主要安全功能,并且允许设备制造商为内核开发硬件驱动程序。

硬件抽象层(HAL)

抽象硬件能力,驱动硬件,兼容适配不同厂商的硬件设备为更高级别的java api框架提供设备硬件功能使用。HAL包含多个库模块,例如相机或蓝牙、wifi模块

原生C/C++库

为安卓核心组件提供类库编译支持,例如ART和HAL,为安卓NDK访问某些原生平台库提供能力支持,比如流媒体处理、openGL、webkit等,三方lib库:scan扫描,安全加密等。

Android Runtime

简称ART,为apk提供那个虚拟空间,同时执行DEX文件,运行程序DEX文件,是一种专门为android设计的字节码格式,经过优化,使用的内存很少。编译工具链将java源码编译为DEX字节码,使其可以在安卓平台上运行。

ART部分主要功能:预先(AOT)和即时编译(JIT),优化的垃圾回收((GC),将DEX文件转换为更为紧凑的机器代码,调试采样分析器,诊断异常和崩溃报告,观察监控程序。

Java API Framework框架

java语言编写的api使用安卓os的整个功能集,这些api形成创建安卓应用所需的构建块。

app层

为系统应用或者普通应用提供能力服务

基础开发知识

git

git是一款分布式源代码管理工具,借鉴了linux基于快照的文件按版本管理系统。,为每一个文件计算一个hash值然后压缩存储到.git/objects目录内,保存提交记录和历史版本,同时提供对大工程项目的文件管理。

image-plyp.png

工作区是修改代码的地方,暂存区是文件暂时存放的地方,方便我们将代码commit提交到本地仓库。

本地仓库就是远端仓库代码在本地的镜像。

远程仓库就是中心服务器。

git clone建议使用ssh的形式,安全性比较高,虽然需要配置,但是配置好后本地可以直接进行提交。

ssh 密钥生成命令

$ ssh-keygen -t rsa

在.ssh文件夹下生成两个文件,id_rsa是私钥,id_rsa_pub是公钥。

常用命令

查看当前分支状态

git status

提交到暂存区

git add “filename1”“filename2”

git add*(慎用,会提交所有修改后的代码)

提交到本地仓库

git commit -m "message"

提交到远程仓库

git push

还原某个文件

git checkout filename

还原某个版本的提交

git reset commitid

安卓四大组件

activity、services、broadcast receiver和content provider

image-tmad.png

image-qbzk.png

activity

image-ibmm.png

image-lacu.png

MainActivity继承自AppCompactActivity,首先必须要有onCreate方法。

AppCompactActivity兼容性更好,使用这个注意theme改成AppCompact。当然使用Activity也行。

image-bjnp.png

xml是静态布局,动态布局可以在类方法中代码实现。

布局优化尽可能使得布局更加扁平,能在一层实现就尽量不要嵌套。

activity显式调用,action隐式调用。

launcher mainactivity是启动应用首先展示的页面。

生命周期

image-zehd.png

image-vxxp.png

onCreate是最先调用的,此时页面对用户还为可见,到onResume才真正对用户可见。不同activity之间的切换和状态是通过栈来进行维护的。

onPause时失去焦点,保留可见性,但是失去与用户的交互,比如当弹出窗口时,必须关闭窗口才能与底下的功能交互。

onStop比较危险,系统可能会回收占用的资源,当调用restart重新启用时,需要重新渲染和装填。

onDestroy负责资源的释放

image-ftdg.png

查看详细activity任务栈信息

$ abd shell dumpsys activity activities

定义启动模式

image-nytu.png

image-crkg.png

image-wfby.png

singleInstence给activity独占一个栈,始终是该栈的唯一成员,一直沿用此栈。

singleTop关注activity是否是在栈顶,如果在栈顶则直接将此栈对用户可见直接使用这个activity,如果不在栈顶,那么新创建一个activity放在栈顶。

singleTask栈中只有唯一的activity实例,使用时其之前的acivity全部出栈。

image-mudk.png

image-kgaj.png

image-egxv.png

image-nwwq.png

singleTask和newTask区别

image-zbyb.png

laucher category指定启动页面

image-joda.png

Activity避坑指南

以下问题是项目过程中必不可少的问题

image-nbir.png

避免在activity中引用长生命周期对象或者被长生命周期对象引用,避免持有activity的引用,如果必须持有,使用弱引用。

生命周期管理,确保正确的释放资源和取消注册监听器。取消注册监听器可以在stop的时候完成。

横竖屏切换是,布局会进行调整以优化用户体验,activity会销毁并重新创建。

注意用户体验

Service

image-sjvu.png

service是后台服务,比如后台的计算,按照算法进行分析,将分析结果反馈给页面。

当activty可见的时候肯定是优先级最高的。

image-dvja.png

image-xyri.png

intentService基本上是一次性的服务,通常使用service即可

创建service后会在manifest中创建service标签,exported关键字声明服务是否对外可见,如果只是应用内部使用的,那应该声明为false,如果该服务对外提供给其他应用调用应该声明为true,exported能为false就绝对不要设置为true,exported=true存在安全性问题,必须为true那么需要进行严格的控制(做try catch处理,比如数据类型不一致可能会导致程序崩溃)严格检查参数是否符合标准。

image-jcuw.png

绑定服务可以很方便的进行进程间通信,建立服务与activity的关联,同时绑定生命周期,当activity生命周期结束时,service自动结束和销毁。

image-uzxn.png

stopSelf是service内部调用

image-dewi.png

无限期运行是理想状态。

image-zxbz.png

image-yfdt.png

image-owki.png

耗时的任务一定不要放在主线程,容易导致程序无响应ARR, false stop。执行耗时的后台操作需要放到子线程执行。

image-frae.png

image-vqqn.png

前台service和activity超过10s报ARR,后台service超过几十秒报ARR

image-xjfq.png

image-ypav.png

最好在serviceDisconnected里面做一下unBind,

image-iefu.png

image-eptf.png

image-gtun.png

image-mhcv.png

image-dlor.png

seializable需要磁盘io,导致效率非常低,

反序列化数据的顺序要与序列化数据的顺序保持一致。比如代码中,序列化先序列化name再序列化age,那么反序列化也是先读string再读int

image-xyoz.png

image-nxma.png

image-aksv.png

image-hloc.png

image-pfjr.png