8/30-9/3

一周总结报告

8/30-9/3这一周主要是学习了事件的分发机制、Activity启动模式、编译系统和Android.mk、Android.bp文件。

一、         事件分发机制

  1. 分发对象

被分发的对象是用户触摸屏幕而产生的点击事件,事件主要包括:按下、滑动、抬起与取消。这些事件被封装成MotionEvent对象。该对象中的主要事件如下表所示:

事件

触发场景

单次事件流中触发的次数

MotionEvent.ACTION_DOWN

在屏幕按下时

1次

MotionEvent.ACTION_MOVE

在屏幕上滑动时

0次或多次

MotionEvent.ACTION_UP

在屏幕抬起时

0次或1次

MotionEvent.ACTION_CANCLE

滑动超出控件边界时

0次或1次

按下、滑动、抬起、取消这几种事件组成了一个事件流。事件流以按下为开始,中间可能有若干次滑动,以抬起或取消作为结束。(在安卓对事件分发的处理过程中,主要是对按下事件作分发,进而找到能够处理按下事件的组件。对于事件流中后续的事件(如滑动、抬起等),则直接分发给能够处理按下事件的组件。)

  1. 分发事件的组件

分发事件者:Activity、ViewGroup、View;

关系:Activity包括了ViewGroup,ViewGroup又可以包含多个View。

  1. 分发的核心方法

dispatchTouchEvent()分发:处理触摸事件分发,事件(多数情况)从Activity的dispatchTouchEvent开始的,执行super.dispatchTouchEvent(ev),事件向下分发。

onInterceptTouchEvent()拦截:由于viewGroup下还包含子View,所以默认返回值为false,即不拦截此ACTION_DOWN事件。如果返回false,则ACTION_DOWN事件继续传递给其子view。如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move, up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。

onTouchEvent()处理:ViewGroup提供的方法,默认返回false,返回true表示拦截。返回true表示该View能处理该事件,事件将终止向上传递(传递给其父View);返回false表示不能处理,则把事件传递给其父View的onTouchEvent()方法来处理

  1. 事件传递

Android中默认情况下事件传递是由最终的view的接收到,传递过程是从父布局到子布局。dispatchTouchEvent()返回true,后续事件(ACTION_MOVE、ACTION_UP)会再传递,如果返回false,dispatchTouchEvent()就接收不到ACTION_UP、ACTION_MOVE。

当触摸事件ACTION_DOWN发生之后,先调用Activity中的dispatchTouchEvent函数进行处理,紧接着ACTION_DOWN事件传递给ViewGroup中的dispatchTouchEvent函数,接着ACTION_DOWN事件传递到调用ViewGroup中的onInterceptTouchEvent函数,此函数负责拦截ACTION_DOWN事件。由于viewGroup下还包含子View,所以默认返回值为false,即不拦截此ACTION_DOWN事件。如果返回false,则ACTION_DOWN事件继续传递给其子view。由于子view不是viewGroup的控件,所以ACTION_DOWN事件接着传递到onTouchEvent进行处理事件。此时消息的传递基本上结束。从上可以分析,motionEvent事件的传递是采用隧道方式传递。隧道方式,即从根元素依次往下传递直到最内层子元素或在中间某一元素中由于某一条件停止传递。

二、         Activity启动模式

standard(标准模式)

    每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在

singleTop(栈顶复用模式)

如果新的Activity的实例已经存在于栈顶,那么新的Activity不会被创建,系统通过调用其onNewIntent()方法将Intent传递到该实例。只要不在栈顶,都会创建实例。

 

 

 

singleTask(栈内复用模式)

只要Activity在一个栈中存在,那么多次启动该Activity都不会重新创建实例。如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移除栈。

 

 

 

 

singleInstance(单实例模式) 只会返回一次

无论从哪个Task中启动目标Activity,只会创建一个目标Activity实例,并会使用一个全新的Task栈来加载该Activity实例,并且这个实例独立运行在一个activity任务栈中,这个task只有这个实例,不允许有别的Activity存在

 

 

 

创建4个activity,分别采用四中启动模式,4个activity可以相互跳转:在每个activity中定义三个按钮,为这三个按钮添加点击事件,点击按钮时通过intent隐式启动activity分别跳转其它三个activity;在AndroidManifest.xml文件中将四个activity分别设置为采用四种启动模式启动。通过back返回时观察activity页面,结合上述知识理解,更加深刻。

三、         Android编译系统

  1. Android.mk和Android.bp

1)         简介

Android.mk本质是一个makefile文件,可以将源文件分组为模块。Android.bp的出现就是为了替换掉Android.mk。Android.bp只是一个纯粹的配置文件,不包括分支、循环语句等控制流程,本质上就是一个json配置文件。Android.bp  通过Blueprint+soong转换成ninja的构建规则文件build.ninja,再使用ninja来进行构建工作。

2)         mk与bp文件的相互转换(课后作业)

命令行输入lunch报错,则首先需要安装python-lunch,然后重新运行lunch,在m10/out/soong/host/linux-x86/bin目录下新建一个Android.mk文件,写入Android.mk内容,输入命令“./androidmk Android.mk > Android.bp”实现转换。

3)         Android.mk的编写

a)          Android.mk文件首先需要指定LOCAL_PATH变量,用于查找源文件。由于一般情况下Android.mk和需要编译的源文件在同一目录下,所以定义成如下形式:LOCAL_PATH:=$(call my-dir)
上面的语句的意思是将LOCAL_PATH变量定义成本文件所在目录路径。

b)          LOCAL_MODULE_TAGS :=user eng tests optional
user: 指该模组只在 user 版本下才编译
eng: 指该模组只在 eng 版本下才编译
tests: 指该模组只在 tests 版本下才编译
optional:指该模组在所有版本下都编译

c)         在 Android.mk 文件中, 还可以用LOCAL_MODULE_PATH和LOCAL_UNSTRIPPED_PATH指定最后的目标安装路径.

d)         不同的文件系统路径用以下的宏进行选择:
    TARGET_ROOT_OUT:表示根文件系统。
    TARGET_OUT:表示 system文件系统。
  TARGET_OUT_DATA:表示 data文件系统。
一些模块详解:https://www.jianshu.com/p/b23905bdcb3a

  1. 将Jgrep、cgrep、mangrep的function内容抽出来,做成 shell脚本将脚本文件所在的路径增加到环境变量 :

步骤:Jgrep:

1.(新建文件命名为jgrep)

gedit jgrep;

2.(将jgrep脚本内容粘贴)

#!/bin/bash

 

find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.java" -print0 | xargs -0 grep --color -n "$@";

3.(添加环境变量:修改 /home/.bashrc,在文件的最后添加)

export PATH=/home/liu/test:$PATH;

4.(使环境变量生效)

source ~/.bashrc;

  1. 使用自定义脚本

jgrep "public",即完成。

 

cgrep的脚本内容:#!/bin/bash

 

find . -name .repo -prune -o -name .git -prune -o -type f \( -name '*.c' -o -name '*.cc' -o -name '*.cpp' -o -name '*.h' -o -name '*.hpp' \) -print0 | xargs -0 grep --color -n "$@"

mangrep的脚本内容:#!/bin/bash

 

find . -name .repo -prune -o -name .git -prune -o -path ./out -prune -o -type f -name 'AndroidManifest.xml' -exec grep --color -n "$@" {} +

其他步骤与Jgrep相同。

  1. 项目整编的方式

谷歌原生的编译方式:1.编译环境初始化:source build/envsetup.sh ;2.选择编译目标:lunch aosp_arm-eng ;3.执行编译:make -j8 。还可单编某个模块:前两步相同,第三步改为“mm/mma/mmm    需要编译的模块 ”。

SCM封装的编译方式:1.在project根目录打开终端输入./mk,终端会显示scm封装好的整编和单编的方式;2.根据需要选择整编和单编:(1)整编:./mk -p HS60 -s -v userdebug -f -m n -o all   (2)单编:./mk -p HS50 -s -f -v userdebug --platform-bit 32 -m mma -o packages/apps/SamSungCamera3/ -j8 

  1. 模块单编指令

m:编译整个安卓系统,构建模块,在只修改了部分源代码的情况下使用,构建速度比mm/mma快。

mm:构建模块,但对于任何依赖项,它将构建错误。编译当前目录下的模块,当前目录下需要有Android.mk这个makefile文件,否则就往上找最近的Android.mk文件。

mma:构建模块,它可以先构建依赖项,然后再构建模块。当前目录新增或删除文件后,可以用mma重新编译。

posted @ 2021-10-14 17:41  星橙月  阅读(91)  评论(0编辑  收藏  举报