记录
| 日期 | 说明 |
|---|---|
| 2023/2/26 | 首次创建 |
| 2023/3/5 | 增加通信,启动,事件体系的内容 |
总纲
关于android机制的相关概念
事件体系
滑动效果
- 直接滑动
- 使用scrollTo/scrollBy
- 缺点:只能滑动内容,不能滑动View本身
- 优点:容易实现而且不影响内部元素的点击事件
- 使用动画
- view动画/属性动画
- 优点:复杂效果必须通过动画实现
- 缺点:3.0以下或者View动画均不能改变view本身的属性,滑动后影响交互
- 使用scrollTo/scrollBy
- 弹性滑动
- Scroller
- Handler#postDelay
- Thread#Sleep
- 滑动冲突
- 内外滑动方向不同
- 外部拦截法
- 重写onInterceptionTouchEvent方法,在ACTION_MOVE事件中根据情况决定是自己拦截并处理就返回true,分发给子元素处理就返回false
- 内部拦截法
- 内外滑动方向相同
- 场景1,2嵌套
事件分发
- 分发过程
- dispatchTouchEvent:事件分发
- onInterceptionEvent:事件是否拦截
- onTouchEvent:处理事件
- 三者的伪代码
public void dispatchTouchEvent(MotionEvent event) {
boolean consume = true;
if (onInterceptionTouchEvent(event)) {
consume = onTouchEvent(event);
} else {
consume = child.dispatchTouchEvent(event);
}
return consume;
}
- 处理事件的优先级: onTouchListener > onTouchEvent > onClickListener
- 点击事件的传递过程: activity > Window > View
- 同一个事件序列是指从手指接待处屏幕的那一刻起,到手指离开屏幕的那一刻,这个事件以down事件开始,中间经过若干个move事件,最终以up事件结束。(cancel?double?)
- 子view通过requestDisallowInterceptionTouchEvent设置FLAG_DISALLOW_INTERCEPT后,ViewGroup将无法拦截除了ACTION_DOWN以外的其他点击事件
- 因为ViewGroup在事件分发时,如果时ACTION_DOWN就会重置FLAG_DISALLOW_INTERCEPT,将导致子view中设置的这个标记位无效,因此当面对ACTION_DOWN事件时,ViewGroup回调用自己的onInterceptionTouchEvent方法来询问自己是否要拦截事件
scroller
- 滑动器。实现具有过渡效果的滑动,需要和view的computeScroll配合
gestureDetector
- 手势检测,辅助检测用户的点击、滑动、长按、双击等行为
- 创建一个GestureDetector对象并实现监听接口
mGrstureDetector = new GestureDetector(mGestureListener); - 在目标View的onTouchEvent方法中添加如下实现
return mGestureDetector.onTouchEvent(event); - 常用的方法有onSingleTapUp,onFLing,onScroll,onLongPress,onDoubleTap
- 在实际的开发中,如果只是监听滑动相关,建议自己在onTouchEvent中实现,如果要监听双击事件,建议使用gestureDetector
- 创建一个GestureDetector对象并实现监听接口
MotionEvent
- 手机接触屏幕后的事件类型
- action_down
- action_move
- action_up
- 获取坐标
- getX和getY返回的是相对于当前View左上角的x和y坐标
- getRawX和getRawY返回的是相对于手机屏幕左上角的x和y坐标
通信方式
线程间通信
- handler
- 线程形态
- Thread
- AsyncTask
- 轻量级异步任务类,可以把执行的进度和结果传递回主线程并更新UI,不适合特别耗时的任务
- 本质是对Thread类和Hanlder的封装
- 他是一个抽象泛型类,提供了params(参数类型),progress(进度),result(返回结果)三个泛型参数
- 5个核心方法:onPreExecute, doInBackground(Params), onProgressUpdate(Progress), onPostExecute(Result), onCancelled()
- 条件限制
- AsyncTask的类必须在主线程中加载
- AsyncTask对象必须在主线程中创建
- execute方法必须在UI线程调用
- 不能够在程序中直接调用5个核心方法
- 一个AsyncTask对象只能执行一次
- HandlerThread
- IntentService
- 线程池
进程间通信
- 文件
- Binder
- AIDL
- 创建AIDL
- 实体类序列化
- 创建AIDL接口文件。注意实体类的目录要和AIDL接口的目录相同
- 生成Binder的java文件。 3.1. stub。构造函数,asInterface,onTreansact 3.2. proxy。接口定义方法的伪实现,实际调用的是真的Binder的方法
- 服务器:Binder中实际执行的方法
- 客户端
- 创建AIDL
- Message
- 基于消息的跨进程通信
- ContentProvider
- AIDL
- Socket
- Bundle
启动
应用启动
- 进程创建
graph TD
Zygote通过fork创建进程 --> 进程中创建binder线程池 --> 反射获取ActivityThread并执行main方法#会创建消息队列等
- application创建
graph TD
调用applicationThread的bindApoplication方法##ipc操作##创建application --> 通过makeActive方法赋值applicationThread --> 通过ATMS启动根activity
activity启动
- 过程
graph TD
activity --> IPC --> System_server#AMS --> IPC2 --> ApplicationThread --> ActivityThread --> Handler切换到主线程 --> activity.attach --> 调度执行onCreate-onStart-onResume等
attach就是获取一个实例的PhoneWIndow
2. onCreate
graph TD
创建activity实例 --> activity.attach方法 --> activity.onCreate方法
- 可见
graph TD
调用onStart-onResume --> 设置视图可见
Service启动
引用
消息机制
原理
- Android应用程序是通过消息来驱动的,系统为每一个应用程序维护一个消息队列,应用程序的主线程不断地从这个消息队例中获取消息(Looper),然后对这些消息进行处理(Handler),这样就实现了通过消息来驱动应用程序的执行。
过程
- 发送:通过handler向相关的messageQueue发送消息
- 存储:把发送的消息以message的形式存储在messageQueue中
- 循环:通过Looper不停的从MessageQueue中获取消息,队列中没有消息时候就阻塞等待新信息
细节
- 创建消息时obtain方式会重复利用缓存池中的对象
- 调用prepare接口会创建消息队列
- 调用loop接口开启消息循环,监听消息队列
- 通过handler的send和post系列方法来发送消息
- 通过handler.dispatchMessage分发消息,先考虑callback,没有就分发拦截,再没有就handlerMessage处理
引用
Context
实现
- ContextImpl: 实现了context函数的类
- ContextWrapper: 包装了context的类
- ContextThemeWrapper: 包装了与主题相关的context类
- activity
- application
- Service
- ContextThemeWrapper: 包装了与主题相关的context类
获取
- view.getContext(): 返回当前view对象的Context对象的,通常是当前正在展示的Activity对象
- Activity.getApplicationContext(): 获取当前activity所在的应用进程的Context对象
- ContextWrapper.getBaseContext(): 获取ContextWrapper进行装饰之前的Context
- Activity.this: 返回当前的activity的实例
- 区别:getApplication, getApplicaitonContext, application本身一个context,所以这两个返回的是相同的内容,都是applicaiton本身的实例,不过getApplication只能用在activity和service,在其他场景用零一个方法
正确使用
- 内存泄漏
- 单例模式的静态对象保存了activity的context,当activity被销毁时并不能gc
- 正确姿势
- 在application的context能搞定的情况下,并且生命周期长的对象,有效使用applicaition的context
- 不让生命周期长于activity的对象持有activity的引用
- 尽量不要在activity中使用非静态内部类,因为非静态内部类会隐式的持有外部类实例的引用,如果使用静态内部类,将外部实例引用作为弱引用持有
- 不推荐使用baseContext
- 对于service和application而言,不推荐使用时因为担心用户修改了basecontext而导致错误发生
- 对于activity而言,除了担心用户的修改之外,basecontext和activity本身对于resource以及theme的相关行为时不同的(如果引用了configuration),使用basecontext可能会出现无法预测的现象