Activity相关
Android进程优先级
- 前台:处于前台和用户交互的activity或者和前台activity绑定的service
- 可见:处于可见但并不是处于前台,用户不能点击的activity
- 服务:在后台开启service服务
- 后台:按home键
- 空:不属于前面4中的任何一种,随时杀掉
Android任务栈
- standard:每次都会重新创建Activity实例,加到任务栈,不考虑复用
- singletop(栈顶复用):在栈顶不会重新创建而是进行复用,不处于栈顶重新创建
- singletast:整个任务栈中是否存在,如果存在将其置于栈顶(调用onNewIntent方法),其上面的activity都移除销毁,如果不存在则重新创建
- singleinstance:在整个系统中,有且只有一个实例并且独享与一个任务栈
scheme跳转协议
Android中的scheme是一种页面内的跳转协议,是一种非常好的实现机制,通过定义自己的scheme协议,可以非常方便的跳转app中的各个页面;通过scheme协议,服务器可以定制化的告诉app跳转哪个页面,可以通过通知栏消息定制化跳转页面,可以通过H5页面跳转页面等。
Fragmen相关
Fragment为什么会被称为第五大组件
为大屏幕更灵活的展现UI,fragment相比activity更节省内存,能动态灵活的加载到Activity中去,UI切换方便,
fragment的2种加载方式
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
DemoFragment fragment = new DemoFragment();
fragmentTransaction.add(R.id.content, fragment);
fragmentTransaction.addToBackStack("DemoFragment");
fragmentTransaction.commit();
FragmentPagerAdapter适用于页面较少的情况
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object
+ " v=" + ((Fragment)object).getView());
mCurTransaction.detach((Fragment)object);
}
FragmentStatePagerAdapter适用于页面较多的情况,每次切换回收内存
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment) object;
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object
+ " v=" + ((Fragment)object).getView());
while (mSavedState.size() <= position) {
mSavedState.add(null);
}
mSavedState.set(position, fragment.isAdded()
? mFragmentManager.saveFragmentInstanceState(fragment) : null);
mFragments.set(position, null);
mCurTransaction.remove(fragment);
}
Fragment生命周期
Fragment通信
- 在Fragment中调用Activity中的方法
- 在Fragment中调用Fragment中的方法 接口回调
- 在Fragment中调用Fragment的方法 findFragmentById
replace、add、remove
Service相关
Service是什么
Service是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件,可由其他组件启动,一旦启动可在后台长时间运行,即使启动它的组件已经被销毁,也不会受影响。另外也可以把Service绑定到activity,从而进行数据交互。
运行在主线程,不能做耗时操作。
Service和Thread区别
- 定义:Thread程序执行的最小单元,运行相对独立;Service是Android中的机制,如果是本地的Service,则运行在主线程
- 实际开发:
- 应用场景:
Service启动
- startService:onCreate首次创建服务时调用,如果服务已经存在,则不会再调用(在调用onStartCommand()和onBind()之前);onStartCommand()方法每次通过startService启动是都会被调用;onDestro服务销毁时回调;
- bindService:1、创建BindService服务端,继承自Service并且在常见一个实现IBinder接口的实例对象并提供公共方法给客户端调用;2、从onBind()回调方法返回此Binder实例;3、在客户端中,从onServiceConnected()回调方法中接收Binder,并使用提供的方法调用绑定服务
BroadcastReceiver相关
广播定义
在Android中,Broadcast是一种广泛运用在应用程序之间传输信息的机制,Android中我们要发送的广播是一个Intent,这个Intent中可以携带我们要传输的数据。
使用场景
- 同一个app具有多个进程的不同组件之间的消息通信
- 不同app之间的组件之间消息通信
种类
- Normal Broadcast: Context.sendBroadcast
- System Broadcast: Context.sendOrderedBroadcast
- Local Broadcast: 只在自身app内传播
实现
- 静态注册:注册完成就一直运行(activity销毁或者app进程被杀掉仍然能收到广播)
- 动态注册:跟随activity的生命周期
内部实现机制
- 自定义广播接收者BroadcastReceiver,并复写onReceive()方法
- 通过Binder机制想AMS(Activity Manager Service)进行注册
- 广播发送者通过Binder机制想AMS发送广播
- AMS查找符合相应条件(IntentFilter/Permission等)的BroadcastReceiver,将广播发送到BroadcastReceiver(一般情况下是Activity)相应的消息循环队列中
- 消息循环队列执行拿到的广播,回调onReceive()方法
LocalBroadcastManager
- 使用它发送的广播只在自身app内传播,因此不必担心泄露隐私数据
- 其它app无法对你的app发送广播,因为你的app根本无法接受到非自身应用发送是广播,因此不必担心有安全漏洞可以利用
- 比系统全局广播更加高效
LocalBroadcastManager实现机制
- LocalBroadcastManager高效的原因主要是它内部是通过handler实现的,它的sendBroadcast()方法含义并非和我们平时所用的一样,它的sendBroadcast()方法其实是通过hander发送一个message实现的
- 既然是它内部通过handler来实现广播的发送的,那么相对于系统广播通过Binder实现那肯定是更高效的了,同时使用Handler来实现,别的应用无法向我们的应用发送改广播,而我们应用发送的广播也不会离开我们的应用
- LocalBroadcastManager内部协作主要是靠2个集合:mReceivers和mActions,当然还有一个List集合mPendingBroadcasts,这个主要就是存储待接收的广播对象
Webview相关
Binder相关
Linux内核的基础知识
- 进程隔离/虚拟地址空间
- 系统调用
- Binder驱动
Binder通信机制介绍
为什么使用Binder
- Android使用的Linux内核拥有非常多的跨进程通信机制
- 性能:更叫高效
- 安全:支持身份校验(权限模型的基础)
Binder通信模型
到底什么是Binder
- 通常意义下,Binder指的是一种通信机制
- 对于Server进程来说,Binder知道是Binder本地对象/对于Client来说,Binder指的是Binder代理对象
- 对于传输过程而言,Binder是可以进行跨进程传递的对象
AIDL
AsyncTask相关
什么是AsyncTask
它本质上就是一个封装了线程池和Handler的异步框架
AsyncTask使用方法
AsyncTask的机制原理
- AsyncTask的本质是一个静态的线程池,AsyncTask派生出的子类可以实现不同的异步任务,这些任务都是提交到静态的线程池中执行。
- 线程池中的工作线程执行doInbackgroud(mParams)方法执行异步任务
- 当任务状态改变后,工作线程回想UI线程发送消息,AsyncTask内部的internalHandler响应这些消息,并调用相关的回调函数
AsyncTask的注意事项
- 内存泄露
- 生命周期
- 结果丢失
- 并行or串行
HandlerThread相关
- HandlerThread本质上是一个线程类
- HandlerThread有自己内部的Looper对象,可以进行Looper循环
- 通过获取HandlerThread的Looper对象传递给Handler对象,可以在HandleMessage方法中执行异步任务
- 有点事不会有阻塞,减少了对性能的消耗,缺点是不能同时进行多任务处理,需要等待进行处理,处理效率底
- 与线程池重并发不同,HandlerThread是一个串行队列,HandlerThread背后只有一个线程
IntentService相关
IntentService是什么
IntentService是继承并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方法和启动传统Service方法一样,同时,当任务执行完成后,IntentService会自动停止,而不需要手动去控制或者stopSelf(),另外,可以多次启动IntentService,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调中执行,并且,每次只执行一个任务,执行完成一个再执行第二个
View绘制相关
View绘制流程
measure->layout->draw
invalidate():控件会重新执行 onMesure() onLayout()
requestLayout():重新执行onDraw()方法
ANR
UI卡顿
什么是ANR
Application Not Responding
Activity中 5秒,广播中 10秒
ANR产生的原因
- 主线程被IO操作(从4.0之后网络IO不允许在主线程中)阻塞
- 主线程中存在耗时的计算
Android中哪些操作在主线程
- Activity的所有生命周期方法
- Service执行
- 广播的onReceive
- 没有使用子线程的Looper的Handler的HandleMessage,post是执行在主线程的
- AsyncTast的回调中除了doInbackgound,其他都是在主线程的
如何解决ANR
- 使用AsyncTast处理IO操作
- 使用Thread或者HandlerThread提高优先级
- 是哦用Handler来处理工作线程的耗时任务
- Activity的onCreate和onResume回调中尽量避免耗时的代码
OOM
什么是OOM
当前占用的内存加上我们申请的内存资源超过了Dalvik虚拟机的最大内存限制就会抛出Out Of Memory异常
一些容易混淆的概念
内存溢出/内存抖动/内存泄露
如何解决OOM
有关bitmap
- 图片显示
- 及时释放内存
- 图片压缩
- inBitmap属性
- 捕获异常
其它方法
- listview:convertview/Lru
- 避免在onDraw方法中执行对象的创建
- 谨慎使用多进程
UI卡顿原理
60fps->16ms(1000/60=16)
overdraw
UI卡顿原因分析
- 人为在UI线程中做了轻微耗时操作,导致UI线程卡顿
- 布局Layout过于复杂,无法再16ms内完成渲染
- 同一时间动画执行的次数过多,导致CPU或者GPU负载过重
- View过度绘制导致某些像素在同一帧时间内被绘制多次,从而是CPU或者GPU负载过重
- View频繁的触发measure、layout,导致measure、layout
- 内存频繁触发GC过多,导致暂时阻塞渲染操作
- 冗余资源以及逻辑等导致加载和执行缓慢
- ANR
UI卡顿总结
- 布局优化 (使用include,merge,viewstub;使用gone代替invisible;避免冗余嵌套和过于复杂的布局)
- 列表以及Adapter优化
- 背景和图片等内存分配优化
- 避免ANR
内存泄露
java内存泄露基础知识
java内存分配策略
- 静态存储区(方法区)
- 栈区
- 堆区
java是如何管理内存的
java中的内存泄露
内存泄露是指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成内存空间的浪费称为内存泄露
Android内存泄露
单例
匿名内部类
非静态内部类会持有外部类的引用
Handler
避免是使用static变量
资源未关闭造成的内存泄露
AsyncTast造成的内存泄露
activity销毁时调用asyncTask.cancel(true)
内存管理
内存管理机制概述
Android中的内存管理机制
内存管理机制的特点
- 更少的占用内存
- 在合适的时候,合理的释放系统资源
- 在系统内存紧张的情况下,能释放大部分不重要的资源,来为Android系统提供可用的内存
- 能够很合理的在特殊生命周期中,保存或者还原重要数据,以至于系统能够正确的重新恢复该应用
内存优化方法
- 当Service完成任务后,尽量停止它
- UI不可见的时候释放一些只有UI使用的资源
- 在系统内存紧张的时候,尽可能多的释放掉一些重要资源
- 避免滥用bitmap导致的内存浪费
- 使用针对内存优化过的数据容器
- 避免使用依赖注入框架
- 使用ZIP对齐APK
- 使用多进程
内存溢出vs内存泄露
冷启动优化
什么是冷启动
- 冷启动:冷启动就是在启动应用前,系统中没有该应用的任何进程信息
- 热启动:用户使用返回键退出应用,然后马上重新启动应用
- 冷启动时间:这个是时间值从应用启动(创建进程)开始计算,到完成试图的第一次绘制(即Activity内容对用户可见)为止
冷启动流程
Zygote进程中fork创建出一个新进程
创建和初始化Application类、创建MainActivity类
inflate布局、当onCreate/onStart/onResume方法都走完
contentView的measure/layout/draw显示在界面上
冷启动优化
- 减少MainActivity中onCreate()方法的工作量
- 不要让Application参与业务操作,不要做耗时操作
- 不要以静态变量的方式在Application中保存数据
- 布局/mainThread
其他优化
Android不用静态变量存储数据
- 静态变量等数据由于进程已经被杀死而被初始化
- 使用其他数据传输方式:文件/sp/contentProvider
有关sp问题
内存对象的序列化
序列化:将对象的状态信息转换为可以存储或者传输的形式的过程
- Serializeble
- Parcelable
- Serializeble是java序列化方式,Parcelable是Android特有的序列化方式
- 在使用内存的时候,Parcelable比Serializeble性能高
- Serializeble在序列化的时候会产生大量的临时变量,从而引起频繁的GC
- Parcelable不能是哦用在将要数据存储在磁盘上的情况
避免在UI线程中做繁重的操作
单例模式
- 单例是一种对象的创建模式,它用于产生一个对象的具体实例,它可以确保系统中一个类只产生一个实例
- 对于频繁是使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言 ,是非常可观的一笔系统开销
- 由于new操作的次数减少,因而对系统内存的使用率也会降低,这将减轻GC压力,缩短GC停顿时间
饿汉模式
懒汉模式
多线程并发下这样的实现是无法保证实例唯一
懒汉线程安全模式
双重检查锁模式
静态内部类
观察者模式
观察者模式详解
概念
定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象都得到通知并被自动更新
使用场景
- 一个对象模型有2个方面,其中一个方面依赖于另一个方面
- 一个对象的改变将导致一个或者多个其他对象也发生改变
- 需要在系统中创建一个触发链
UML类图
实现
观察者模式在Android中的实际运用
- 回调模式
- listview中notifyDataSetChanged
- Rxjava中观察者模式的运用