- Android的构成基石----四大组件
- Activity
- 在Activity和开发人员设置的视图之间还隔着两层:
- 实际上视图会被设置给一个Window类,Window中有一个DecorView,他才是整个窗口的顶级视图
- 我们设置的视图会被设置到DecorView的mContentParent布局中
- 启动模式中关于singleInstance的理解
- 设置了singleInstance的Activity会在一个独立的任务中开启,且此任务只有这么一个Activity实例
- 当再次启动此Activity事,会重用已经存在的任务和实例
- singleInstance保证的是这个系统中只有此Activity这么一个实例
- 在Activity和开发人员设置的视图之间还隔着两层:
- Service
- 理解:无界面的Activity
- IntentService:
- 会运行在子线程
- 任务结束后自我停止
- 用户只需要复写onHandlerIntent函数并在这个函数中完成自己的耗时操作就好了
- 运行在前台的Service(练一练) 通知
- 优先级更高,怎么开启?
- AIDL(练一练)
- 是什么?
- AIDL就是定义一个接口,客户端(调用端)通过bindService来与远程服务端建立一个链接,在该连接建立时会返回一个IBinder对象,该对象是服务端Binder的BinderProxy,在建立连接时,客户端通过asInterface函数将该BinderProxy对象包装成本地的Proxy,并将远程服务端的BinderProxy对象赋值给Proxy类的mRemote字段,就是通过mRemote执行远程函数调用。
- 是什么?
- Broadcast(广播)
- 广播三要素:Broadcast(发送广播)、BroadcastReceiver(接收器)、传递信息的Intent
- 普通广播:
- 完全异步
- 无法终止,知道没有与之匹配的广播接收器为止
- 有序广播:
- 按照优先级接受
- 本地广播:
- 只有同一个同一个应用内才能收到
- ContentProvider(外共享数据)
- 本质是对SQLiteOpenHelper的进一步封装
- 通过Uri映射来判断选择需要操作数据库中哪个表,进行什么操作
- Activity
- 创建出丰富多彩的UI View与动画
- 重要的View控件
- 用户界面组成:
- 必须掌握的最重要的技能---自定义控件
- Scroller的使用
- 动画
- 帧动画
- 补间动画
- 属性动画:
- 核心类:ValueAnimator:
- 给出属性的取值范围、运行时长自动计算属性值在各个动画运行时段的取值
- 动画的播放次数、播放模式、以及动画的监听
- 简单,他只是负责生成不懂动画时刻的属性值,单一职责
- ObjectAnimator
- 继承自ValueAnimator,但是比ValueAnimator更高级,可以操具体控件的属性的值
- 极为强大,他能操纵任意对象中的任意属性
- AnimatorSet
- 同时执行多个动画
- 动画执行时间与速度:
- TypeEvaluator:
- 他的作用是根据当前动画已经执行时间占总时间的百分比来计算新的属性值
- TimeInterpolator:
- 作用是修改动画已执行时间与总时间的百分百,从而可以实现非匀速的一些效果
- TypeEvaluator:
- 核心类:ValueAnimator:
- 重要的View控件
- 保证App流畅的关键因素----多线程
- Android中的消息机制:
- 每个Handler都会关联一个消息队列,消息队列被封装在Looper中,而每个Looper又会关联一个线程(存放在ThreadLocal中),最终就等于每个消息队列关联一个线程。Handler相当于处理这个消息队列的消息处理器,即使你创建再多的handler,他发消息都会发到同一个消息队列中去,只不过是哪个Handler发的,消息队列会让哪个Handler来处理
- Handler创建的时候是如何关联Looper的?
- 当在主线程中创建Handler的时候,因为主线程(UI线程)启动的时候已经初始化好了一个Looper(消息队列),所以可以直接创建,并自动将创建好的线程唯一的消息队列关联给Handler
- 如果在一个子线程中直接创建Handler的话,因为没有创建属于该线程的消息队列,因此Handler会创建失败,解决的方法是在子线程中创建一个消息队列,并让消息队列循环起来以后在进行创建Handler
- Looper对象存放在哪里?
- Looper对象是每个线程所持有的唯一的一个消息队列,存在在该线程的一个静态的ThreadLocal变量中,关于ThreadLocal的理解可以看ThreadLocal的理解
- 在主线程中在app一启动的时候系统就已经为UI线程创建好了一个Looper并存在了ThreadLocal中,并让这个Looper开始循环起来
- Handler为何能处理消息
- Looper建立以后就会立即执行loop方法,他是一个死循环,不断的取消息Message中有一个Handler的变量名为target,如果target不是空,那么就会调用Message中target的dispatchMessage分发到Handler,由Handler来处理这个消息,这也解释了为什么是同一个消息队列不同的Handler post的消息只能自己执行,就是因为每个消息都有一个target来指明了谁发送的自己就会由谁来处理自己
- Android中的多线程
- Runnable才是代表一个任务,Thread相当于Runnable的一个封装,他实现了Runnable
- 线程的wait、sleep、join、yield的区别:
- wait()调用后进入等待池,失去对象锁,其他线程可以访问
- sleep()线程休眠,但不释放对象锁,其他线程无法访问
- join() 等待目标线程执行完之后再执行
- yield()线程礼让,目标线程切换为就绪状态,让出执行权限,使得其他线程可以优先执行,但其他线程能否执行时未知的。
- 与多线程相关的方法
- Callable与Runnable大致相同,不同的是Callable能够有一个返回值,也就是任务执行完以后返回一个值。
- Future相当于任务的一个管理者,提供了对Runnable或者Callable的取消、查询完成结果等FutureTask是他的实现类。经由FutureTask包装后的Runnable或者Callable再扔到线程池中去执行,可以暂停、查询状态,如果Callable还可以查询执行完成后的结果,Runnable则不行。
- 线程池
- 定时执行一些任务———ScheduledThreadPoolExecutor
- 同步集合
- 多线程中的程序优化策略:
- CopyOnWriteArrayList:在进行写之前先复制,写完以后再复制回去
- 提高并发效率——ConcurrentHashMap:原理是将数据分段加锁,这样多个线程访问的效率就会提高
- 有效的方法——BlockingQueue 队列满了以后就会阻塞,直至不满,生产者消费者模式有用
- 多线程中的程序优化策略:
- 同步锁:
- synchronized:
- 作用于函数的时候实际上锁的是对象,就是该函数所在类的对象
- 作用于class的时候则锁的是整个Class类
- 显示锁——ReentrantLock与Condition
- 获取和释放更加灵活
- 轮询锁和定时锁
- 公平性
- 信号量:一般适用于允许多个同事访问但不允许超过一个限制的情况
- 循环栅栏:一个同步辅助类,适用于当线程达到一定数量才开始执行的情况
- 闭锁CountDownLatch:让一个线程等待,知道条件被满足才继续执行
- synchronized:
- AsyncTask的工作原理
- 一个简单的AsyncTask:SimpleAsyncTask.java
- Android中的消息机制:
- 性能优化
- 布局优化
- 使用include标签
- 使用merge标签
- ViewStub视图
- 布局尽量简单,不要太多的层级,尽量使用RelativeLayout 不要使用AbsoluteLayout
- 避免使用LInearLayout的layout_weight属性
- 内存优化
- 如何管理内存:
- 珍惜Service资源
- 原则就是执行完了就关闭,所以最好的办法就是使用IntentService,他会在处理完他的intent任务之后尽快结束自己
- 当UI隐藏的时候释放内存
- 当用户离开你的UI的时候会回调onTrimMemory 并返回参数TRIM_MEMORY_UI_HIDDEN,可以在此处释放那些仅仅被你的UI使用的资源
- 这与onStop不同
- 当内存紧张时释放部分内存
- onTrimMemory同样可以告诉我们整个设备的内存资源已经开始紧张,下边是他的返回参数的不同级别:
- TRIM_MEMORY_RUNNING_MODERATE:设备处于低内存状态
- TRIM_MEMORYRUNNING_LOW:设备还没被杀死,但是处于更低内存状态
- ….
- onTrimMemory同样可以告诉我们整个设备的内存资源已经开始紧张,下边是他的返回参数的不同级别:
- 检查应该使用多少内存:
- getMemoryClass()获取app可用heap大小 超过这个会oom
- 避免Bitmaps的浪费:尽量使用图片框架、预加载策略
- 使用优化的数据容器:SparseArray...等等
- 请注意内存开销
- Enums的内存消耗通常是static constants的2倍
- 一个类会使用大概500bytes
- 每一个类的实例产生的花销是12-16bytes
- HashMap添加一个entry会占用额外的32bytes
- 注意代码抽象
- 不要过度抽象,过多的抽象也会加重系统负担
- 避免使用依赖框架
- 优化整体性能
- 使用ProGuard来剔除不需要的代码
- 对最终的apk进行zipalign
- 使用多进程
- 珍惜Service资源
- 内存泄漏:
- 使用Memory Monitor如果内存居高不小或者是GC太频繁,那么就说明出现了内存泄漏
- LeakCanary的使用
- 如何管理内存:
- 性能优化
- 过度绘制:
- 概念
- 检测:开发者选项中的过度绘制功能
- 最小化过度绘制:
- 使用clipRect为视图定义可绘制区域
- Hierarchy Viewer可以将层级可视化
- TraceView 数据采集和分析工具
- 每个函数执行时间
- 过度绘制:
- ThreadLocal的理解:
- 通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。而使用ThreadLocal创建的变量只能被当前线程访问,其他线程则无法访问和修改。 而ThreadLocal就是一个关于创建线程局部变量的类。
- 布局优化
[读书笔记] Android 从小工到专家
2019-08-16