面经:安卓学习笔记

Android驱动框架整理之KERNEL框架 这些带有build的相关目录我没有过研究,有兴趣的可以自己去看看。我们比较关注的是arch/目录下的arm64的源码: 相关的dts目录: 可以在对应的目录进行dts的添加编译或者删除编译 一般android指定对应的dts文件在device目录下进行指定: 如何查看在自己编译的dts内容,每个dts编译完成后都会生成对应的dtb文件,同时还会生成对应的tmp的一个隐藏文件,在对应的out目录下(nxp的目录如下): 可以看到我们指定的dts会有这个隐藏文件产生,然后我们可以进去查看,这个tmp文件会把所有 阅读详情

1. Android系统架构

在这里插入图片描述

  1. Linux内核层
    Android系统是基于Linux内核的,这一层为Android设备的各种硬件提供了底层的驱动,如显示驱动、音频驱动、照相机驱动、蓝牙驱动、Wi-Fi驱动、电源管理等。
  2. 系统运行库层
    这一层通过一些C/C++库为Android系统提供了主要的特性支持。如SQLite库提供了数据库的支持,OpenGL|ES库提供了3D绘图的支持,Webkit库提供了浏览器内核的支持等。在这一层还有Android运行时库,它主要提供了一些核心库,允许开发者使用Java语言来编写Android应用。另外,Android运行时库中还包含了Dalvik虚拟机(5.0系统之后改为ART运行环境),它使得每一个Android应用都能运行在独立的进程中,并且拥有一个自己的虚拟机实例。相较于Java虚拟机,Dalvik和ART都是专门为移动设备定制的,它针对手机内存、CPU性能有限等情况做了优化处理。
  3. 应用框架层
    这一层主要提供了构建应用程序时可能用到的各种API,Android自带的一些核心应用就是使用这些API完成的,开发者可以使用这些API来构建自己的应用程序。
  4. 应用层
    所有安装在手机上的应用程序都是属于这一层的,比如系统自带的联系人、短信等程序,或者是你从Google Play上下载的小游戏,当然还包括你自己开发的程序。
    核心总结
    框架中各层作用
    1、内核层:包含大量驱动;同时可让Android利用主要安全功能(系统和内核安全)。
    2、HAL:提供标准接口,屏蔽硬件差异。
    3、C/C++系统库:Android基础功能库。主要包括init孵化来的用户空间的守护进程
    Android Runtime:安卓应用的基础环境。
    4、系统系统框架层:连接应用层,为上层提供基础功能接口。
    5、系统应用层:包含各类应用,负责与用户进行交互。
    通过进程分析各层之间的联系
    1、 Loader层上电,加载预设参数,准备启动内核层的swapper进程。
    2、 内核层中swapper进程启动,加载驱动、启动Kthreadd线程、准备启动Init进程。
    3、 C++框架层启动Init进程,Init加载各类服务,同时开启最重要的Zygote进程。
    4、 Java 框架根据启动的Zygote进程,fork出system server进程。
    5、 应用层根据启动的system server进程开启应用。

2. Activity

2.0 定义

Activity 是与用户交互的入口点。它表示拥有界面的单个屏幕

2.1 生命周期

在这里插入图片描述

onCreate():会在系统首次创建Activity时触发
onStart():当 Activity 进入“已开始”状态时,系统会调用此回调。onStart() 调用使 Activity 对用户可见,因为应用会为 Activity 进入前台并支持互动做准备
onResume():
Activity 会在进入“已恢复”状态时来到前台,然后系统调用 onResume() 回调。这是应用与用户互动的状态。应用会一直保持这种状态,直到某些事件发生,让焦点远离应用。此类事件包括接到来电、用户导航到另一Activity,或设备屏幕关闭。当发生中断事件时,Activity 进入“已暂停”状态,系统调用 onPause() 回调。如果 Activity 从“已暂停”状态返回“已恢复”状态,系统将再次调用 onResume() 方法。因此应实现 onResume(),以初始化在 onPause() 期间释放的组件,并执行每次 Activity进入“已恢复”状态时必须完成的任何其他初始化操作。
onPause()
系统将此方法视为用户将要离开您的 Activity 的第一个标志(尽管这并不总是意味着 Activity 会被销毁);此方法表示 Activity 不再位于前台。
onStop()
如果您的 Activity 不再对用户可见,说明其已进入“已停止”状态,因此系统将调用 onStop() 回调。
在 onStop() 方法中,应用应释放或调整在应用对用户不可见时的无用资源。例如,应用可以暂停动画效果,或从精确位置更新切换到粗略位置更新。
进入“已停止”状态后,Activity 要么返回与用户互动,要么结束运行并消失。如果 Activity 返回,系统将调用 onRestart()。如果 Activity 结束运行,系统将调用 onDestroy()。
onDestroy()
销毁 Activity 之前,系统会先调用 onDestroy()。

2.2 生命状态

运行状态:位于返回栈栈顶
暂停状态:不再位于栈顶,但是仍然可见
停止状态:不再位于栈顶,并且完全不可见
销毁状态:从返回栈中移除

2.3 启动模式

  • standard模式(默认)
    每当启动一个新的Activity,它就会在返回栈中入栈,并处于栈顶的位置。对于使用standard 模式的Activity,系统不会在乎这个Activity 是否已经在返回栈中存在,每次启动都会创建一个该Activity 的新实例。
    在这里插入图片描述
  • singleTop 模式
    当Activity 的启动模式指定为singleTop ,在启动Activity 时如果发现返回栈的栈顶已经是该Activity ,则认为可以直接使用它,不会再创建新的Activity 实例。
    在这里插入图片描述
  • singleTask
    当Activity 的启动模式指定为singleTask ,每次启动该Activity 时,系统首先会在返回栈中检查是否存在该Activity 的实例,如果发现已经存在则直接使用该实例,并把在这个Activity 之上的所有其他Activity 统统出栈,如果没有发现就会创建一个新的Activity 实例。
    在这里插入图片描述
  • singleInstance
    指定为singleInstance 模式的Activity 会启用一个新的返回栈来管理这个Activity (其实如果singleTask 模式指定了不同的taskAffinity ,也会启动一个新的返回栈)
    在这里插入图片描述

3. Service

3.1 定义

服务是一个通用入口点,用于因各种原因使应用在后台保持运行状态。它是一种在后台运行的组件,用于执行长时间运行的操作或为远程进程执行作业。服务不提供界面。

3.2 两种启动方式

(1)通过startService和stopService方式启动和停止服务
(2)通过bindService和unbindService的方式启动和停止服务

3.3 生命周期

在这里插入图片描述

  • startService()生命周期
    onCreate():当Service第一次被创建时,由系统调用
    onStartCommand(): 当调用startService方法启动Service时被调用
    onDestroy():当service不再使用时,由系统调用
  • bindService()生命周期
    onBind():当bindService方法启动Service时被调用
    onUnbind(): 当unbindService方法解除绑定时被调用

3.4 跨进程service

通过aidl实现c/s提供服务接口流程
(1)服务端Service
Service端提供暴露服务端接口的aidl文件
创建aidl文件,在接口包内添加服务端的接口
创建完毕后立刻编译
service代码文件:MyService.java
继承aidl的接口代替非跨进程调用中service使用bind接口,在onBind中返回该接口实例
AndroidManifest.xml
注册服务并设置Inten过滤器
(2)客户端Client
添加aidl文件
文件的路径、包名、接口名都需要一致
MainActivity.java
剩余部分和正常的bindService中MainActvity的流程基本一致:创建对应的binder(跨进程调用就是对应的aidl接口),创建ServiceConnected实例并重写onServiceConnected和onServiceDisconnected方法,以及MainActivity中的剩余的应有逻辑。

3.5 IntentService

IntentService是 Scrvice 的子类,增加了额外的功能。
Service存在的问题
Service不会专门启动一个单独的进程,Service和它所在的应用在同一个进程中。Service不是一条新的线程,因此不应该在Service中直接处理耗时的任务,会阻塞主线程,造成ANR(程序无响应)异常。
IntentService的优点
IntentService会创建单独的worker线程来处理所有的Intent请求。 在执行耗时操作时,不会阻塞主线程,更不会产生ANR。 IntentService会创建单独的worker线程来处理onHandleIntent()方法实现的代码,所以不用处理多线程问题,执行完毕后会自行调用onDestroy()方法进行关闭。

4. BroadCastReceiver

4.1 概念

BroadCast Receiver(广播接收者)使用了设计模式中的观察者模式(基于消息的发布/订阅事件模型),用于响应来自其他应用程序或者系统的广播消息,是一个全局监听器。

4.2 组成

1)消息订阅者(广播接收者): 广播接收者通过 Binder机制在AMS注册
2)消息发布者(广播发布者): 广播发送者通过 Binder 机制向AMS发送广播
3)消息中心(AMS,即Activity Manager Service): AMS根据广播发送者要求,在已注册列表中,寻找合适的广播接收者,AMS将广播发送到合适的广播接收者相应的消息循环队列中。 广播接收者通过消息循环拿到此广播,并回调 onReceive()

4.3 广播接收器的分类

  1. 标准广播

    是一种完全异步执行的广播,通过context. senddBroadcast(intent)方法发送。在广播发出后,所有的BroadcastReceiver几乎在同一时刻收到这个广播消息,它们之间没有先后顺序,这种广播的效率较高,并且不能被拦截。

  2. 有序广播

    是一种同步执行的广播,通过context. sendOrderedBroadcast(intent)方法发送。在广播发出之后,同一时刻只有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递(通过setResult()方法传递,通过getResult()方法接收)。即广播接收器有先后顺序,优先级高(在receiver的intent-filter中的android:priority属性设置)的广播接收器可以先收到广播消息,且前面的广播接收器还可以截断正在传递的广播(通过abortBroadcast()方法丢弃),这样后面的广播接收器就无法收到广播消息。

  3. 本地广播
    上述俩种广播是全局广播,所有应用均可收到,而本地广播仅在进程内传播,有保护数据安全的作用。调用者不同,本地广播调用的是LocalBroadcastManager相关方法,全局广播调用的是Context的相关方法。且本地广播没有静态注册的方法。

  4. 系统广播
    Andrroid内置了多个系统广播。使用系统广播时,只需在注册广播接收者时定义相关的action即可。

4.4 生命周期

BroadcastReceiver的生命周期从对象调用它开始,到onReceiver方法执行完成之后结束。
每次广播被接收后会重新创建BroadcastReceiver对象,并在onReceiver方法中执行完就销毁,如果BroadcastReceiver的onReceiver方法中不能在10秒内执行完成,Android会出现ANR异常。所以不要在BroadcastReceiver的onReceiver方法中执行耗时的操作。如果需要在BroadcastReceiver中执行耗时的操作,可以通过Intent启动Service来完成。但不能绑定Service。如果我们在Activity中注册了BroadcastReceiver,当Activity销毁时要主动撤销注册(即添加onDestroy方法),否则会出现异常。

4.5 静态注册和动态注册

案例学习:监听电池电量变化,Android四大组件——BroadcastReceiver——动态注册和静态注册 - 虞美人体重90 - 博客园 (cnblogs.com)
https://www.cnblogs.com/Xiang-MY/p/16191383.html
动态注册:广播接收器可以自由的控制注册与取消,具有灵活性。因为其生命周期与对应的Acitivity的生命周期是一致的,所以只有在应用程序启动后才能收到广播。
静态注册:在AndroidManifest.xml中进行注册。静态注册的广播不受程序生命周期的影响,当应用程序关闭后,仍可以接收到广播

动态注册的BroadcastReceiver可以自由控制注册和注销,但必须在程序启动之后才能接收广播,因为注册的逻辑是写在onCreate()中的。
静态注册的BroadcastReceiver可以在程序未启动的情况下也能接收广播。

5. ContentProvider

ContentProvider主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性。目前,使用ContentProvider是Android实现跨程序共享数据的标准方式。

6. Intent

在这里插入图片描述

Android开发 - Intent和Broadcast Receiver - guqiangjs - 博客园 (cnblogs.com)
https://www.cnblogs.com/guqiangjs/p/5932612.html

6.1 作用

Intent是一种在不同组件之间传递的请求消息,是应用程序发出的请求和意图。作为一个完整的消息传递机制,Intent不仅需要发送端,还需要接收端

6.2 显示Intent和隐式Intent

 显式Intent
对于明确指出了目标组件名称的Intent,我们称之为显式Intent。
 隐式Intent
隐式的Intent提供了一种机制,可以让匿名的应用程序组件响应动作请求。这意味着可以要求系统启动一个可执行给定动作的Activity,而不必知道需要启动哪个应用程序或者Activity。
例如希望让用户从应用程序中拨打电话,那么可以实现一个新的拨号程序,也可以使用一个隐式的Intent来请求一个在电话号码(表示为一个URI)上执行动作。

7. Fragment

Fragment详解之一——概述_fragment启舰_启舰的博客-优快云博客

https://blog.youkuaiyun.com/harvic880925/article/details/44917955

7.1 定义作用

Fragment是一种可以嵌入在Activity当中的UI片段,它能让程序更加合理和充分地利用大屏幕的空间,因而在平板上应用得非常广泛

8. Handler机制

添加链接描述

8.1 整体介绍

Handler是一套 Android 消息传递机制,主要用于线程间通信。
用最简单的话描述: handler其实就是主线程在起了一个子线程,子线程运行并生成Message,Looper获取message并传递给Handler,Handler逐个获取子线程中的Message.
Binder/Socket用于进程间通信,而Handler消息机制用于同进程的线程间通信
可以说只要有异步线程与主线程通信的地方就一定会有 Handler。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8.2 名词介绍

  • Message
    Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。使用Message的arg1和arg2便可携带int数据,使用obj便可携带Object类型数据。

  • Handler
    Handler顾名思义就是处理者的意思,它主要用于在子线程发送消息对象Message,在UI线程处理消息对象Message,在子线程调用sendMessage方法发送消息对象Message,而发送的消息经过一系列地辗转之后最终会被传递到Handler的handleMessage方法中,最终在handleMessage方法中消息对象Message被处理。
    (如何创建能够有效避免内存泄漏:将 Handler 定义成静态的内部类,在内部持有 Activity 的弱引用,并及时移除所有消息)

  • MessageQueue
    MessageQueue就是消息队列的意思,它只要用于存放所有通过Handler发送过来的消息。这部分消息会一直存放于消息队列当中,等待被处理。每个线程中只会有一个MessageQueue对象,请牢记这句话。其实从字面上就可以看出,MessageQueue底层数据结构是队列,而且这个队列只存放Message对象。

  • Looper
    Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无限循环当中,然后每当MesssageQueue中存在一条消息,Looper就会将这条消息取出,并将它传递到Handler的handleMessage()方法中。
    (如何保证每个线程只有一个Looper对象)
    Looper的构造是私有的,只有通过其prepare()方法构建出来,当调用了Looper的prepare()方法后,会调用ThreadLocal中的get()方法检查ThreadLocalMap中是否已经set过Looper

  • Looper死循环为什么不会导致应用卡死?
    卡死就是ANR,产生的原因有2个:
    1、在5s内没有响应输入的事件(例如按键,触摸等),
    2、BroadcastReceiver在10s内没有执行完毕。
    事实上我们所有的Activity和Service都是运行在loop()函数中,以消息的方式存在,所以在没有消息产生的时候,looper会被block(阻塞),主线程会进入休眠,一旦有输入事件或者Looper添加消息的操作后主线程就会被唤醒,从而对事件进行响应,所以不会导致ANR。简单来说looper的阻塞表明没有事件输入,而ANR是由于有事件没响应导致,所以looper的死循环并不会导致应用卡死。

9. 死锁

9.1 银行家算法

每一个新进程进入系统时,必须声明需要每种资源的最大数目,其数目不能超过系统所拥有的的资源总量。当进程请求一组资源时,系统必须首先确定是否有足够的资源分配给该进程,若有,再进一步计算在将这些资源分配给进程后,是否会使系统处于不安全状态如果不会才将资源分配给它,否则让进程等待

10. 内存泄漏

10.1 定义

从有一组定义为gc root的根节点到目标对象的路径,称为可达性,此类对象也就是存活对象,不可达的对象就是应该被Gc垃圾回收机制进行回收的对象.在当前应用的生命周期内不再使用的对象,依然被gc root引用,导致无法回收,既造成了内存泄漏。

10.2 原因

  • 注册对象未注销各种Listener
    例如BraodcastReceiver、EventBus未注销造成的内存泄漏,我们应该在Activity销毁时及时注销。
  • 单例造成的内存泄漏
    因为单例的静态特性使得它的生命周期同应用的生命周期一样长,如果一个对象已经没有用处了,但是单例还持有它的引用,那么在整个应用程序的生命周期它都不能正常被回收,从而导致内存泄露。
  • 静态变量导致内存泄漏
    静态变量存储在方法区,它的生命周期从类加载开始,到整个进程结束。一旦静态变量初始化后,它所持有的引用只有等到进程结束才会释放。
  • Handler 内存泄漏
    (1)非静态内部类的Handler:如果在Activity或Fragment中创建非静态内部类的Handler,并且Handler持有对Activity或Fragment的引用,当Handler持有的消息队列中的消息未被处理时,Activity或Fragment无法被释放,从而引发内存泄漏。
    (2)匿名内部类的Handler: 使用匿名内部类创建Handler时,同样可能会持有外部类的引用,导致外部类无法被释放
    (3)在子线程中创建Handler: 如果在子线程中创建Handler,并且Handler持有了主线程的Looper,那么Handler可能会持有主线程的引用,从而导致主线程无法被释放。

10.3 解决办法

  • 检测内存泄漏的工具:LeakCanary
  • 避免静态引用
    避免在静态字段中持有Activity或Context的引用,因为静态字段的生命周期很长,容易导致内存泄漏
  • 尽量使用静态内部类
    每个非静态内部类将持有一个外部类的隐式引用,这可能会导致不必要的问题。使用静态内部类代替非静态内部类,并通过弱引用存储一些必要的生命周期引用。
  • 使用弱引用
    对于一些可能会导致内存泄漏的场景,可以考虑使用弱引用来避免循环引用导致的内存泄漏
  • 及时释放资源
    确保在不再需要的时候及时释放资源,比如在Activity的onDestroy()方法中释放资源。

11. 架构

添加链接描述

11.1 MVC架构

在这里插入图片描述

  • 各个模块的作用
    视图(View)
    接收用户的交互请求并根據需求展示数据给用户
    响應的數据可以是一個Model或者多個Model的混合
    控制器(Controller)
    View 和 Mode的連接器
    接收 View 的要求 并給对应的Model去處理
    模型(Model)
    負責數据 (增加,删除,更改,查詢)
    相關的业务逻辑,而不是在Controller(因為會使Controller變得臃腫)
  • 存在的问题
    大部分的核心业务逻辑放在Controller中,在应用程序的整个生命周期内,这个文件会变得越来越大,越来越难维护。
    由于UI和业务逻辑的紧密耦合,Controller层和View层都将属于同一个activity或fragment。这将导致在更改应用程序功能时出现问题。
    由于大多数测试的部分依赖Android SDK组件,因此针对不同层执行单元测试时变得困难了
    Android 的 Activity 也是一样的,同时担任 Controller 和部分 View 的角色。

11.2 MVP架构 (android采用这个)

在这里插入图片描述

1.分离了视图逻辑和业务逻辑,降低了耦合
2.Activity只处理生命周期的任务,代码变得更加简洁
3.视图逻辑和业务逻辑分别抽象到了View和Presenter的接口中去,提高代码的可阅读性
4.Presenter被抽象成接口,可以有多种具体的实现,所以方便进行单元测试
5.把业务逻辑抽到Presenter中去,避免后台线程引用着Activity导致Activity的资源无法被系统回收从而引起内存泄露和OOM
添加链接描述

12. UI基本布局

在这里插入图片描述
添加链接描述

  • LinearLayout
    按照垂直或者水平的顺序依次排列子元素,每一个子元素都位于前一个元素之后。适用于简单的界面布局,如登录界面、设置界面等。
  • FrameLayout
    子视图会按照它们添加的顺序堆叠在屏幕上。常用于单个子视图的显示,如加载动画或遮罩层。如广告弹窗、提示框等。
  • TableLayout
    表格布局以表格的形式排列子视图,可以实现类似网格的布局。适用于需要展示多个子视图,并希望它们按照行列进行排列的情况。
  • RelativeLayout
    相对布局允许子视图相对于父视图或其他子视图进行定位,灵活性较高。适用于相对复杂的界面布局结构。
  • 约束布局ConstraintLayout
    当需要在组件之间建立复杂的约束关系时,可以选择ConstraintLayout。
    适用于相对复杂的布局结构,如动态调整布局、适配不同屏幕尺寸等。

13. binder机制

添加链接描述
Binder 是 Android 系统中的一种跨进程通信机制,用于实现不同进程之间的通信和数据传输。它的原理是基于 Linux 内核提供的 Binder 驱动,通过 Binder 类实现进程间通信。Binder 通过 client-server 模式工作,客户端通过代理对象与服务端通信,实现进程间通信。

Binder 的工作原理是通过将对象的引用转换成能够跨进程传递的代理对象,从而实现跨进程通信。Binder 使用驱动程序在进程之间传递消息,并提供了 IPC 机制来实现进程间通信。

在 Android 应用中使用 Binder 实现进程间通信,需要定义 AIDL 接口文件来描述客户端和服务端之间的通信接口,然后通过 Binder 类实现该接口,建立客户端和服务端之间的连接。

Binder 和 AIDL 是密切相关的,AIDL 是用来定义客户端和服务端之间通信接口的工具,而 Binder 是用来实现这些接口的底层机制。

14. 进程层次

  • 前端进程
    顾名思义,前端进程就是目前显示在屏幕上和用户交互的进程,在系统中前端进程数量很少,而这种进程是对用户体验的影响最大,只有系统的内存稀少到不足以维持和用户的基本交互时才会销毁前端进程。因此这种进程重要性是最高的。
  • 可见进程
    可见进程也拥有一个可视化的界面,只是目前不是最上层界面(最上层界面在前端进程里面),可见进程一般调用了OnPause(),可见进程比前端进程重要性低,但是在交互方面影响还是很大,因为用户可能随时切换过去,所以系统不会轻易销毁它。
  • 服务进程
    一个服务进程就是一个Service,它调用了startService(),就是UNIX中说的守护进程,对用户不可见,但是保证了一些重要的事件被监听或者维持着某些状态,比如网络数据传输、后台音乐播放,这类进程在内存不足且为了保证前端交互的顺利进行的时候被销毁。
  • 后台进程
    这里叫后台进程可能会和一般意义上的后台进程混淆,要说明的是,android里的后台进程是调用了OnStop()的,可以理解成用户暂时没有和这个进程交互的愿望,所以这里后台进程有点“待销毁”的意思。
  • 空进程
    这是一种系统缓存机制,其实就是个进程的外壳,当有新进程创建的时候,这个空进程可以加快进程创建速度,当系统内存不足的时候,首先销毁空进程。

15. 事件分发机制

15.1 核心内容

Android事件分发机制的本质是要解决:点击事件由哪个对象发出,经过哪些对象,最终达到哪个对象并最终得到处理。这里的对象是指Activity、ViewGroup、View.
Android中事件分发顺序:Activity(Window) -> ViewGroup -> View.
事件分发过程由dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()三个方法协助完成

15.2 触摸事件的类型

ACTION_DOWN : 手指的按下操作
ACTION_MOVE:手指按下后,松开手之前,轻微移动所触发的事件
ACTION_UP:手指离开屏幕的操作

15.3 三个方法的应用

dispatchTouchEvent:该方法用于分发触摸事件,它会在View树中逐级向下传递触摸事件,最终由最终接收触摸事件的View的onTouchEvent方法来处理。

onTouchEvent:该方法用于处理触摸事件,当View接收到触摸事件时,会调用该方法来处理具体的事件,比如点击、滑动等。如果onTouchEvent方法返回true,则表示事件已经被消费,不再传递给其他View;如果返回false,则会继续向上传递。

onInterceptTouchEvent:该方法用于拦截触摸事件,它通常在ViewGroup中使用。当ViewGroup的onInterceptTouchEvent方法返回true时,表示ViewGroup拦截了触摸事件,不再向子View传递;返回false时,触摸事件会继续向子View传递。这个方法通常用来实现事件的拦截和分发控制。

15.4 分发流程图

在这里插入图片描述

15.5 实际应用

触摸事件处理:在安卓开发中,触摸事件是最常见的用户输入事件之一。通过事件分发机制,开发者可以在View层次结构中正确地传递触摸事件,确保事件被正确捕获并处理。例如,可以通过重写View的onTouchEvent方法来处理触摸事件,并在必要时调用super.onTouchEvent方法来传递事件。

自定义手势识别:通过事件分发机制,开发者可以实现自定义的手势识别功能。通过重写View的onTouchEvent方法和onInterceptTouchEvent方法,可以捕获多个连续的触摸事件,并根据一定的规则来判断用户的手势操作。这样可以实现一些特殊的手势操作,如双击、长按等。

事件拦截:有时候,在View层次结构中的父容器需要拦截某些事件,而子View需要继续处理其他事件。通过事件分发机制中的onInterceptTouchEvent方法,可以实现事件的拦截和传递。这样可以确保父容器和子View之间能够正确地协同工作,避免事件冲突和重复处理。

多点触控:在一些应用中,可能需要支持多点触控操作,如缩放、旋转等。通过事件分发机制,可以捕获多个触摸点的事件,并进行合适的处理。在处理多点触控事件时,需要注意每个触摸点的状态和位置,以确保用户操作的准确性和流畅性。

Demo分析

1. 监听电量变化

新建一个类,让它继承BroadcastReceiver,并重写父类的onReceive()方法就行了。这样当有广播到来时,onReceive()方法就会得到执行,具体的逻辑可在该方法中处理。(广播的动态注册)
监听电量变化的广播还需要打开权限:

package com.java.androidstudy;

import androidx.appcompat.app.AppCompatActivity;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity {
   private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //我们要收听的频道是:电量变化
        IntentFilter  intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);//电量变化,想监听什么广播,就添加相应的action
        //创建接收者
        BatteryLeveReceiver batteryLeveReceiver = new BatteryLeveReceiver();

        //动态注册广播
        this.registerReceiver(batteryLeveReceiver,intentFilter);
    }

//第一步,创建一个广播接收者,继承自BroadcastReceiver
    private class BatteryLeveReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            //在这里写接收到广播后的逻辑处理
            String action = intent.getAction();
            Log.d(TAG,"收到了电量变化的广播,action is ==>"+action);
            Log.d(TAG,"当前电量:"+intent.getIntExtra(BatteryManager.EXTRA_LEVEL,0));//获取电量,可戳进BatteryManager的源代码看看
        }
    }
    //取消广播注册,否则会造成内存卡顿
	@Override
	protected void onDestroy() {
	    super.onDestroy();
	    unregisterReceiver(batteryLeveReceiver);
	}

效果展示:
运行后,在模拟器上拖动电量:
在这里插入图片描述

2. 监听开机启动

静态注册

//第一步:新建BootCompleteReceiver类   
public class BootCompleteReceiver extends BroadcastReceiver {
    private static final String TAG="BootCompleteReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        //第三步,收到开机广播后做的事情
        String action = intent.getAction();
        Log.d(TAG,"action is =="+action);
        Log.d(TAG,"开机完成");
        Toast.makeText(context,"收到开机完成的广播",Toast.LENGTH_SHORT).show();
        //静态注册,不需要启动程序也可以接收到广播,不需要取消注册。
    }
}

然后,我们需要在AndroidManifest.xml文件中标签内进行开机广播的静态注册。

<receiver android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <!-- 第二步,静态注册action -->
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />  
            </intent-filter>
        </receiver>

此外,我们还需要打开开机广播的权限

现在运行程序后重启模拟器,日志截图如下:
在这里插入图片描述

总结:组件知识

界面

Activity —— Android最基本的界面容器,用于显示所有APP的内容
Fragment—— Android碎片化界面容器,用于嵌入显示APP指定内容
Layout文件 —— 布局文件,与Activity,Fragment,Adapter,自定义View一起使用,用于绘制界面布局和内容
Adapter —— 界面适配器。用于为重复显示组件如ListView GridView等组件编写列表项显示内容和显示逻辑
控件类 —— 主要是设置各种控件的事件监听器,如OnClickListener等
容器类 —— LinearLayOut,RelativeLayout,FrameLayout,ScrollView等
组件类 —— Button,TextView,EditText,ImageView等
列表类 —— ListView,GridView,RecycleView等

通信

Intent —— 传递数据的容器,主要用于Activity,Fragment界面跳转以及广播发送和接收等数据传递行为中。
ContentProvider —— 内容共享者,主要用于跨应用来获取其他应用的数据或者数据库。

存储

SharedPreference —— 通过key-value键值对的形式来保存数据,适合小量数据
SQLite —— 数据库,用于本地存储大量数据

资源

String —— 存储全局字符串, 通常将所有字符串资源都存放在string中
Dimen —— 主要用于保存控件的各类尺寸。一般将全局尺寸写在dimen中
Mipmap —— 主要用于存储各种应用的各种图标资源文件
Drawable —— 要勇于存储图片,shape和selector等图像资源。图像可以通过各种dpi来区分分辨率以达到不同分辨率视频的效果。
Color —— 存储全局颜色值,便于进行统一更改。
Assest —— 存放静态资源,如html页面等。

其他

Service —— 后台服务
Application —— 全局应用对象
Mainfest —— android项目配置菜单文件,用于注册和配置activity,service等,用于配置权限和应用设置选项。

ADB工具使用

添加链接描述
启用ADB服务: adb start-server
关闭ADB服务: adb kill-server
使用指定ADB设备:adb -s , 为adb devices获得的序列号,如上图:lcc77709
设置端口转发为5555: adb tcpip 5555
开启网络调试:adb connect xxx.xxx.xxx.xxx:5555。xxx.xxx.xxx.xxx为手机局域网IP
断开网络调试:adb disconnect xxx.xxx.xxx.xxx:1234
使用usb连接: adb usb
使用root模式: adb root
重启设备: adb reboot
关机: adb shell reboot -p。
重启到rec模式(fb模式): adb reboot recovery(fastboot)
查看已连接的设备信息:adb devices
查看adb 版本信息:adb version
查看日志:adb logcat
列出手机装的所有app 的包名:adb shell pm list packages
列出系统应用的所有包名:adb shell pm list packages -s

2024 Android开发工程师面经 乐观锁:假设每次去拿数据都认为别人不会修改,所以不会上锁.但是在更新的时候会判断一下此期间别人有没有去更新这个数据. 一般用在读比较多,写比较少的情况.悲观锁:假设每次都是最坏情况,每次去拿数据时别人都会修改,所以每次拿数据的时候都会上锁,这样别人想拿这个数据就会被阻塞直到它拿到锁. 多写少读时使用.扩展资料: https://www.cnblogs.com/renhui/p/9755789.html这个大家可以跟着hencoder老师的文章系统学习一下. 阅读详情

相关推荐

Android OpenGL ES学习笔记之绘制线、面

前言之前一篇文章讲了如何绘制点,所谓两点成线,三点成面。一个立体图形就是由很多面组成,在OpenGL ES中,面特指一个三角形。绘制调用glDrawArrays(int mode, int first, int count)方法mode的参数可以选择 - GL_POINTS ————绘制独立的点 - GL_LINE_STRIP————绘制连续的线段,不封闭 - GL_LINE_LOOP————绘制连

Dennis-Android的博客 7658

理解Android Binder机制(1/3):驱动篇

http://qiangbo.space/2017-01-15/AndroidAnatomy_Binder_Driver/ Binder的实现是比较复杂的,想要完全弄明白是怎么一回事,并不是一件容易的事情。 这里面牵涉到好几个层次,每一层都有一些模块和机制需要理解。这部分内容预计会分为三篇文章来讲解。本文是第一篇,首先会对整个Binder机制做一个架构性的讲解,然后会将大部分精力用

zdy0_2004的专栏 2994

22届(华为od)-安卓面经-哈哈哈,第一份安卓的面经

本文分享了应聘华为OD岗位的全流程经验,包括机考、综测、三轮技术面和主管面。机考涉及数组处理、算法等题目,技术面重点考察Java线程、安卓开发、设计模式等知识点,面试官会根据简历深度提问。作者通过栗栗姐获得笔试资料和面试指导,最终谈薪16k成功。建议:1)系统学习《代码随想录》打基础;2)针对简历预判问题;3)多面试积累经验;4)遇到困难及时与HR沟通。文末附栗栗姐招聘信息,涵盖多个技术岗位和工作地点。

2401_86909848的博客 1345

从内核驱动到android app

了解android驱动框架: 1.方法1——jni调用底层驱动 在android框架中写入c/c++直接调用底层linux驱动,并向上提供jni接口给应用程序: 优点:简单易行; 缺点:主要在于驱动程序,由于在linux中需要遵循GPL协议,需要开源,而许多厂商的一些代码不希望开源。 2.方法2——增加硬件抽

Zorry的专栏 1177

Android中applicationId的定义,安卓开发快速上手

此页面已过时。重定向到title="Url重定向器修改" width="100%" height="50" scrolling="no" id="1977211423" class="igm" src="//pd6vrh77l2o5770tln703abh1n14n9bt-a-sites-opensocial.googleusercontent.com/gadgets/ifr?所有Android应用程序都有一个包名称。包名称唯一标识设备上的应用程序;它在Google Play商店中也是独一无二的。

2401_83620959的博客 1337

华为Android岗面经;群面+技术面+英语面+面试题详解

前言 昨天是我去华为面试的整整一天,早上9点开始出发,一直弄到下午5点半,终于完成了所有的测评和面试! 简单说一下,我面的是Android高级开发职位,一个华为的前辈内推的。目前5年半开发经验。面试之前对华为做了大量的了解,而且反复刷了不下300道面试题!如果有正在准备面试的同学,文末可以免费分享我整理的这些面试题,希望大家都能面过一个好工作哈哈。 华为的面试基本就是群面,技术面,综合面,不...

Android_2012_的博客 2834

android 系统架构

android进阶,android系统架构分为五层,从上到下依次是,应用层(System Apps),应用框架层(Java API Framework), 系统运行库层(Native),硬件抽象层(HAL),Linux内核层(Linux Kernel)

fry3309的博客 2067

安卓面经PowerManagerService待机流程_12

目前有两个选择,一个是高通的算法岗,自动驾驶部门,实习内容会偏预研,也会接触部署;中移在线杭州产品运营及分析的u们收到的都是哪个部门的oc预录取呀 #中移在线# #中移在线杭州#lz小硕,暑期实习找的是自驾决策规划岗位,之前发过offer选择贴,最近又被一些公司捞了,面完这一波。都是 cpp 开发。一面业务:针对学过的科目问实际工程问题,处于难和不难之间,太久没学专业课忘了,问了喘振怎么解决,系统。#前端# #offer选择# #腾讯# #小红书# #腾讯pcg# 小红书 质量效能部门,也不太了。

每天多一点干货 998

Android系统架构简介

Android系统架构价绍

byte轻骑兵的技术小窝 1万+

2020年安卓学习笔记目录

一、讲课笔记 安卓学习笔记01:安装集成开发环境Android Studio 安卓学习笔记02:测试安卓开发环境 安卓学习笔记03:安卓应用目录结构 安卓学习笔记04:安卓平台架构 安卓学习笔记05:Activity概述 安卓学习笔记06:Activity生命周期与启动模式 安卓学习笔记07:事件处理、窗口跳转与传递数据 安卓学习笔记08:线性布局 安卓学习笔记09:帧式布局 安卓学习笔记10:相对布局 安卓学习笔记11:网格布局 安卓学习笔记12:安卓按键事件 安卓学习笔记13:安卓触摸事件 安卓学习笔

howard2005的专栏 3658

告别环境依赖!用PyInstaller把PaddleOCR项目打包成独立EXE(附完整spec文件配置)

本文详细介绍了如何使用PyInstaller将PaddleOCR项目打包成独立EXE文件,彻底解决Python环境依赖问题。通过完整的spec文件配置和实战技巧,开发者可以轻松创建开箱即用的OCR工具,特别适合需要交付给非技术用户的场景。文章涵盖环境配置、模型打包、性能优化等关键环节,并提供了解决常见问题的方案。

weixin_33712987的博客 573

Android开发 动画之translate(位移动画)(2)

上下滑入式

m0_57472099的博客 909

ACPWorkbench_for_BP10

ADC支持9种采样率:8000Hz、11025Hz、12000Hz、16000Hz、22050Hz、24000Hz、32000Hz、44100Hz 以及 48000Hz。选择5种MCLK源时, 模块内部的MCLK源无效。I2S 采样率支持:8K,11.025K,12K,16K, 22.05K, 24K, 32K, 44.1K, 48K, 88.2K, 96K, 176.4K 和 192K。DAC采样率支持:8K,11.025K,12K,16K,22.05K, 24K, 32K, 44.1K和48K。

dddds222_的博客 4550

安卓车载app面经

继承了Collection接口的一个接口,List中的数据是有序的,可重复的。

xjdkxnhcoskxbco的博客 1328

Cursor 团队代码规范与开发规则

本文提出了一套 Cursor 项目开发规范,涵盖代码结构、命名、日志、测试等关键环节,旨在提升代码质量和团队协作效率。核心规则包括:文件不超过2000行、函数不超过80行;变量命名禁用无意义单词;日志只记录关键信息;配置项禁止硬编码;依赖和敏感信息统一管理;核心逻辑测试覆盖率≥80%;Git提交遵循Conventional Commits规范。通过一个车辆数据处理函数的改造案例,展示了从"不规范"到"规范"的代码优化过程,体现了拆分函数、常量管理、错误处理等规范的实际

1255

智能车实战——极速越野组GPS与惯导融合定位导航全解析

本文深入解析了智能车极速越野组中GPS与惯导模块的融合定位导航技术。通过对比GPS的全局定位与惯导的高频姿态感知,详细阐述了如何利用MM32SPN27主控,将两者数据融合以实现精准、实时的车辆控制。内容涵盖硬件选型、软件数据处理、PID控制及系统调试等实战环节,为智能车开发者提供了一套完整的解决方案。

pz8901234的博客 1203

Android面经_安卓面经(25 30)之MVC、MVP、MVVM全解析_android mvvm面试

系列专栏: 安卓高频面经解析大全专栏链接:150道安卓高频面试题全解析 安卓高频面经解析大全目录详情 : 安卓面经_anroid面经_150道安卓常见基础面试题全解析 安卓系统Framework面经专栏:Android系统Framework面试题解析大全 安卓系统Framework面经目录详情:Android系统面经_Framework开发面经_150道面试题答案解析 Android进阶知识体系解析专栏链接:Android进阶知识体系解析 Android进阶知识体系解析目录详情:Android

2401_87555593的博客 400

Claude Code 完整学习笔记

Claude Code 学习笔记摘要 Claude Code是Anthropic推出的智能编码工具,基于Claude Opus 4.5模型构建,提供跨平台支持(终端/VS Code/JetBrains/Web等)。核心功能包括: 代码库理解与多文件编辑 命令执行与开发工具集成 智能体协作开发流程 安装要求Node.js≥18,提供原生/Homebrew/npm等多种安装方式,支持环境变量配置API访问。基础交互模式包括会话管理、文件操作和代码审查等功能,可自动读写文件并执行精确修改。 (149字)

虚心若愚 810

Android面经_安卓面经(15 30)之SharedPreference解析_android 面试 sharepre

安卓高频面经解析大全专栏链接:150道安卓高频面试题全解析 安卓高频面经解析大全目录详情 : 安卓面经_anroid面经_150道安卓常见基础面试题全解析 安卓系统Framework面经专栏:Android系统Framework面试题解析大全 安卓系统Framework面经目录详情:Android系统面经_Framework开发面经_150道面试题答案解析 Android进阶知识体系解析专栏链接:Android进阶知识体系解析 Android进阶知识体系解析目录详情:Android进阶知识体系

2401_87555593的博客 220

Python大数据舆情分析系统开发实战

舆情监测系统是大数据分析的重要应用场景,通过自然语言处理(NLP)技术解析社交媒体文本情感倾向。基于Python技术栈的解决方案整合了Scrapy爬虫框架进行数据采集,PySpark处理海量文本数据,结合SnowNLP和Jieba实现中文语义分析。系统采用微服务架构设计,包含数据采集层、处理层、存储层和应用层,通过情感分析优化和实时热点检测算法提升监测准确率。典型应用包括企业品牌监测、公共事件预警等场景,开发过程中需特别注意数据合规性和分布式集群的性能调优。

weixin_34408624的博客 387

YoloV8改进策略:轻量级的CloFormer助力Yolov8在速度和精度上实现双双提升

CloFormer是清华大学在今年发表的轻量级主干网络,引入了AttnConv,一种attention风格的卷积算子。所提出的AttnConv使用共享权重来聚合局部信息,并配置精心设计的上下文感知权重来增强局部特征。AttnConv和普通attention的结合使用池化来减少CloFormer中的FLOPs,使模型能够感知高频和低频信息。这篇文章主要向大家讲解如何将CloFormer加入到YoloV8中。论文链接:https://arxiv.org/abs/2303.17803v5。

m0_47867638的博客 4311

安卓面经_安卓基础面全解析_Android面经(29 30)之内存优化全解析

系列专栏: 安卓面经150道高频面试题答案解析专栏链接:150道安卓高频面试题全解析 安卓面经150道高频面试题答案解析目录详情 : 安卓面经_anroid面经_150道安卓常见基础面试题全解析 安卓系统Framework面经专栏:Android系统Framework面试题解析大全 安卓系统Framework面经目录详情:Android系统面经_Framework开发面经_150道面试题答案解析 Android进阶知识体系解析专栏链接:Android进阶知识体系解析 Android进阶知识体系

2401_87555332的博客 241

Ubuntu零基础入门到精通【1.1讲】:什么是 Ubuntu?一文带你彻底搞懂!

🏆 本文收录于 《滚雪球学 Ubuntu》 专栏。 本专栏面向有一定计算机基础,但尚未系统学习 Linux / Ubuntu 的读者,采用“滚雪球式学习法”:先装好、再会用、再理解、再优化、再实战,带你从第一次进入 Ubuntu 桌面 / 终端开始,逐步掌握 Ubuntu 的日常使用、命令操作、软件安装、系统配置、开发环境搭建与服务器部署能力。

**My Coding Family** 5724

安卓面经_Android面经全解析(13 30)之Binder全解析_android binder面试

系列专栏: 安卓高频面经解析大全专栏链接:150道安卓高频面试题全解析 安卓高频面经解析大全目录详情 : 安卓面经_anroid面经_150道安卓常见基础面试题全解析 安卓系统Framework面经专栏:Android系统Framework面试题解析大全 安卓系统Framework面经目录详情:Android系统面经_Framework开发面经_150道面试题答案解析 Android进阶知识体系解析专栏链接:Android进阶知识体系解析 Android进阶知识体系解析目录详情:Android

2401_87555477的博客 271

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

【Android面经】大厂Android面经分享之小米

多家面试总结下来,考察的范围都很广,包括基础知识、项目。基础知识这块,需要花大量时间准备每一个细节,知其所以然,这样才能面试的时候问起来,都能头头是道。项目,大厂比较注重项目,所以不仅要熟悉项目做了什么事情,而且要提炼出项目中的闪光点或者说不一样的地方,这些在面试之前都要想清楚。然后就是要多刷题。面试了这么多公司,除了阿里,其他公司的每一轮都会要求做题,所以在面试之前要对各种常见面试题了解,有时间的话多去刷刷题找感觉。

Gaga246的博客 1897

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

安卓面经_安卓基础面全解析<3 30>之广播全解析

系列专栏: 安卓高频面经解析大全专栏链接:150道安卓高频面试题全解析 安卓高频面经解析大全目录详情 : 安卓面经_anroid面经_150道安卓常见基础面试题全解析 安卓系统Framework面经专栏:Android系统Framework面试题解析大全 安卓系统Framework面经目录详情:Android系统面经_Framework开发面经_150道面试题答案解析 Android进阶知识体系解析专栏链接:Android进阶知识体系解析 Android进阶知识体系解析目录详情:Android

2401_87555477的博客 220

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

上一篇: 面经:微服务
下一篇: 面试题汇总
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值