冬困秋乏春无力-来一份全面的面试宝典洗洗脑,2024年最新小公司程序员面试

这种方式启动的话,需要注意一下几个问题:
第一: 当我们通过 startService 被调用以后,多次在调用 startService(),onCreate()方法也只会被调用一次,而 onStartConmon()会被多次调用当我们调用 stopService()的时候,onDestroy()就会被调用,从而销毁服务。
第二: 当我们通过 startService 启动时候,通过 intent 传值,在 onStartConmon()方法中获取值的时候,一定要先判断 intent 是否为 null。
通 过 bindService() 方 式 进 行 绑 定 , 这 种 方 式 绑 定 service , 生 命 周 期 走 法 :bindService–>onCreate()–>onBind()–>unBind()–>onDestroy() bingservice 这种方式进行启动service 好处是更加便利 activity 中操作 service,比如加入 service 中有几个方法,a,b ,如果
要在 activity 中调用,在需要在 activity 获取 ServiceConnection 对象,通过 ServiceConnection来获取 service 中内部类的类对象,然后通过这个类对象就可以调用类中的方法,当然这个类需要继承 Binder 对象

3 、Activity 的启动过程(不要回答生命周期)

app 启动的过程有两种情况,第一种是从桌面 launcher 上点击相应的应用图标,第二种是在activity 中通过调用 startActivity 来启动一个新的 activity。

我们创建一个新的项目,默认的根 activity 都是 MainActivity,而所有的 activity 都是保存在堆栈中的,我们启动一个新的 activity 就会放在上一个 activity 上面,而我们从桌面点击应用图标的时候,由于 launcher 本身也是一个应用,当我们点击图标的时候,系统就会调用startActivitySately(),一般情况下,我们所启动的 activity 的相关信息都会保存在 intent 中,比如 action , category 等 等 。 我 们 在 安 装 这 个 应 用 的 时 候 , 系 统 也 会 启 动 一 个PackaManagerService 的管理服务,这个管理服务会对AndroidManifest.xml 文件进行解析,从而得到应用程序中的相关信息,比如 service,activity,Broadcast 等等,然后获得相关组件的信息。当我们点击应用图标的时候,就会调用 startActivitySately()方法,而这个方法内部则是调用 startActivty(),而 startActivity()方法最终还是会调用startActivityForResult()这个方法。而在 startActivityForResult()这个方法。

因为 startActivityForResult()方法是有返回结果的,所以系统就直接给一个-1,就表示不需要结果返回了。而 startActivityForResult()这个方法实际是通过 Instrumentation 类中的 execStartActivity()方法来启动 activity Instrumentation 这个类主要作用就是监控程序和系统之间的交互。而在这个 execStartActivity()方法中会获取ActivityManagerService 的代理对象,通过这个代理对象进行启动 activity。启动会就会调用一个 checkStartActivityResult()方法,如果说没有在配置清单中配置有这个组件,就会在这个方法中抛出异常了。当然最后是调用的是Application.scheduleLaunchActivity()进行启动 activity,而这个方法中通过获取得到一个 ActivityClientRecord 对象,而这个ActivityClientRecord 通过handler 来进行消息的发送,系统内部会将每一个 activity 组件使用 ActivityClientRecord 对象来进行描述,而 ActivityClientRecord对象中保存有一个 LoaderApk 对象,通过这个对象调用handleLaunchActivity 来启动 activity 组件,而页面的生命周期方法也就是在这个方法中进行调用。

4 、Broadcast注册方式与区别

此处延伸: 什么情况下用动态注册
Broadcast 广播,注册方式主要有两种.第一种是静态注册,也可成为常驻型广播,这种广播需要在 Androidmanifest.xml 中进行注册,这中方式注册的广播,不受页面生命周期的影响,即使退出了页面,也可以收到广播这种广播一般用于想开机自启动啊等等,由于这种注册的方式的广播是常驻型广播,所以会占用CPU 的资源。

第二种是动态注册,而动态注册的话,是在代码中注册的,这种注册方式也叫非常驻型广播,收到生命周期的影响,退出页面后,就不会收到广播,我们通常运用在更新 UI 方面。这种注册方式优先级较高。最后需要解绑,否会会内存泄露

广播是分为有序广播和无序广播。

5 、HttpClient 与 与 HttpUrlConnection 的区别

此处延伸: Volley 里用的哪种请求方式(2.3 前 HttpClient,2.3 后 HttpUrlConnection)

首先 HttpClientHttpUrlConnection 这两种方式都支持 Https 协议,都是以流的形式进行上传或者下载数据,也可以说是以流的形式进行数据的传输,还有 ipv6,以及连接池等功能。HttpClient 这个拥有非常多的 API,所以如果想要进行扩展的话,并且不破坏它的兼容性的话,很难进行扩展,也就是这个原因,Google 在 Android6.0 的时候,直接就弃用了这个 HttpClient.

HttpUrlConnection 相对来说就是比较轻量级了,API 比较少,容易扩展,并且能够满足Android 大部分的数据传输。比较经典的一个框架 volley,在 2.3 版本以前都是使用 HttpClient,在 2.3 以后就使用了 HttpUrlConnection

6 、java 虚拟机和 Dalvik 虚拟机的区别
Java 虚拟机:

1、java 虚拟机基于栈。 基于栈的机器必须使用指令来载入和操作栈上数据,所需指令更多更多。
2、java 虚拟机运行的是 java 字节码。(java 类会被编译成一个或多个字节码.class 文件)

Dalvik 虚拟机:

1、dalvik 虚拟机是基于寄存器的
2、Dalvik 运行的是自定义的.dex 字节码格式。(java 类被编译成.class 文件后,会通过一个
dx 工具将所有的.class 文件转换成一个.dex 文件,然后 dalvik 虚拟机会从其中读取指令和数据
3、常量池已被修改为只使用 32 位的索引,以 简化解释器。
4、一个应用,一个虚拟机实例,一个进程(所有 android 应用的线程都是对应一个 linux 线程,都运行在自己的沙盒中,不同的应用在不同的进程中运行。每个 android dalvik 应用程序都被赋予了一个独立的 linux PID(app_*))

7 、进程保活(不死进程)

此处延伸: 进程的优先级是什么
当前业界的 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),但你的进程优先级又是高于普通后台进程的。那么如何利用系统的漏洞呢,大致的实现思路和代码如下:
思路一: API < 18,启动前台 Service 时直接传入 new Notification();
思路二: API >= 18,同时启动两个 id 相同的前台 Service,然后再将后启动的 Service 做 stop处理

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

进程的重要性,划分 5 级:

前台进程 (Foreground process)
可见进程 (Visible process)
服务进程 (Service process)
后台进程 (Background process)
空进程 (Empty process)

了解完 Low Memory Killer,再科普一下 oom_adj。什么是 oom_adj?它是 linux 内核分配给每个系统进程的一个值,代表进程的优先级,进程回收机制就是根据这个优先级来决定是否进行回收。对于 oom_adj 的作用,你只需要记住以下几点即可:进程的 oom_adj 越大,表示此进程优先级越低,越容易被杀回收;越小,表示进程优先级越高,越不容易被杀回收

普通 app 进程的 oom_adj>=0,系统进程的 oom_adj 才可能<0

有些手机厂商把这些知名的 app 放入了自己的白名单中,保证了进程不死来提高用户体验(如微信、QQ、陌陌都在小米的白名单中)。如果从白名单中移除,他们终究还是和普通app 一样躲避不了被杀的命运,为了尽量避免被杀,还是老老实实去做好优化工作吧。所以,进程保活的根本方案终究还是回到了性能优化上,进程永生不死终究是个彻头彻尾的伪命题!

8 、讲解一下 Context

Context 是一个抽象基类。在翻译为上下文,也可以理解为环境,是提供一些程序的运行环境基础信息。Context 下有两个子类,ContextWrapper 是上下文功能的封装类,而 ContextImpl则是上下文功能的实现类。而ContextWrapper又有三个直接的子类,ContextThemeWrapper、Service 和 Application。其中,ContextThemeWrapper 是一个带主题的封装类,而它有一个直接子类就是 Activity,所以 Activity 和 Service 以及 Application 的 Context 是不一样的,只有Activity 需要主题,Service 不需要主题。Context 一共有三种类型,分别是 Application、Activity和 Service。这三个类虽然分别各种承担着不同的作用,但它们都属于 Context 的一种,而它们具体 Context 的功能则是由 ContextImpl 类去实现的,因此在绝大多数场景下,Activity、Service 和 Application 这三种类型的 Context 都是可以通用的。不过有几种场景比较特殊,比如启动 Activity,还有弹出 Dialog。出于安全原因的考虑,Android 是不允许 Activity 或 Dialog凭空出现的,一个 Activity 的启动必须要建立在另一个 Activity 的基础之上,也就是以此形成的返回栈。而 Dialog 则必须在一个 Activity 上面弹出(除非是 System Alert 类型的 Dialog),因此在这种场景下,我们只能使用 Activity 类型的 Context,否则将会出错。

getApplicationContext()getApplication()方法得到的对象都是同一个 application 对象,只是对象的类型不一样。

Context 数量 = Activity 数量 + Service 数量 + 1 (1 为 Application)

9 、理解 Activity ,View,Window 三者关系

这个问题真的很不好回答。所以这里先来个算是比较恰当的比喻来形容下它们的关系吧。Activity 像一个工匠(控制单元),Window 像窗户(承载模型),View 像窗花(显示视图)LayoutInflater 像剪刀,Xml 配置像窗花图纸。

1:Activity 构造的时候会初始化一个 Window,准确的说是PhoneWindow
2:这个 PhoneWindow 有一个“ViewRoot”,这个“ViewRoot”是一个 View 或者说 ViewGroup,是最初始的根视图。
3:“ViewRoot”通过 addView 方法来一个个的添加 View。比如 TextView,Button 等
4:这些 View 的事件监听,是由 WindowManagerService 来接受消息,并且回调 Activity 函数。比如 onClickListeneronKeyDown 等。

10 、四种 LaunchMode 及其使用场景

此处延伸: 栈(First In Last Out)与队列(First In First Out)的区别

栈与队列的区别:
  1. 队列先进先出,栈先进后出
  2. 对插入和删除操作的"限定"。 栈是限定只能在表的一端进行插入和删除操作的线性表。队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。
  3. 遍历数据速度不同
standard 模式

这是默认模式,每次激活 Activity 时都会创建 Activity 实例,并放入任务栈中。
使用场景: 大多数 Activity。

singleTop 模式

如 果 在 任 务 的 栈 顶 正 好 存 在 该 Activity 的 实 例 , 就 重 用 该 实 例 ( 会 调 用 实 例 的onNewIntent() ),否则就会创建新的实例并放入栈顶,即使栈中已经存在该 Activity 的实例,只要不在栈顶,都会创建新的实例。使用场景如新闻类或者阅读类 App 的内容页面。

singleTask 模式

如果在栈中已经有该 Activity 的实例,就重用该实例(会调用实例的 onNewIntent() )。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移出栈。如果栈中不存在该实例,将会创建新的实例放入栈中。使用场景如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走 onNewIntent,并且会清空主界面上面的其他页面。

singleInstance 模式

在一个新栈中创建该 Activity 的实例,并让多个应用共享该栈中的该 Activity 实例。一旦该模式的 Activity 实例已经存在于某个栈中,任何应用再激活该 Activity 时都会重用该栈中的实例( 会调用实例的 onNewIntent() )。其效果相当于多个应用共享一个应用,不管谁激活该Activity 都会进入同一个应用中。使用场景如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance 不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B(singleInstance) -> C,完全退出后,在此启动,首先打开的是 B

11 、View 的绘制流程
自定义控件:

1、组合控件。这种自定义控件不需要我们自己绘制,而是使用原生控件组合成的新控件。如标题栏。
2、继承原有的控件。这种自定义控件在原生控件提供的方法外,可以自己添加一些方法。如制作圆角,圆形图片。
3、完全自定义控件:这个 View 上所展现的内容全部都是我们自己绘制出来的。比如说制作水波纹进度条。

View 的绘制流程: OnMeasure()——>OnLayout()——>OnDraw()
第一步: OnMeasure():测量视图大小。从顶层父 View 到子 View 递归调用 measure 方法,measure 方法又回调 OnMeasure
第二步: OnLayout():确定 View 位置,进行页面布局。从顶层父 View 向子 View 的递归调用view.layout 方法的过程,即父 View 根据上一步 measure 子 View 所得到的布局大小和布局参数,将子 View 放在合适的位置上。
第三步: OnDraw():绘制视图。ViewRoot 创建一个 Canvas 对象,然后调用 OnDraw()。六个
步骤:

①、绘制视图的背景;
②、保存画布的图层(Layer);
③、绘制 View 的内容;
④、绘制 View 子视图,如果没有就不用;
⑤、还原图层(Layer);
⑥、绘制滚动条。

12 、View ,ViewGroup 事件分发
  1. Touch事件分发中只有两个主角:ViewGroupViewViewGroup包含onInterceptTouchEventdispatchTouchEventonTouchEvent三个相关事件。View包含dispatchTouchEventonTouchEvent两个相关事件。其中 ViewGroup 又继承于 View。

2.ViewGroup 和 View 组成了一个树状结构,根节点为 Activity 内部包含的一个 ViwGroup。

3.触摸事件由 Action_Down、Action_Move、Aciton_UP 组成,其中一次完整的触摸事件中,Down 和 Up 都只有一个,Move 有若干个,可以为 0 个。

4.当 Acitivty 接收到 Touch 事件时,将遍历子 View 进行 Down 事件的分发。ViewGroup 的遍历可以看成是递归的。分发的目的是为了找到真正要处理本次完整触摸事件的 View,这个View 会在 onTouchuEvent 结果返回 true。

5.当某个子View返回true时,会中止Down事件的分发,同时在ViewGroup中记录该子View。接下去的 Move 和 Up 事件将由该子 View 直接进行处理。由于子 View 是保存在 ViewGroup中的,多层 ViewGroup 的节点结构时,上级 ViewGroup 保存的会是真实处理事件的 View 所在的 ViewGroup 对象:如 ViewGroup0-ViewGroup1-TextView 的结构中,TextView 返回了 true,它将被保存在 ViewGroup1 中,而 ViewGroup1 也会返回 true,被保存在 ViewGroup0 中。当Move 和 UP 事件来时,会先从 ViewGroup0 传递至 ViewGroup1,再由 ViewGroup1 传递至
TextView。

6.当 ViewGroup 中所有子 View 都不捕获 Down 事件时,将触发 ViewGroup 自身的 onTouch事件。触发的方式是调用 super.dispatchTouchEvent 函数,即父类 View 的 dispatchTouchEvent
方法。在所有子 View 都不处理的情况下,触发 Acitivity 的 onTouchEvent 方法。

7.onInterceptTouchEvent 有两个作用:

1.拦截 Down 事件的分发。
2.中止 Up 和 Move 事件向目标 View 传递,使得目标 View 所在的 ViewGroup 捕获 Up 和 Move 事件。

13 、保存 Activity 状态

onSaveInstanceState(Bundle)会在 activity 转入后台状态之前被调用,也就是 onStop()方法之前,onPause 方法之后被调用;

14 、Android 中的几种动画

帧动画:指通过指定每一帧的图片和播放时间,有序的进行播放而形成动画效果,比如想听的律动条。

补间动画: 指通过指定 View 的初始状态、变化时间、方式,通过一系列的算法去进行图形变换,从而形成动画效果,主要有 Alpha、Scale、Translate、Rotate 四种效果。
注意: 只是在视图层实现了动画效果,并没有真正改变 View 的属性,比如滑动列表,改变标题栏的透明度。
属性动画: 在 Android3.0 的时候才支持,通过不断的改变 View 的属性,不断的重绘而形成动画效果。相比于视图动画,View 的属性是真正改变了。比如 view 的旋转,放大,缩小。

15 、Android 中跨进程通讯的几种方式

Android 跨进程通信,像 intent,contentProvider,广播,service 都可以跨进程通信。
intent:这种跨进程方式并不是访问内存的形式,它需要传递一个 uri,比如说打电话。
contentProvider:这种形式,是使用数据共享的形式进行数据共享。
service:远程服务,aidl,广播

16 、AIDL 理解

此处延伸: 简述 Binder
AIDL: 每一个进程都有自己的 Dalvik VM 实例,都有自己的一块独立的内存,都在自己的内存上存储自己的数据,执行着自己的操作,都在自己的那片狭小的空间里过完自己的一生。而 aidl 就类似与两个进程之间的桥梁,使得两个进程之间可以进行数据的传输,跨进程通信有多种选择,比如BroadcastReceiver , Messenger 等,但是 BroadcastReceiver 占用的系统资源比较多,如果是频繁的跨进程通信的话显然是不可取的;Messenger 进行跨进程通信时请求队列是同步进行的,无法并发执行。

Binde 机制简单理解:

在 Android 系统的 Binder 机制中,是有Client,Service,ServiceManager,Binder 驱动程序组成的,其中 Client,service,Service Manager 运行在用户空间,Binder 驱动程序是运行在内核空间的。而 Binder 就是把这 4 种组件粘合在一块的粘合剂,其中核心的组件就是 Binder 驱动程序,Service Manager 提供辅助管理的功能,而 Client 和 Service 正是在 Binder 驱动程序和Service Manager 提供的基础设施上实现 C/S 之间的通信。其中 Binder 驱动程序提供设备文件/dev/binder 与用户控件进行交互,Client、Service,Service Manager 通过 open 和 ioctl 文件操作相应的方法与 Binder 驱动程序进行通信。而Client和Service之间的进程间通信是通过Binder驱动程序间接实现的。而BinderManager 是一个守护进程,用来管理 Service,并向 Client 提供查询 Service 接口的能力。

17 、Handler 的原理

Android 中主线程是不能进行耗时操作的,子线程是不能进行更新 UI的。所以就有了 handler,它的作用就是实现线程之间的通信。

handler 整个流程中,主要有四个对象,handlerMessage,MessageQueue,Looper。当应用创建的时候,就会在主线程中创建 handler 对象,

我们通过要传送的消息保存到 Message 中,handler 通过调用 sendMessage 方法将 Message发送到 MessageQueue 中,Looper 对象就会不断的调用 loop()方法

不断的从 MessageQueue 中取出 Message 交给 handler 进行处理。从而实现线程之间的通信。

18 、Binder 机制原理

在 Android 系统的 Binder 机制中,是有Client,Service,ServiceManager,Binder 驱动程序组成的,其中 Client,service,Service Manager 运行在用户空间,Binder 驱动程序是运行在内核空间的。而 Binder 就是把这 4 种组件粘合在一块的粘合剂,其中核心的组件就是 Binder 驱动程序,Service Manager 提供辅助管理的功能,而 Client 和 Service 正是在 Binder 驱动程序和Service Manager 提供的基础设施上实现 C/S 之间的通信。其中 Binder 驱动程序提供设备文件/dev/binder 与用户控件进行交互,Client、Service,Service Manager 通过 open 和 ioctl 文件操作相应的方法与 Binder 驱动程序进行通信。而 Client 和 Service 之间的进程间通信是通过 Binder 驱动程序间接实现的。而 Binder Manager 是一个守护进程,用来管理 Service,并向 Client 提供查询 Service 接口的能力。

19 、热修复的原理

我们知道 Java 虚拟机 —— JVM 是加载类的 class 文件的,而 Android 虚拟机——Dalvik/ARTVM 是加载类的 dex 文件,

而他们加载类的时候都需要ClassLoader,ClassLoader 有一个子类 BaseDexClassLoader,而BaseDexClassLoader 下有一个数组——DexPathList,是用来存放 dex 文件,当 BaseDexClassLoader 通过调用 findClass 方法时,实际上就是遍历数组,找到相应的 dex 文件,找到,则直接将它 return。

而热修复的解决方法就是将新的 dex 添加到该集合中,并且是在旧的 dex 的前面,所以就会优先被取出来并且 return 返回。

20 、Android 内存泄露及管理

(1)内存溢出(OOM)和内存泄露(对象无法被回收)的区别。
(2)引起内存泄露的原因
( 3 ) 内存泄露检测工具 ------>LeakCanary

内存溢出 out of memory: 是指程序在申请内存时,没有足够的内存空间供其使用,出现 out of memory;比如申请了一个 integer,但给它存了 long 才能存下的数,那就是内存溢出。内存溢出通俗的讲就是内存不够用。
内存泄露 memory leak: 是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光

内存泄露原因:

①Handler 引起的内存泄漏。
解决:将 Handler 声明为静态内部类,就不会持有外部类 SecondActivity 的引用,其生命周期就和外部类无关,如果 Handler 里面需要 context 的话,可以通过弱引用方式引用外部类
②单例模式引起的内存泄漏。
解决:Context 是 ApplicationContext,由于 ApplicationContext 的生命周期是和 app 一致的,不会导致内存泄漏
③非静态内部类创建静态实例引起的内存泄漏。
解决: 把内部类修改为静态的就可以避免内存泄漏了
④非静态匿名内部类引起的内存泄漏。
解决:将匿名内部类设置为静态的。
⑤注册/反注册未成对使用引起的内存泄漏。
注册广播接受器、EventBus 等,记得解绑。
⑥资源对象没有关闭引起的内存泄漏。
在这些资源不使用的时候,记得调用相应的类似 close()、destroy()、recycler()、release()等方法释放。
⑦集合对象没有及时清理引起的内存泄漏。
通常会把一些对象装入到集合中,当不使用的时候一定要记得及时清理集合,让相关对象不再被引用。

21 、Fragment 与 与 Fragment 、Activity 通信的方式

1.直接在一个 Fragment 中调用另外一个 Fragment 中的方法
2.使用接口回调
3.使用广播
4.Fragment 直接调用 Activity 中的 public 方法

22 、Android UI 适配

字体使用 sp,使用 dp,多使用 match_parent,wrap_content,weight
图片资源,不同图片的的分辨率,放在相应的文件夹下可使用百分比代替。

23 、app 优化

app 优化: (工具:Hierarchy Viewer 分析布局 工具:TraceView 测试分析耗时的)
App 启动优化.布局优化响应优化.内存优化.电池使用优化.网络优化.App 启动优化(针对冷启动)

App 启动的方式有三种:

冷启动: App 没有启动过或 App 进程被 killed, 系统中不存在该 App 进程, 此时启动 App 即为冷启动。
热启动: 热启动意味着你的 App 进程只是处于后台, 系统只是将其从后台带到前台, 展示给用户。

介于冷启动和热启动之间, 一般来说在以下两种情况下发生:

(1)用户 back 退出了 App, 然后又启动. App 进程可能还在运行, 但是 activity 需要重建。
(2)用户退出 App 后, 系统可能由于内存原因将 App 杀死, 进程和 activity 都需要重启, 但是可以在 onCreate 中将被动杀死锁保存的状态(saved instance state)恢复。

优化:

Application 的 onCreate(特别是第三方 SDK 初始化),首屏 Activity 的渲染都不要进行耗时操作,如果有,就可以放到子线程或者 IntentService 中

布局优化

尽量不要过于复杂的嵌套。可以使用,,

响应优化

Android 系统每隔 16ms 会发出 VSYNC 信号重绘我们的界面(Activity)。

页面卡顿的原因:

①过于复杂的布局.
②UI 线程的复杂运算
③频繁的 GC,导致频繁 GC 有两个原因:

  • 内存抖动, 即大量的对象被创建又在短时间内马上被释放.
  • 瞬间产生大量的对象会严重占用内存区域。

内存优化: 参考内存泄露和内存溢出部分
电池使用优化(使用工具: Batterystats & bugreport)

(1)优化网络请求
(2)定位中使用 GPS, 请记得及时关闭

网络优化(网络连接对用户的影响:流量,电量,用户等待)可在Android studio下方logcat旁边那个工具 Network Monitor 检测
API 设计: App 与 Server 之间的 API 设计要考虑网络请求的频次, 资源的状态等. 以便 App可以以较少的请求来完成业务需求和界面的展示.
Gzip 压缩: 使用 Gzip 来压缩 request 和 response, 减少传输数据量, 从而减少流量消耗.
**图片的 Size:**可以在获取图片时告知服务器需要的图片的宽高, 以便服务器给出合适的图片,避免浪费.
网络缓存: 适当的缓存, 既可以让我们的应用看起来更快, 也能避免一些不必要的流量消耗.

24 、图片优化

(1) 对 图 片 本 身 进 行 操 作 。 尽 量 不 要 使 用 setImageBitmap 、 setImageResource 、BitmapFactory.decodeResource 来设置一张大图,因为这些方法在完成 decode 后,最终都是通过 java 层的 createBitmap 来完成的,需要消耗更多内存.
(2)图片进行缩放的比例,SDK 中建议其值是 2 的指数值,值越大会导致图片不清晰。
(3)不用的图片记得调用图片的 recycle()方法

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

最后

其实要轻松掌握很简单,要点就两个:

  1. 找到一套好的视频资料,紧跟大牛梳理好的知识框架进行学习。
  2. 多练。 (视频优势是互动感强,容易集中注意力)

你不需要是天才,也不需要具备强悍的天赋,只要做到这两点,短期内成功的概率是非常高的。

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。

阿里P7Android高级教程

下面资料部分截图,诚意满满:特别适合有3-5年开发经验的Android程序员们学习。

附送高清脑图,高清知识点讲解教程,以及一些面试真题及答案解析。送给需要的提升技术、近期面试跳槽、自身职业规划迷茫的朋友们。

Android核心高级技术PDF资料,BAT大厂面试真题解析;

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img
423969)]

附送高清脑图,高清知识点讲解教程,以及一些面试真题及答案解析。送给需要的提升技术、近期面试跳槽、自身职业规划迷茫的朋友们。

Android核心高级技术PDF资料,BAT大厂面试真题解析;
[外链图片转存中…(img-9BwPbGpI-1712970423969)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-lvFnGpQE-1712970423969)]

  • 24
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值