Android-机制

109 阅读6分钟

记录

日期说明
2023/2/26首次创建
2023/3/5增加通信,启动,事件体系的内容

总纲

关于android机制的相关概念

事件体系

滑动效果

  • 直接滑动
    • 使用scrollTo/scrollBy
      • 缺点:只能滑动内容,不能滑动View本身
      • 优点:容易实现而且不影响内部元素的点击事件
    • 使用动画
      • view动画/属性动画
      • 优点:复杂效果必须通过动画实现
      • 缺点:3.0以下或者View动画均不能改变view本身的属性,滑动后影响交互
  • 弹性滑动
    • Scroller
    • Handler#postDelay
    • Thread#Sleep
  • 滑动冲突
    1. 内外滑动方向不同
    • 外部拦截法
      • 重写onInterceptionTouchEvent方法,在ACTION_MOVE事件中根据情况决定是自己拦截并处理就返回true,分发给子元素处理就返回false
    • 内部拦截法
    1. 内外滑动方向相同
    2. 场景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

  • 手势检测,辅助检测用户的点击、滑动、长按、双击等行为
    1. 创建一个GestureDetector对象并实现监听接口 mGrstureDetector = new GestureDetector(mGestureListener);
    2. 在目标View的onTouchEvent方法中添加如下实现 return mGestureDetector.onTouchEvent(event);
    3. 常用的方法有onSingleTapUp,onFLing,onScroll,onLongPress,onDoubleTap
    4. 在实际的开发中,如果只是监听滑动相关,建议自己在onTouchEvent中实现,如果要监听双击事件,建议使用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
        1. 实体类序列化
        2. 创建AIDL接口文件。注意实体类的目录要和AIDL接口的目录相同
        3. 生成Binder的java文件。 3.1. stub。构造函数,asInterface,onTreansact 3.2. proxy。接口定义方法的伪实现,实际调用的是真的Binder的方法
      • 服务器:Binder中实际执行的方法
      • 客户端
    • Message
      • 基于消息的跨进程通信
    • ContentProvider
  • Socket
  • Bundle

启动

应用启动

  1. 进程创建
graph TD
Zygote通过fork创建进程 --> 进程中创建binder线程池 --> 反射获取ActivityThread并执行main方法#会创建消息队列等
  1. application创建
graph TD
调用applicationThread的bindApoplication方法##ipc操作##创建application --> 通过makeActive方法赋值applicationThread --> 通过ATMS启动根activity

activity启动

  1. 过程
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方法
  1. 可见
graph TD
调用onStart-onResume --> 设置视图可见

Service启动

引用

  1. activity过程详解
  2. Android 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

获取

  • 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可能会出现无法预测的现象