- 博客(41)
- 收藏
- 关注
原创 注解与依赖注入框架:
基本的定义:定义新的注解类型使用关键字@interface,这一定义一个接口很相像。//@Test//注解只有成员变量,没有方法。注解的成员变量在注解定义中以“无形参的方法”的形式来进行声明。其“方法名”定义了该成员变量的名字,其返回值,定义了该成员变量的类型。int age();定义了成员变量之后,就应该在使用该注解时为该成员变量指定值。//当然也可以在定义注解的成员变量的时候,使用default关键字为其指定默认值。
2023-12-20 00:25:30
702
原创 View体系和自定义View:
需要注意的是,凡事都要有度,自定义View毕竟不是规范的控件,如果设计不好、不考虑性能,则反而会适得其反;另外,其适配起来可能也会产生问题。如果能用系统控件的情况还是应尽量用系统控件。自定义View分为三大类,第一种是自定义View,第二种是自定义ViewGroup,第三种是自定义组合控件。其中,自定义View又分为继承系统控件(比如 TextView)和继承View两种情况。
2023-12-17 11:39:08
845
原创 认识Jetpack(下):
在类的头部使用@Database注解声明数据库版本和实体类,多个实体类用逗号分隔即可。然后Database类必须继承于。
2023-12-12 14:05:17
802
原创 认识Jetpack(上):
按照Google官方的介绍,Jetpack是一个由多个库组成的套件,可帮助开发者遵循最佳做法,减少样板代码并编写可以在各种Android版本和设备中一致运行的代码,这样开发者就可以集中精力编写重要的代码了。早在2017年的时候,Google就推出了一系列架构组件,称为ArchitectureComponents,并于2018年在Google I/O大会上提出Jetpack,且将Architecture Components纳入其中,时至今日,越来越多的组件,如room,paging3等等也被纳入其中。
2023-12-10 19:03:35
895
原创 Gradle:
在学习Gradle之前,先来了解一下要使用Gradle的原因。我们可以对 wrapper task 进行修改,生成自定义配置的 gradle-wrapper.properties。过程是在 build.gradle 构建脚本中通过自定义Wrapper task来配置gradle-wrapper.properties的属性值以达到自定义Gradle Wrapper的效果。对象插件是指实现了org.gradle.api.Plugin接口的类。想要自定义插件就需要实现这个方法。@Override。
2023-12-04 01:20:58
894
原创 Groovy基础:
闭包的定义语法为: { 参数列表 -> 语句 }。多参数用逗号分割。参数列表的部分是可选的,如果闭包只有一个参数的话,则参数的名字也是可选的,因为Groovy会隐式的指定it作为参数名。当然也可以直接使用it代替参数名。如果期望声明一个无参数的闭包,需要显式添加->来声明空参数列表, 以避免Groovy提供默认参数it。//{参数列表->语句}//默认指定it作为参数名//显式指定it{ ->语句}//无参。
2023-12-01 15:33:35
2040
原创 IPC机制:
其中重要的是android:process属性,表示是否要开启一个新的进程运行,而后面的命名方式有两种,分别是:加冒号和不加冒号,其中加冒号的进程名,表示这个新的进程对这个应用来说是私有的,其他的应用组件不能和新的进程运行在同一个进程中。而不加冒号的,表示这个服务运行在以这个名字命名的全局的进程中,当然前提的有权限,将允许不同应用的组件运行在同一个进程中,从而减少资源的占用。套接字是更基础的进程间通信机制,与其他通信机制不同的是,套接字可用于不同机器之间的进程间通信。
2023-11-30 13:58:59
1755
原创 Binder原理:
addService函数将数据打包发送给BpBinder来进行处理。BpBinder新建一个 IPCThreadState对象,并将通信的任务交给 IPCThreadState。IPCThreadState的 writeTransactionData函数用于将命令协议和数据写入mOut。IPCThreadState的waitForResponse函数主要有两个作用,一个作用是通过ioctl函数操作,mOut和mIn与Binder驱动进行数据交互,另一个作用是处理各种命令协议。
2023-11-29 14:40:16
1638
原创 理解输入系统和IMS:
输入事件的处理涉及了四个关键的类,分别是IMS、Evenfub、InputDispatcher 和InputReaderIMS 启动了InputDispatcherThread 和InputReaderThread,它们分别用来运行InputDispatcher和 InputReader。InputDispatcher 先于InputReader被创建,InputDispatcher的 dispatchOnceInnerLocked函数用来将事件分发给合适的窗口。
2023-11-23 00:38:39
925
原创 理解包管理机制和PMS:
与ActivityManager和AMS的关系类似,PMS也有一个对应的管理类,用于向应用程序进程提供一些功能。PackageManager是一个抽象类。它的具体实现类为,ApplicationPackageManager中的方法会通过获取一个应用程序的所有信息。获取四大组件的信息。查询permission的相关信息。获取包的相关信息。安装和卸载APK。
2023-11-22 00:19:18
967
原创 系统源码的下载,编译,调试:
Android平台的编译系统,其实就是用Makefile写的一个独立项目。它定义了规则,实现了“自动化编译”,不仅能把分散在数百个Git库中的代码整合起来进编译,而且还能把产物分门别类地输出到一个目录中,打包成手机ROM,还可以生成应用开发时所使用的SDK、NDK等。因此,采用Makefile编写的编译系统,也可以称为Makefile编译系统。Makefile编译系统的一部分Android.mk,定义了一个模块的必要参数,使模块随着平台编译。
2023-11-19 15:21:47
122
原创 Hook技术:
我们知道Android系统的代码调用和回调都是按照一定的顺序执行的,例如:对象A调用对象B,对象B处理之后将数据回调给对象A。而采用Hook技术之后为:我们可以看到Hook可以是一个方法或者是一个对象,它就像是一个钩子一样挂在对象A和对象B之间(也可以说劫持),当对象A调用对象B之前做一些处理(比如修改方法的参数和返回值),起到了欺上瞒下的作用。
2023-11-11 13:36:36
84
原创 热修复原理:
Instant Run是Android Studio2.0以后新增加的一个运行机制,能够显著的减少开发人员第二次以及以后构建和部署时间。在没有使用Instant Run之前,我们编译和部署应用程序的流程为:我们看到传统的编译部署需要重新安装App和重启App,这种情况显然会很耗时,Instant Run会避免这种情况。从图中可以看出 Instant Run的构建和部署都是基于更改的部分的。
2023-11-10 18:18:23
102
原创 理解ClassLoader:
自定义类加载器首先从缓存中查找class文件是否已经加载,如果已经加载就返回,否则委托给父加载器,如果一直没有加载到,则一直委托到Bootstrap ClassLoader,如果Bootstrap ClassLoader在缓存都没有找到,那么则在它的目录查找,如果找到就返回class,没有就交给子加载器,子加载器重复该步骤查找目录,直到返回至自定义类加载器,如果还没有就抛出异常。采用双亲委托模式可以避免重复加载且更加安全。
2023-11-09 17:25:40
146
原创 Java虚拟机,Dalvik和ART:
并发GC,不会使App的线程暂停,该GC是在后台线程运行的,并不会阻止内存分配。Alloc:当堆内存已满时,App尝试分配内存而引起的GC,这个GC会发生在正在分配内存的线程中。App显示的请求垃圾收集,例如调用System.gc()。与DVM一样,最佳做法是应该信任GC并避免显式地请求GC,显式地请求GC会阻止分配线程并不必要地浪费CPU周期。如果显式地请求GC导致其他线程被抢占,那么有可能会导致jank(App同一帧画了多次)。
2023-11-08 19:48:14
136
原创 JNI原理:
JNI是Java Native Interface,翻译为,是Java与其他语言通信的桥梁,当查询一些用Java技术无法处理的任务时,开发人员就可以使用JNI技术来完成。一般来说主要有以下情况需要用到JNI技术。JNI不只是应用于Android开发,它还有非常广泛的应用场景。而在Android的应用场景一般有:音频开发,热修复,插件化,逆向开发,系统源码调用等等。为了更加方便的使用JNI技术,Android还提供了NDK这个工具集合。
2023-11-07 18:38:44
74
原创 理解WindowManager与WindowManageService:
对所要添加的窗口进行检查,如果窗口不满足一些条件,就不再执行下面的逻辑。WindowToken相关的处理。WindowState的创建和相关的处理,并且将WindowState和WindowToken相关联。创建和配置DisplayContent,完成窗口添加到系统之前的准备工作。检查线程的正确性。从三个列表中删除与它对应的元素。判断是否可以直接执行删除操作。执行删除操作,释放资源。
2023-11-06 19:55:53
149
原创 理解ActivityManagerService:
Activity的栈管理是建立在Activity任务栈模型之上的,有了栈管理,我们可以对应用程序进行操作,应用可以复用应用中以及其他应用的Activity,节省了资源。AMP的startActivity方法它把传入的参数写入Parcel类型的data中,通过IBinder类型的mRemote对象的transact方法向服务器端的AMS发送信息,那么服务器端的AMS就会从Binder线程池中读取客户端发送的数据,最终调用AMN的onTransact方法,它会调用AMS的startActivity方法。
2023-11-05 00:37:08
57
原创 上下文Context:
和Context相关联的类,除了它们以外,还有Activity,ContextThemeWrapper等等。ContextImpl和ContextWrapper都继承自Context,在ContextWrapper中包含了很多的Context类型的mBase对象,mBase对象具体指的是ContextImpl,ContextImpl提供了很多的功能,但是外界需要使用并且扩展ContextImpl的功能,因此使用了。
2023-11-03 23:53:40
56
原创 四大组件的工作过程(下):
动态注册是在代码中注册,它可以自由的控制注册和注销,但必须在程序启动之后才能接收广播。理论上讲动态注册能够监听到的系统广播,静态注册也能够监听到,但是由于静态注册的恶意使用,导致在Android8.0之后,所有的隐式广播都不允许使用静态注册的方式来接收。再来看broadcastIntentLocked方法,该方法首先会将动态注册的广播接收者和静态注册的广播接收者按照优先级不同存储在不同的列表中去,再将这两个列表合并到receivers列表中,这样receivers列表就包含了所有的广播接收者。
2023-11-03 18:09:08
37
原创 四大组件的工作过程(上):
在系统启动和应用程序进程启动之后,就应该启动应用程序了,也就是启动根Activity。而Activity是四大组件之一,其他还有Service,BroadcastReceiver和ContentProvider。
2023-11-02 14:28:27
44
原创 Android应用程序进程启动过程:
要想启动一个应用程序,首先要保证这个应用程序所需要的应用程序进程已经启动。AMS在启动应用程序时会检查这个应用程序所需要的应用程序进程是否存在,不存在就会请求Zygote进程启动需要的应用程序进程。我们知道Zygote的Java框架层中会创建一个service端的socket,它等待AMS请求Zygote来创建新的应用程序进程。Zygote进程通过fork自身创建应用程序进程,这样应用程序进程就会获取Zygote进程启动时创建的虚拟机实例。
2023-10-30 18:47:40
79
原创 Android系统启动:
创建和挂载启动需要的文件目录。初始化和启动属性服务。解析init.rc配置文件并且启动Zygote进程。调用runtime的start函数启动Zygote。创建Java虚拟机并且为Java虚拟机注册JNI方法。通过JNI调用ZygoteInit的main方法进入zygote的Java框架层。通过registerServerSocket方法创建一个server端的socket;并且通过runSelectLoop方法来等待AMS请求创建新的应用程序进程。
2023-10-30 11:47:46
88
原创 MySQL:
MySQL是一种DBMS,即是一种数据库软件。它以成本低,性能高,可信赖,简单等优点收获了大量公司和开发者。DBMS可以分为两部分:一部分为基于共享文件系统的DBMS,用于桌面用途,通常不用于高端或者更关键的应用;一部分为基于客户端-服务器端的DBMS,MySQL,Oracle等等数据库都是基于客户端-服务器端的数据库。其中客户端-服务器端应用又可以分为两部分,服务器部分是负责所有的数据访问和处理的一个软件。关于数据的添加,删除,更新的所有请求都是由服务器软件完成。
2023-10-20 16:02:56
110
1
原创 SQL(上):
SQL是structured query language(结构化查询语言)的缩写。SQL是一种专门用来与数据库沟通的语言,SQL是一种强有力的语言。
2023-10-14 13:46:04
159
1
原创 Kotlin小知识点总结
注解:在单例类或者companion object中的方法里加上@JvmStatic注解,那么编译器就会把这些方法编译成为真正的静态方法。顶层方法:它是指那些没有定义在任何类中的方法,kotlin会把所有的顶层方法全部编译成为静态方法。如果在kotlin中调用的话,直接写上方法名即可,因为所有的顶层方法都可以在任何的位置被直接调用,不用管包名路径,也不用创建实例。而Java没有顶层方法这个概念,所有的方法都必须写在类中。
2023-10-10 18:10:09
263
1
原创 读书笔记(四):并发
在HotSpot VM的线程模型中,Java线程(java.lang.Thread)被一对一映射为本地操作系统线程。Java线程启动时会创建一个本地操作系统线程;当该Java线程终止时,这个操作系统线程也会被回收。操作系统会调度所有线程并将它们分配给可用的CPU。在上层,Java多线程程序通常把应用分解为若干个任务,然后使用用户级的调度器(Executor框架)将这些任务映射为固定数量的线程;在底层,操作系统内核将这些线程映射到硬件处理器上。应用程序通过Executor框架控制上层的调度;
2023-10-01 19:29:19
157
原创 读书笔记(三):并发
在并发编程中,有时候需要使用线程安全的队列。如果要实现一个线程安全的队列有两种方式:一种是使用阻塞算法,另一种是使用非阻塞算法。使用阻塞算法的队列可以用一个锁(入队和出队用同一把锁)或两个锁(入队和出队用不同的锁)等方式来实现。非阻塞的实现方式则可以使用循环CAS的方式来实现。ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列,它采用先进先出的规则对节点进行排序,当我们添加一个元素的时候,它会添加到队列的尾部,当我们获取一个元素时候,它会返回队列头部的元素。
2023-09-30 10:46:56
145
原创 读书笔记(二):并发
现代操作系统在运行一个程序时,会为其创建一个进程。例如,启动一个Java程序,操作系统就会创建一个Java进程。现代操作系统调度的最小单元是线程,也叫轻量级进程(Light Weight Process),在一个进程里可以创建多个线程,这些线程都拥有各自的计数器、堆栈和局部变量等属性,并且能够访问共享的内存变量。处理器在这些线程上高速切换,让使用者感觉到这些线程在同时执行。
2023-09-27 11:51:32
171
原创 读书笔记(一):并发
即使是单核处理器也支持多线程执行代码,CPU通过给每个线程分配时间片来实现这个机制。时间片是CPU分配给各个线程的时间,因为时间片非常短,所以CPU通过不停的切换线程执行,让我们感觉多个线程是同时执行的,时间片的时间一般是几十毫秒。CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便于下次切换回这个任务时,可以再加载这个任务的状态。所以任务从保存到再加载的过程就是一次上下文切换。同样上下文切换也会影响多线程的执行速度。
2023-09-25 13:37:04
229
1
原创 数据结构(六):堆,红黑树
红黑树是一种自平衡的二叉查找树,是一种高效的查找树。红黑树具有良好的效率,它可在O(logN)时间内完成查找、增加、删除等操作。因此,红黑树应用很广泛。(与AVL树不同的是它并没有AVL树的平衡因子的概念,它只是靠着满足红黑树的性质来维持一种接近平衡的结构,进而提升整体的性能,同时红黑树的插入删除比AVL树更便于控制操作,查找时性能没差别)。
2023-09-20 00:40:38
651
1
原创 数据结构(五):图
在表中,数据元素是被串起来的,每个数据元素只有一个直接前驱和一个直接后继元素。在树中,数据元素有着明显的层次关系,并且每一层的数据元素都可能与下一层的多个元素有关,但是只能和上一层的一个数据元素相关。而图是一种更加复杂的数据结构,图的定义为:一个图G=(V,E)由顶点的集合V和边的集合E组成,每一条边就是一幅点对(v,w),其中v,w都属于V,有时候也会把边叫做弧。在表中我们把数据元素叫做元素,在树中把数据元素叫做结点,那么在图中我们称数据元素为顶点。在表中可以没有元素,叫做空表;
2023-09-18 22:25:49
276
原创 数据结构(四):散列表
HashSet是基于HashMap来实现的,所以允许空值,且不是线程安全的(区别就在 于:HashMap中输入一个键值对,而在HashSet中只输入一个值)。HashSet还继承了 AbstractSet 抽象类,实现了Set接口,同时还实现了Cloneable(允许克隆),Serializable (可序列化)。
2023-09-17 17:48:50
442
1
原创 数据结构(三):树
树是n个结点的有限集,当n=0时,叫做空树。而在任意的一颗非空树中,有且仅有一个特定的叫做根的结点,在n>1时,其余的结点就可以分为m(m>0)个互不相交的有限集,而每个有限集本身又都是一棵树,也叫做根的子树。二叉树是n(n>=0)个结点的有限集合;该集合或者在n=0时,我们称它为空二叉树,或 者是由一个根结点和两棵互不相交的,分别被称为根结点的左子树和右子树的二叉树 组成。
2023-09-15 21:04:54
314
原创 数据结构(二):栈和队列
栈是只限定在一端进行插入和删除操作的表。我们把允许插入和删除的一端叫做栈顶,而另一端叫做栈底,当栈不含有任何元素时又叫做空栈。栈又叫做后进先出的表,即LIFO表。队列同样作为一种特殊的表,但与栈不同的是,队列只允许在一端进行插入操作,而另一端进行删除操作。队列是一种先进先出的表,即FIFO,允许插入的一端叫做队尾,而允许删除的一端叫做队头。Java中定义了接口用来表示队列。Java中的Queue与ListSet属于同一个级别接口,同时它继承了Collection接口。
2023-09-12 22:51:54
274
原创 数据结构(一):表
零个或多个数据元素的有限序列,也即是:元素之间是有顺序的,若元素存在多个,则第一个元素无前驱,最后一个元素无后继,其他每个元素都有且只有一个前驱和后继。表的元素的个数n(n>=0)定义为表的长度,当n=0时,称为空表。它是JDK专门提供的一个接口java.util.Iterator。用于迭代访问Collection中的元素。它取出元素之前要先判断集合中有没有元素,如果有就把这个元素取出来,继续再判断,如果还有就再取出来,一直把集合中所有元素全部取出。过程也叫做迭代。
2023-09-11 22:49:54
338
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人