Android基础

Context继承关系
Activity/Service/Application都是继承自ContextWrapper,而ContextWrapper内部会包含一个base context,由这个base context去实现了绝大多数的方法。凡是跟UI相关的,都应该使用Activity作为Context来处理;其它的一些操作,Service/Activity/Application等示例都可以。
参考文档:Android Context 上下文 你必须知道的一切


ActivityThread工作原理,主线程的消息循环,与SystemServer跨进程交互(AMS)
在Application进程中管理执行主线程,调度和执行Activity、Broadcast,以及和Activity管理请求的其它操作。
system_server进程是由ActivityThread.attach()过程创建Application
普通app进程是由ActivityThread.handleBindApplication()过程创建Application(两次Binder调用)
参考文档:理解Application创建过程ActivityThread


Application/Activity/Service生命周期,Activity的onNewIntent


Service/IntentService,Service和其它组件间通信,顺带HandlerThread
a.IntentService内部维护一个工作线程来处理耗时操作,每一个耗时操作将会在onHandleIntent回调方法中执行,可以多次启动IntentService,依次串行执行,任务执行完成后Service会自动停止(stopSelf)。
b.HandlerThread是自带Looper的Thread,创建后需start,之后便会调用Looper.prepare()创建该线程的Looper,再调用Looper.loop()开启线程消息循环。外界通过该线程的Looper创建对应的Handler对象,就可以发送对应的消息到该线程进行处理。


Fragment的懒加载实现,参数传递与保存
a.当使用FragmentTransaction来控制Fragment的show和hide时,onHiddenChange()方法会被回调。
b.setUserVisibleHint()在Fragment创建时会被回调(时机可能在onCreateView之前,控件使用需谨慎),且当Fragment可见状态发生变化时也会被回调;当Fragment结合ViewPager使用时,setUserVisibleHint()会被调用。
c.当一个Fragment重新创建的时候,系统会再次调用Fragment中的默认构造函数,推荐使用Fragment.setArguments(Bundle bundle)方式来传递参数。Activity重新创建时,会重新构建它所管理的Fragment,原先Fragment的字段值将会全部丢失,但是通过Fragment.setArguments(Bundle bundle)方式设置的bundle会保留下来,并在重建时恢复,setArguments方法的使用必须要在FragmentTransaction的commit之前使用。
d.设置setRetainInstance(true)后,可以让Fragment在Activity被重建时保持实例不变。
参考文档:为什么要通过Fragment.setArguments(Bundle)传递参数


Fragment使用陷阱
参考文档:


ContentProvider实例详解
ContentProvider(内容提供者)用于提供数据的统一访问格式,封装底层的具体实现。对于数据的使用者来说,无需知晓数据的来源是数据库、文件、或者网络,只需简单地使用ContentProvider提供的数据操作接口,也就是增(insert)、删(delete)、改(update)、查(query)四个过程。
参考文档:ContentProvider 使用详解理解ContentProvider原理


BroadcastReceiver/LocalBroadcastManager实现原理
广播(Broadcast)机制用于进程/线程间通信,分为静态/动态
--->ApplicationThread.scheduleReceiver
参考文档:Android Broadcast广播机制分析


Android页面恢复,onSaveInstanceState(Activity容易被系统销毁时触发)和onRestoreInstanceState
a.在onSaveInstanceState里面保存数据,而在onRestoreInstanceState恢复数据,这个场景是在进程被系统回收之后,我们在最近使用程序列表里面点击那个应用时,系统会重启进程并且帮我们恢复Activity。前台进程死亡后恢复,恢复的是当前显示的Activity的上一个Activity,记住Activity要想被恢复,必须是经历过onSaveInstanceState的Activity。
b.onSaveInstanceState不一定会触发,onPause和onStop之后的Activity遇到系统内存不足、系统配置变化等会导致Activity销毁并可能触发onSaveInstanceState,不适合保存持久化数据(应在onPause中),适合保存瞬态数据,如UI控件状态、成员变量的值。


Android消息机制Handler/Looper/MessageQueue,主线程Looper.loop()为啥不会死循环
在主线程的MessageQueue没有消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,通过往pipe管道端写入数据来唤醒主线程工作。这里采用的epoll机制,是一种IO多路复用机制,可以同时监听多个描述符,当某个描述符就绪(读或写就绪),则立即通知响应程序进行    读或写操作,本质同步IO,即读写是阻塞的。所以说,主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源。
参考文档:Android消息机制


IdleHandler闲时任务处理
每次消费掉一个有效Message,在获取下一个Message时,如果当前时刻没有需要消费的有效(需要立即执行的)Message,那么会执行一次IdleHandler,执行完成之后线程进入休眠状态,直到被唤醒。
参考文档:你知道android的MessageQueue.IdleHandler吗?


Activity/Window/DecorView/TitleView+ContentView
a.Activity像个控制器,不负责视图部分。Window像个承载器,装着内部视图。DecorView是顶层视图,是所有View的最外层布局。ViewRoot像个连接器,负责沟通,通过硬件的感知来通知视图,进行用户之间的交互。
b.当用户点击屏幕产出一个触摸行为,这个触摸行为则是通过底层硬件来传递捕获,然后交给ViewRootImpl,接着将事件传递给DecorView,而DecorView再交给PhoneWindow,PhoneWindow再交给Activity,然后接下来就是我们常见的的View事件分发了。
参考文档:简析Window、Activity、DecorView以及ViewRoot之间的错综关系
                  ViewRootImpl源码分析事件分发


Android事件分发机制,嵌套滑动实现原理
a.Android事件分发先是传递到ViewGroup,再由ViewGroup传递到View的。
b.在ViewGroup中可以通过onInterceptTouchEvent方法对事件传递进行拦截,onInterceptTouchEvent方法返回true代表不允许事件继续向子View传递,返回false代表不对事件进行拦截,默认返回false。
c.子View中如果将传递的事件消费掉,ViewGroup中将无法接收到如何事件。
父View收到ACTION_DOWN,如果没有拦截事件,则ACTION_DOWN前驱事件被子视图接收,父视图后续事件会发送到子View。此时如果在父View中拦截ACTION_UP或ACTION_MOVE,在第一次父视图拦截消息的瞬间,父视图指定子视图不接收后续消息了,同时子视图会收到ACTION_CANCEL事件。
滑动冲突解决:一文解决Android View滑动冲突
参考文档:Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
                  Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
                  一文读懂Android View事件分发机制


Android多线程的实现:Thread/ThreadPool/HandlerThread/AsyncTask/IntentService
ThreadPool:别再说你不懂线程池——做个优雅的攻城狮
AsyncTask:你真的了解AsyncTask?


View/SurfaceView/TextureView
参考文档:视频画面帧的展示控件 SurfaceView 及 TextureView 对比
                  Android UI 显示原理分析小结
                  一篇文章看明白 Android 图形系统 Surface 与 SurfaceFlinger 之间的关系


LayoutInflater实现原理
1、如果root为null,attachToRoot将失去作用,设置任何值都没有意义,新解析的view会直接作为结果返回。
2、如果root不为null,attachToRoot设为true,则会给加载的布局文件的指定一个父布局,即root,新解析出来的view会被add到root中去,然后将 root 作为结果返回。
3、如果root不为null,attachToRoot设为false,则会将布局文件最外层的所有layout属性进行设置,当该view被添加到父view当中时,这些layout属性会自动生效。
4、在不设置attachToRoot参数的情况下,如果root不为null,attachToRoot参数默认为true。
参考文档:LayoutInflater原理分析


ViewStub
1、使用 ViewStub 需要在 XML 中设置 android:layout,不是 layout,否则会抛出异常。throw new IllegalArgumentException("ViewStub must have a valid layoutResource");
2、ViewStub 不能作为根布局,它需要放在 ViewGroup 中, 否则会抛出异常。throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");
3、一旦调用 setVisibility(View.VISIBLE) 或者 inflate() 方法之后,该 ViewStub 将会从试图中被移除(此时调用 findViewById() 时找不到该 ViewStub 对象)。
4、如果指定了 mInflatedId , 被 inflate 的 layoutView 的 id 就是 mInflatedId。
5、被 inflate 的 layoutView 的 layoutParams 与 ViewStub 的 layoutParams 相同。
参考文档:ViewStub解析


MeasureSpec源码解析
对于DecorView而言,它的MeasureSpec由窗口尺寸和其自身的LayoutParams共同决定;对于普通的View,它的MeasureSpec由父视图的MeasureSpec和其自身的LayoutParams共同决定。


View的绘制流程,自定义View,自定义ViewGroup,View宽高获取时机
参考文档:一文彻底搞懂Android View的绘制流程


动画(帧动画/补间动画/属性动画)


requestLayout/invalidate/postInvalidate区别与联系
子View调用requestLayout方法,会标记当前View及父容器,同时逐层向上提交,直到ViewRootImpl处理该事件,ViewRootImpl会调用三大流程,从measure开始,对于每一个含有标记位的View及其子View都会进行测量、布局、绘制。
当子View调用了invalidate方法后,会为该View添加一个标记位,同时不断向父容器请求刷新,父容器通过计算得出自身需要重绘的区域,直到传递到ViewRootImpl中,最终触发performTraversals方法,进行开始View树重绘流程(只绘制需要重绘的视图)。
参考文档:Android View 深度分析requestLayout、invalidate与postInvalidate


RecyclerView与ListView(缓存原理,区别联系,优缺点)


ViewPager的缓存实现


SharedPreferences
SharedPreferences是Android平台上 轻量级的存储类,用来保存App的各种配置信息,其本质是一个以 键值对(key-value)的方式保存数据的xml文件,其保存在/data/data/shared_prefs目录下。虽然 内存缓存机制 表面上看起来好像是一种 空间换时间 的权衡,实际上规避了短时间内频繁的I/O操作对性能产生的影响,而通过良好的代码规范,也能够避免该机制可能会导致内存占用过高的副作用。
本质上文件的I/O是一个非常重的操作,直接放在主线程中的commit()方法某些场景下会导致ANR(比如数据量过大),因此更合理的方式是应该将其放入子线程执行。但是,更多的问题随之而来,比如子线程更新文件,必然会引发线程安全问题,通过使用了3把锁(mLock/mEditorLock/mWritingToDiskLock),对整个读写操作的线程安全进行了保证。
apply()方法设计的初衷是为了规避主线程的I/O操作导致ANR问题的产生,但并没有完全规避掉这个问题。在apply()方法中,首先会创建一个等待锁,根据源码版本的不同,最终更新文件的任务会交给QueuedWork.singleThreadExecutor()单个线程或者HandlerThread去执行,当文件更新完毕后会释放锁。但当Activity.onStop()以及Service处理onStop等相关方法时,则会执行 QueuedWork.waitToFinish()等待所有的等待锁释放,因此如果SharedPreferences一直没有完成更新任务(比如太频繁无节制的apply()导致任务过多),有可能会导致卡在主线程,最终超时导致ANR。Google 在 Activity 和 Service 调用 onStop 之前阻塞主线程来处理 SP,我们能猜到的唯一原因是尽可能的保证数据的持久化,因为如果在运行过程中产生了 crash,也会导致 SP 未持久化,持久化本身是 IO 操作,也会失败。由于没有使用跨进程的锁,SharedPreferences是进程不安全的,在跨进程频繁读写会有数据丢失的可能。实现思路很多,比如使用文件锁,保证每次只有一个进程在访问这个文件;或者对于Android开发而言,ContentProvider作为官方倡导的跨进程组件,其它进程通过定制的ContentProvider用于访问SharedPreferences,同样可以保证SharedPreferences的进程安全。
参考文档:SharedPreference存在的问题SP ANR问题SharedPreferences源码解析


MMKV


DataStore


Android SQLite的入门使用


assets目录与res目录的区别
两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制。
res/raw中的文件会被映射到R.java文件中,访问的时候直接使用资源ID即R.id.filename;assets文件夹下的文件不会被映射到R.java中,访问的时候需要AssetManager类。
res/raw不可以有目录结构,而assets则可以有目录结构,也就是assets目录下可以再建立文件夹。


Android换肤原理


Android两种虚拟机,DVM和ART
参考文档:Dalvik 和 ART 有什么区别?


Android混淆
参考文档:Android混淆(Proguard)详解点亮技能树 - 从害怕到玩转 Android 代码混淆!


ADB常用命令


APP安装过程
与应用相关的一些目录:
        a./system/priv-app:系统应用安装路径,Android 4.4+开始出现,区分系统应用权限,拥有SignatureOrSystem权限,此目录下的sevice具有保活能力;
        b./system/app:系统应用安装路径,权限略低于priv-app目录下的应用,放置比如厂商内置应用;
        c./data/app:用户应用安装路径,应用安装时将apk复制到此目录下;
        d./data/data:用户应用数据存放路径,存在沙箱隔离;
        e./data/dalvik-cache:存放应用的dex文件;
        f./data/system:存放应用安装相关文件。packages.xml是一个应用的注册表,在解析应用  时创建,有变化时更新,记录系统权限,各应用信息,如name、codePath、flag、version、userid,下次开机时直接读取并添加到内存列表;package.list指定应用的默认存储位置、userid等。
应用安装过程总结:
        a.将应用apk拷贝到指定目录下;
        b.解压apk,将dex文件拷贝到/data/dalvik-cache目录,创建/data/data数据目录;
        c.解析AndroidManifest.xml及其它资源文件,提取应用包信息,注册到packages.xml中;
        d.由Launcher进程通过PMS取出所以应用程序,展示在桌面上。
参考文档:Android应用安装过程深度解析


Android应用程序启动流程


Activity/Service/Broadcast启动流程,核心AMS


Android包管理机制,核心PMS


AndroidWindow管理机制,核心WMS


Android多进程
在Android中使用多进程,就是在AndroidManifest中给四大组件指定android:process属性。设置android:process属性时,如果是以:开头的名字,则表示这是一个应用程序的私有进程,否则它是一个全局进程(需符合android包名规范com.example.eg)。私有进程的名称会在冒号前自动加上包名,而全局进程则不会,一般我们都是有私有进程,很少使用全局进程。
1.静态成员和单例模式失效:Android为每一个进程分配一个独立的虚拟机,不同虚拟机在内存分配上有不同的地址空间,这就导致多进程下访问同一个类的对象会产生多份副本。所以在一个进程中修改某个值,只会在当前进程有效,对其他进程不会造成任何影响。解决方法就是使用Intent或者aidl等进程通讯方式传递内容。
2.线程同步失效:因为多进程的内存地址空间不同,锁的不是同一个对象,所以不管是锁对象还是锁全局对象都无法保证线程同步。3.SharedPreference的可靠性下降:因为SharedPrefercences底层通过读写xml实现,并发读写不是安全的操作,甚至会出现数据错乱。解决方法就是多进程的时候不并发访问同一个文件,比如子进程涉及到操作数据库,就可以考虑调用主进程进行数据库的操作。4.Application会多次创建:默认情况下,应用拥有一个主进程。组件被指定新进程之后,系统在启动这个组件的时候,事先会创建这个进程,再创建该组件。打印出进程名称办法:重载Application类的onCreate方法即可。
参考文档:Android 多进程通信


进程间通信IPC方式(socket/pipe/信号signal/消息队列message/共享内存/信号量semaphore)
参考文档:进程间通信IPC (InterProcess Communication)Android 多进程通信


Binder机制
面向对象思想的引入将进程间通信转化为通过某个Binder对象的引用,调用该对象的方法,而其独特之处在于Binder对象是一个可以跨进程引用的对象,它的实体(本地对象)位于一个进程中,而它的引用(代理对象)却遍布于系统的各个进程之中。
a.对于Server进程来说,Binder指的是Binder本地对象
b.对于Client进程来说,Binder指的是Binder代理对象,它只是Binder本地对象的远程代理;对这个Binder代理对象的操作,会通过驱动最终转发到Binder本地对象上去完成;对于一个拥有Binder对象的使用者而言,它无需关心这是一个Binder代理对象还是Binder本地对象;对于代理对象的操作和对本地对象的操作对它来说没有区别。
c.对于传输过程而言,Binder是可以进行跨进程传递的对象;Binder驱动会对具有跨进程传递能力的对象做特殊处理:自动完成代理对象和本地对象的转换。
Server进程里面的Binder对象指的是Binder本地对象,Client进程里面的对象指的是Binder代理对象。在Binder对象进行跨进程传递的时候,Binder驱动会自动完成这两种类型的转换。因此,Binder驱动必然保存了每一个跨越进程的Binder对象的相关信息。在驱动中,binder_proc是描述进程上下文信息的,每一个用户空间的进程都对应一个binder_proc结构体,Binder本地对象的代表是一个叫做binder_node的数据结构(Server在Binder驱动中的体现),Binder代理对象的代表是一个叫做binder_ref的数据结构(Client在Binder驱动中的体现)。有的地方把Binder本地对象直接称作Binder实体,把Binder代理对象直接称作Binder引用(句柄),其实指的是Binder对象在驱动里面的表现形式。
“Binder实体”和“Binder引用”可以很好的将Server和Client关联起来:因为Binder实体和Binder引用分别是Server和Client在Binder驱动中的体现。Client获取到Server对象后,“Binder引用所引用的Binder实体(即binder_ref.node)”会指向“Server对应的Binder实体”;同样的,Server被某个Client引用之后,“Server对应的Binder实体的引用列表(即binder_node.refs)”会包含“Client对应的Binder引用”。
IBinder是一个接口,它代表了一种跨进程传输的能力;只要实现了这个接口,就能将这个对象进行跨进程传递;这是驱动底层支持的;在跨进程数据流经驱动的时候,驱动会识别IBinder类型的数据,从而自动完成不同进程Binder本地对象以及Binder代理对象的转换。
IBinder负责数据传输,那么client与server端的调用契约(这里不用接口避免混淆)呢?这里的IInterface代表的就是远程server对象具有什么能力,具体来说,就是aidl里面的接口。
Java层的Binder类,代表的其实就是Binder本地对象。BinderProxy类是Binder类的一个内部类,它代表远程进程的Binder对象的本地代理;这两个类都继承自IBinder,因而都具有跨进程传输的能力;实际上,在跨越进程的时候,Binder驱动会自动完成这两个对象的转换。
在使用AIDL的时候,编译工具会给我们生成一个Stub的静态内部类;这个类继承了Binder,说明它是一个Binder本地对象,它实现了IInterface接口,表明它具有远程Server承诺给Client的能力;Stub是一个抽象类,具体IInterface的相关实现需要我们手动完成,这里使用了策略模式。
参考文档:带你简单理解Binder
                  Binder学习指南
                  Android Binder机制(一) Binder的设计和框架


Binder异常处理机制
参考文档:Binder异常处理机制


AIDL实现原理
参考文档:源码分析——从AIDL的使用开始理解Binder进程间通信的流程


屏幕适配


FileProvider
参考文档:Android 适配 - FileProvider


权限动态申请
使用兼容库checkSelfPermission、requestPermissions等几个权限相关的方法用v4包里的可以兼容6.0以下版本,否则需要包一层版本判断。
参考文档:Android动态权限申请


MultiDex
参考文档:MultiDex工作原理分析和优化方案


HotPatch热修复
参考文档:Android N混合编译与对热补丁影响解析
                  Android技术——ASM字节码插桩
                  Android Transform + ASM 初探


组件化


插件化


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容