👹知识复盘【技术类】

微信截图_20230512153226.png

1:int、Integer有什么区别?

Integer是int的包装类,默认是null;int是基本数据类型,默认值是0;

2:equals与==区别,stringBuffer和stringbuilder区别

equals:比较的是两个对象是否相等
==:比较的是栈内存中的值
StringBuffer:线程安全
StringBuilder:线程不安全
既然 StringBuffer 是线程安全的,它的所有公开方法都是同步的,StringBuilder 是没有对方法加锁同步的,所以毫无疑问,StringBuilder 的性能要远大于 StringBuffer。

3:A启动B时activity的两个activity生命周期的流程。

A启动:
Aactivity oncreate  onstart onResume
A进入B:
Activity onPause  BActivity oncrete onstart onResume Activity onStop
B返回:
Bctivity onPause Activity restart  start onResume Bactivity onStop ondestroy
A返回:
Activity onPase onstop ondestroy

4:Activity旋转会调用哪些方法?

没有任何配置的情况下:
onPause()--onStop()--onDestroy()--onCreate()--onStart()--onResume();

5:android四种启动模式

1:standard标准模式:
每次启动都会重新创建一个新的实例入栈,不管之前是否存在。
2:SingleTop:
栈顶复用模式,如果Activity处于栈顶,则不再创建新的activity,如果不存在栈顶则重新创建实例。
3:SingleTask:
栈内复用模式,当需要创建这个activity时,如果activity已经存在则将所有的在它之上的activity销毁,让它处于栈顶。
4:singleInstance:
单实例模式,具有此模式的Activity单独位于一个任务栈中。只能有一个实例。

6:startService和bindService区别,多次启动调用哪些方法?

1:生命周期上的区别:
startService:onCreate-->onStartCommand-->onStop-->onDestory
bindService:onCreate-->onBind-->unBindService-->onDestroy。
多次调用startService时service只能被创建一次,每次调用startService,onStartCommand都会执行;
第一次执行bindService时,onCreate-->onBind都会被调用,多次执行时候,onCreate-->onBind不会多次调用。

7:IO操作(断点续传原理)

RandomAccessFile:
支持对随即访问文件的读写。

8:跨进程通信方式

Content Provider
广播
Binder机制
Intent
文件读写

9:Android动画

逐帧动画(放电影,一帧一帧)
补间动画(控制平移,旋转,缩放等)
属性动画(升级版的补间动画,支持任意属性的变化)
SurfaceView实现动画。

10:invalidate()和postInvalidate()区别

invalidate会刷新整个View,只能在UI线程中调用。
postInvalidate,可以在非UI线程中去调用刷新UI,postInvalidate是通过handler将刷新事件通知到handlerMessage中执行invalidate的。

11:广播注册后不注销有什么问题?(内存泄漏)

广播在onReceiver方法中的参数Context,所以BroadCastReveiver中持有Activity,
而且广播不仅被Activity持有,可能还被ActivityManagerService等系统服务持有。
当Activity调用onDestroy方法时候,Activity并不能被回收,从而导致内存泄漏。
所以需要结束时候调用unregisterReceiver()。
onReceive()在10s内没有执行完会ANR。

12:屏幕适配方案

传统方案:
在res下建不同的values文件夹,创建不同的dimens。
今日头条:
通过反射适配系统的density(密度)值
密度=屏幕中1dp所占的多少像素点
限定符适配:
smallestwidth,通过宽高限定符,配置在manifast.xml中,程序启动时候读取xml设值。

13:如何监听activity是否后台切换到前台?不是在onReusme()中处理。

1:ActivityManager中处理:
getRunningTasks返回一个list集合,通过getClassName获取在前台的Activity。
2:OnResume中和onPause中记录一个变量。

14:FragmentPageAdater和FragmentStateAdapter区别?

FragmentPageAdater:fragment对象会一直在内存中,适用于少数的page情况。
FargmentStateAdapter:默认保存三个fragment,上一个当前的和下一个,一起对象的fragment会被销毁,但是在执行ondestroy时先调用onSaveInstenceState()来保存Fragment的状态,当fragment执行oncreate时候再把Bundle中的值取出来,比较适合多页面。

15:Servie&IntentService

Servie不能做耗时操作
IntentService继承自service,可以做后台下载等耗时操作。

16:Android常用性能调优

1:内存优化
GC释放对象包含(引用点):java栈中引用的对象;静态方法引用的对象;静态常量引用的对象;Native中JNI引用的对象,Thread。
内存溢出原因:瞬间申请了大量内存导致OOM;长期不能释放导致超过阈值导致OOM;小范围累积不能释放导致卡顿的OOM。
优化方式:利用profiler查看堆栈快照,具体查看波动内存是哪里导致的。
利用leakCanary工具查看生成的dump文件。
2:UI布局优化
UI卡顿的情况:View过渡绘制;Layout过于复杂,无法在16ms内完成渲染;View频繁出发measure,layout。
优化方式:开启GPU过渡绘制工具查看当前布局的绘制情况。
a:用RealtiveLayout代替LinearLayout
b:include,ViewStub,merge标签的使用
3:代码质量优化
a:使用as自带的unused resource清理无用资源
b:代码混淆
4:网络优化
a:用as自带的profiler进行网络监听。
ANR产生的原因:
Activity5s内无响应;广播10s无法处理完;服务service20s无法处理完。
网络请求中的图片可以用webp格式,质量相同的情况下减少流量。
优化方式:
一般多线程可以通过Asynctask处理,可以控制线程的顺序,执行完A后根据A返回的参数执行B线程。
5:耗电优化
a:需要进行网络请求时先判断当前的网络状态。
b:当有wifi和移动网络时候,优先选择wifi比移动网络耗电低。
c:减少后台任务的唤醒操作。
6:启动优化
a:冷启动,杀死进程后启动或程序第一次启动,耗时最久,因为要重新经历application初始化,启动ui线程,创建Activity,导入视图绘制视图等。
b:暖启动,当activity被销毁,但在内存中常驻时,启动减少了对象的初始化,布局加载等,启动时间短。
c:热启动,启动时间最短,比如按home键重新回到应用。
优化方式:Application创建过程尽量少,减少布局层次,启动页预加载等。

17:Java常用设计模式

1.单一职责原则:不要存在多于一个导致类变更的原因。
 通俗的说:即一个类只负责一项职责。
2.里氏替换原则:所有引用基类的地方必须能透明地使用其子类
 通俗的说:当使用继承时。类 B 继承类 A 时,除添加新的方法完成新增功能外,尽量不要重写父类 A 的方法,也尽量不要重载父类 A 的方法。如果子类
对这些非抽象方法任意修改,就会对整个继承体系造成破坏。子类可以扩展父类
的功能,但不能改变父类原有的功能。
3.依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依
赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
 通俗的说:在 java 中,抽象指的是接口或者抽象类,细节就是具体的实现类,
使用接口或者抽象类的目的 ,是制定好规范和契约,而不去涉及任何具体的操作,
把展现细节的任务交给他们的实现类去完成。依赖倒置原则的核心思想是面向接
口编程.
4.接口隔离原则:客户端不应该依赖它不需要的接口;一个类对
另一个类的依赖应该建立在最小的接口上。
通俗的说:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的
方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一
个很庞大的接口供所有依赖它的类去调用。
5.迪米特法则:一个对象应该对其他对象保持最少的了解
 通俗的说:尽量降低类与类之间的耦合。
6.开闭原则:一个软件实体如类、模块和函数应该对扩展开放,
对修改关闭。
 通俗的说:用抽象构建框架,用实现扩展细节。因为抽象灵活性好,适应性广,
只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节,我们用
从抽象派生的实现类来进行扩展,当软件需要发生变化时,我们只需要根据需求
重新派生一个实现类来扩展就可以了。
单例模式:某个类只能有一个实例,提供一个全局的访问点。避免对象的重复创建,提高资源的有效利用。(饿汉式)
代理模式:为其他对象提供一个代理,以便控制这个对象的访问。
工厂模式:定义一个创建对象的接口,让子类决定实例化哪个类。
观察者模式:对象间的一对多的依赖关系。

18:Android常用开发架构

1.mvc:数据、View、Activity,View 将操作反馈给 Activity,Activitiy 去获取数据,数
据通过观察者模式刷新给 View。循环依赖
  1.Activity 重,很难单元测试
  2.View 和 Model 耦合严重
2.mvp:数据、View、Presenter,View 将操作给 Presenter,Presenter 去获取数据,数
据获取好了返回给 Presenter,Presenter 去刷新 View。PV,PM 双向依赖
  1.接口爆炸
  2.Presenter 很重
3.mvvm:数据、View、ViewModel,View 将操作给 ViewModel,ViewModel 去获取数
据,数据和界面绑定了,数据更新界面更新。
  1.viewModel 的业务逻辑可以单独拿来测试
  2.一个 view 对应一个 viewModel 业务逻辑可以分离,不会出现全能类
  3.数据和界面绑定了,不用写垃圾代码,但是复用起来不舒服viewmodel不能持有上下文。

19:自定义控件

自定义View:继承View
基于现有组件:继承View的派生类
组合方式:自定义控件中包含了其他的组件
onMeasure:测量View的大小宽高
根据父View和MeasureSpec加上子view自己的LayoutParams,通过相应的转化规则而得到大小。
MeasureSpec代表宽度或高度的要求,每个MeasureSpec都包含了size和mode,MeasureSpec的模式主要分为:
(1)exactly:父容器已经测量出子view的大小,对应view的layoutparams的match_parent。
(2)at_most:父容器已经限制了view的大小,对应view的layoutParams的wrap_content。
onLayout:计算显示位置。
对View进行排版布局,要看父容器,也就是viewGroup。
onDraw:绘制背景,内容,绘制子view等

20:事件分发机制?

Activity/View处理事件分发的方法:
dispatchTouchEvent()
onTouchEvent()
ViewGroup事件分发处理:
dispatchTouchEvent()
onInterceptTouchEvent()
onTouchEvent()
在activity中当用户屏幕点击了后会先触发dispatchTouchEvent()如果view处理该事件则返回true,事件传递结束。如果返回false则调用onTouchEvent()处理该事件。
在ViewGroup中ViewGroup的dispatchTouchEvent先判断ViewGroup是否拦截Touch事件,如果拦截了则不向下传递直接调用TouchEvent处理事件,如果没有拦截则遍历所有子view找到点击的那个View把touch事件传递给它。viewgroup的onInterceptTouchEvent方法默认false,viewgroup事件分发都会调用它,一旦onInterceptTouchEvent返回true则表示拦截了事件,后续进行事件分发不再调用onInterceptTouchEvent方法。
总体优先级 setTouchListener > onTouchEvent > onClick > setClickListener 
注意:DOWN或UP就是一个事件,不是DOWM+MOVE+UP才是一个事件,加起来是我们称作一系列事件 
重写onTouchEvent时千万别删了super.onTouchEvent(event)——本人手贱,为此付出过惨痛代价。

getParent().requestDisallowInterceptTouchEvent(true):父控件不会拦截事件
getParent().requestDisallowInterceptTouchEvent(false):父控件会根据自身的判断来决定是否拦截

21:如何计算View大小&如何对子控件进行布局

计算View大小:
view在测量过程和activity生命周期不是同步的,所以在onCreate/onStart/onResume获取view宽高是0。
在onWindowFocusChanged里面获取。(getMeasuredWidth(),getMesureHeight())
子View布局:
可以通过addView方式,infalte布局

22:RecyclerView优缺点

RecyclerView卡顿情况:布局复杂,多层嵌套,设置setNestedScrollingEnable(false);含视频,滑动到item时加载,item滑出界面释放资源;含图片,图片懒加载(默认图占位)
RecyclerView4级缓存:
第一级ChangedScrap匹配position或者id获取holder缓存。可见缓存 x(无限制) ArrayList 用于屏幕中可见View的回收和复用
第二级从CachedViews 缓存列表 2 ArrayList 用于移除屏幕的View的回收和复用,不会清空数据
第三级ViewCacheExtension自定义缓存  x       一般不使用这个
第四级通过RecyclerViewPool   缓存池 5   SparseArray 用于移除屏幕的View的回收和复用,会将ViewHolder的数据重置

23:Http&Socket编程,TCP/IP原理

TCP 建立连接要进行 3 次握手,而断开连接要进行 4 次
1.基于连接与无连接;
2.对系统资源的要求(TCP 较多,UDP 少);
3.UDP 程序结构较简单;
4.流模式与数据报模式 ;
5.TCP 保证数据正确性,UDP 可能丢包,TCP 保证数据顺序,UDP 不
保证。
三次握手:
A:你好我是A。
B:你好A,我是B。
A:你好B
四次挥手:
A:B啊,我不想玩了。
B:哦,你不想玩了,我知道了。(这个时候,只是A不想玩了,A不再发送数据,但B可能有未完成的数据,所以需要等待)
B:A啊,好吧,我也不玩了,拜拜。
A:好的,拜拜。
Http和Https区别:
https是具有安全性的ssl加密身份认证的传输协议,需要到ca申请证书。端口443。
http是超文本传输协议,信息是明文传输。端口是80,是无状态连接。

24:图片优化

bitmap占用内存=图片长*图片宽*一个像素点占用的字节数。
bitmap.config中argb_4444和argb_8888代表一个像素点占用多少位。
图片压缩方式:
a:质量压缩,bitmap.compress不会改变图片所在内存大小,改变的是图片所占磁盘大小。
b:设置图片格式,png无损,jpeg有损,webp有损和无损,体积更小。
c:采样率压缩inSampleSize宽高压缩。
d:缩放压缩,减少图片的像素来降低磁盘和内存大小,可用于缩略图。
e:JNI调用JPEG库。(图片引擎采用skia,去掉了压缩算法导致)
Glide:
用法是with().load().into()。用法和pissco一致,是pissco的升级版。
SupportRequestManagerFragment是一致存在于栈中的fragment。不管上下文是用activity还是application的基本不会造成OOM,LruCache通过键值对形式存储bitmap,通过linkedHashmap保证插入顺序,Gilde可以从LruCache获取图片,从弱引用中获取缓存,从网络请求中获取图片。

25:Handle机制(postDelay),postDelay执行时候是什么时候把message添加Queue中的?

1.MessageQueue:读取会自动删除消息,单链表维护,在插入和删除上有优势。在
其 next()中会无限循环,不断判断是否有消息,有就返回这条消息并移除。
2.Looper:Looper 创建的时候会创建一个 MessageQueue,调用 loop()方法的时候消
息循环开始,loop()也是一个死循环,会不断调用 messageQueue 的 next(),当有消
息就处理,否则阻塞在 messageQueue 的 next()中。当 Looper 的 quit()被调用的时候
会调用 messageQueue 的 quit(),此时 next()会返回 null,然后 loop()方法也跟着退出。
3.Handler:在主线程构造一个 Handler,然后在其他线程调用 sendMessage(),此时主
线程的 MessageQueue 中会插入一条 message,然后被 Looper 使用。
4.系统的主线程在 ActivityThread 的 main()为入口开启主线程,其中定义了内部类
Activity.H 定义了一系列消息类型,包含四大组件的启动停止。
5.MessageQueue 和 Looper 是一对一关系,Handler 和 Looper 是多对一
https://www.jianshu.com/p/c7b87f8ed0c7(问题1)
https://blog.csdn.net/cmyperson/article/details/98970586  (问题2)
总的来说,一个线程中可以创建许多 Handler,然而这些 Handler 对象持有的 Looer、MessageQueue 引用指向的都是相同的对象(线程中唯一的的);这样一来,在其他线程中用这些 Handler 对象去发送消息(发出的消息持有发消息的 Handler 对象的引用),发出去的消息最终都是被放到了创建 Handler 线程中对应那个 MessageQueue 中
而创建 Handler 的线程中通过 Looper.loop 死循环不断地从消息队列中取出消息,这样便实现了线程之间的通信;由于对消息的入队和出队操作都是加了锁的,因此便保证了通信的安全性

为什么loop死循环不会卡死:
线程是一段可执行的代码,当执行完后线程的生命周期便终止,线程退出。而主线程我们希望一直运行下去,死循环便能保证不会被退出。真正导致卡死主线程的操作是在回调onCreate/onStart/onResume等操作时间过长导致ANR,looper.loop本身不会导致应用卡死。

26:EventBus原理

register注册,post发送消息。
EventBus解耦其实是使用了反射,在register时候会通过反射将信息记录下来。
观察者模式:通过subscrible订阅消息,Observer观察者。
源码解析:

EventBus发送事件原理是,subscriptionsByEventType通过事件类型EventType.class获取到订阅方法包装类List集合。
然后通过postToSubscription方法,在方法中匹配发送事件的线程模式threadMode,
例如匹配到主线程时,会直接通过反射调用订阅方法subscription.subscriberMethod.method.invoke(subscription.subscriber, event)
实现事件的发布-订阅执行。
EventBus事件的解注册
EventBus解注册原理则是清空typesBySubscriber和subscriptionsByEventType。
EventBus发送粘性事件
EventBus在处理粘性事件的原理,先通过postSticky方法将键值对(key=事件类型class,value=事件实例)存入字典stickyEvents中。
而真实的执行粘性事件的订阅方法,则是通过EventBus.register()来实现的。
发布事件的订阅类在注册时如果判断得知该事件属于粘性事件,那么就会通过循环遍历字典stickyEvents,
以执行订阅方法的执行~ 【在执行订阅方法进入方法postToSubscription时,跟非粘性事件处理就一致了】

27:jvm模型,java内存模型,垃圾回收机制,垃圾回收哪个区域,对象在内存哪个区域。

jvm内存模型:方法区,堆,程序计数器,本地方法栈。
垃圾回收机制执行:
1:年老代被写满
2:持久带被写满
3:System.gc()被显示调用
4:上一次gc之后heap的分配策略动态变化。
对象在内存中的堆里面。JVM所有对象都是在堆中分配内存空间,栈只是保存局部变量和临时变量,如果是对象只保存引用。

28:Parcelable和Serializable区别

Parcelable:
Android提供的,代码多,速度高
Parcelable中的三大过程介绍(序列化,反序列化,描述)
什么是序列化

序列化,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。

Parcelable和Serializable的区别和比较
Parcelable和Serializable都是实现序列化并且都可以用于Intent间传递数据,Serializable是Java的实现方式,可能会频繁的IO操作,所以消耗比较大,但是实现方式简单 Parcelable是Android提供的方式,效率比较高,但是实现起来复杂一些 , 二者的选取规则是:内存序列化上选择Parcelable, 存储到设备或者网络传输上选择Serializable(当然Parcelable也可以但是稍显复杂)

选择序列化方法的原则

1)在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。

2)Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。

3)Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable 。
Serializable:
java自带的,代码量少,速度低

29:ContentProvider实现原理,如何进行批量操作?

ContentProvider可以作为数据访问接口之外,还可以在不同应用程序之间进行数据共享。因为Binder传递数据有大小限制,所以用ContentProvider来处理比较高效。
ContentProvider必须在Manifest中声明。访问provider需要知道它的URI,所以把provider的URI作为公共常量出来。
ContentProviderOperation:
可以批量更新,插入,删除数据。
ContentProviderOperation.Builder:
newInsert 插入操作
newUpdate 更新操作
newDelete 删除操作
newAssertQuery 查询没有符合条件的数据

30:Android动态权限?各版本差异性?

5.0
沉浸式状态栏
6.0
动态权限,httpclient删除。
7.0 8.0 9.0
更注重耗电和后台优化。将bitmap中的像素点放在native层等。
10.0
不再需要任何权限即可在外部存储设备中访问和保存自己的文件,谷歌官方推荐应用在沙盒内存储文件的地址为Context.getExternalFilesDir()下的文件夹
11
安装app动态权限
12
隐私,存储,权限优化
13
优化蓝牙、音频,为大屏设备和平板做优化

31:SurfaceView和View

SurfaceView是从View基类中派生出来的显示类,他和View的区别有:

View需要在UI线程对画面进行刷新,而SurfaceView可在子线程进行页面的刷新,View适用于主动更新的情况,View频繁刷新会阻塞主线程,导致界面卡顿

SurfaceView在底层已实现双缓冲机制,而View没有,因此SurfaceView更适用于被动更新,需要频繁刷新、刷新时数据处理量很大的页面

32:AsyncTask异步任务

更新UI操作必须在主线程进行,下载图片,文件,网络请求需要在子线程进行,可以用handler机制。
Asynctask:
对线程和Handler进行了封装,可以直接对UI进行更新操作。
1:onPreExecute():执行在后台下载操作之前,与现行在主线程中。
2:doInBackground:核心方法,运行在子线程中
3:onPostExecute():后台下载完成后回调,运行在主线程中。
4:onProgressUpdate():在下载操作中调用publicProgress用于更新下载进度,运行在主线程中。
别再傻傻得认为AsyncTask只可以在主线程中创建实例和调用execute方法

总结一下就是,可以在子线程中创建AsyncTask实例,并执行execute.  注意在哪个线程执行AsyncTask的execute(),onPreExecute会运行在执行在哪个线程中,onPostExecute方法还是会执行在主线程中,doInBackground方法会执行在AsyncTask创建的线程中。

这个问题的核心是, Handler实例化需要用到线程的Looper,而我自己新建的Thread并没有调用Looper.prepare(),所以新开的线程Looper肯定为空,怎么会运行正常呢?

因为AsyncTask源码里Handler持有的主线程的Looper

sHandler = new InternalHandler(Looper.getMainLooper());

33:Android强软弱虚引用的应用场景

    private String a="test";
1:强引用,定义的常量属于强引用,内存不足OOM时候也不会去回收该对象。
2:软引用,内存足够就不回收,不足是进行回收
3:弱引用,比软引用生命周期更短,只要被垃圾回收器线程发现,就会被回收。
4:虚引用,任何时候都可能会回收。

34:混淆的优点和使用场景

nimifyEnabled true开启混淆
优点:
1:增加对apk反编译的困难性
2:减少apk体积
注意:
1:避免混淆Android基本组件,避免混淆get/set方法,避免混淆枚举类,序列化类等。

35:java反射

反射:
对于任意一个类,都能得到它的属性和方法。通过setAccessible(true),可以得到私有属性

动态代理

36:android安全性

安全性,可以通过混淆代码形式。
防止抓包,可以通过指纹码或者公钥证书,配合okhttp里面的sslFactory做防止中间人攻击。
AES
1、AES加密是一种对称式加密,即加密和解密所需秘钥是相同的,你可以生成一组秘钥,然后利用该秘钥加密数据,然后发给合作伙伴,同时也需要把秘钥发送给合作伙伴,这样你的合作伙伴才能解密。
相比RSA加密来说,好处是不会限制加密字符串的长度

RES
2、RSA加密,是一种非对称式加密.

加壳原理(爱加密):


20190506114334.png

37:SharedPrefrence原理,能否夸进程,如何实现?

不能跨进程,默认模式mode_private,其他支持跨境成模式已经被废弃,可以用contentProvider跨进程通信。
SharedPrefrence是基于xml实现的一种数据持久化手段。
SharedPrefrence不支持多进程。
SharedPrefrence的commit与apply一个是同步一个是异步。
SharedPrefrence不要存储过大数据。
SharedPreferences 也有其自身缺陷,比如其职能存储 boolean,int,float,long 和 String 五种简单的数据类

38:webView加载h5的优化,webView内存泄漏是否了解。

页面加载速度优化:
1:选择合适的浏览器缓存机制
2:常用资源预加载,常用JS本地化及延迟加载,放在本地加载。
导致内存泄漏:
系统在attachTowindow和detachFromWindow处进行注册和反注册component callback导致。
封装自己的webView,不再xml中声明,在代码中直接new WebView,传入Application的上下文防止acitivty被滥用。
WebView webView =  new WebView(getContext().getApplicationContext());
webFrameLayout.addView(webView, 0);

39:插件化

腾讯的tinker和阿里的andfix。
本地热修复
1:修改好代码后编译后生成.class文件
2:用sdk中提供的dx工具将需要替换的.class文件转化成dex。
3:将.dex文件放入磁盘,创建一个DexClassLoader,通过PathClassLoader遍历出需要修改的dexElements,设值新的参数。
4:启动时候重新loadFixdex()

问题:
模块间耦合度过大沟通成本高,app方法数超过65535等问题
解决:
将一个apk拆分成多个小apk,每个小apk能单独运行。业务模块基本完全解耦。
1:dex加载原理
dexClassLoader:可以加载文件系统上的jar、dex、apk。
PathClassLoader:可以加载/data/app目录下的apk,只能加载已安装的apk。
PathClassLoader和DexClassLoader都是Android提供给我们的ClassLoader,都能加载dex
网上很多文章都说PathClassLoader只能加载已经被系统安装过的apk,DexClassLoader无此限制,然而我自己测试是都可以
根据art源码来看,两者都继承自BaseDexClassLoader,最终都会创建一个DexFile,不同点是一个关键的参数:optimizedDirectory,PathClassLoader为null,DexClassLoader则使用传递进来的
然后会根据optimizedDirectory判断对应的oat文件是否已经生成(null则使用/data/dalvik-cache/),如果有且该oat对应的dex正确则直接加载,否则触发dex2oat(就是这家伙耗了我们宝贵的时间!!),成功则用生成的oat,失败则走解释执行
ps:貌似Q版做了优化,不会再卡死在dex2oat里了
根据加载外部dex的实验,DexClassLoader会触发dex2oat,而PathClassLoader不会

40:线程池

wait:线程睡眠时,释放对象锁,其他线程可以访问。
sleep:线程睡眠时,仍然占有该锁,其他线程无法访问。
线程池是用来存放线程的池子,里面的线程可以被重复利用,不浪费。
创建线程池:用Executors 。
singleThreadPool单一线程
fixedThreadPool固定数量的线程池
scheduleThreadPool周期任务
cacheThreadPool想建几个就建几个

线程池

41:Glide源码分析

Glide源码分析

42:okhttp源码分析

okhttp源码分析

43:LeakCanary源码分析

LeakCanary源码分析

44:RxJava操作符

RxJava操作符

45:HashMap原理

HashMap原理

46:framework层AMS、PMS、WMS

activity启动过程:
1:通过Launcher启动Activity或者startActivity来启动,都是通过Binder进程间通信进入到ActivityManagerService进程中,并且调用ActivityManagerService.startActivity接口;
2:ActivityManagerService调用ActivityStack.startActivityMayWait来做准备要启动activity的相关信息;
3:ActivityStack通知Application Thread要进行Activity启动调度了。
4:Application Thread不执行真正的启动操作,它通过调用ActivityManagerService.activityPaused接口进入到ActivityManagerService进程中,看看是否需要创建新的进程来启动Activity;
5:如果是通过Launcher的情况,ActivityManagerService会调用startProcessLocked来创建新的进程,对于startActivity来启动的情况,这一步不需要执行,直接在原来Activity所在的进程中启动。
6:ActivityManagerService调用Application Thread.scheduleLaunchActivity接口,通知相应的进程启动Activity;
7:Application Thread把这个启动Activity的操作转发给ActivityThread,ActivityThread通过ClassLoader导入相应的Activity类,然后启动起来了。
安装过程:
复制APK安装包到/data/app目录下,
解压并扫描安装包,
向资源管理器注入APK资源,
解析manifest文件,
在data/data目录下创建应用数据目录,
针对dalvik环境优化dex文件,
保存到dalvik-cache目录,
将manifest文件解析出的组件权限注册到packgeManagerService并发送广播。

framework层AMS、PMS、WMS

47:binder机制原理

binder机制原理

48:flutter原理优势,kotlin协程

flutter都是write once,run everywhere。
Flutter,基于Dart语言,基于独有的图形引擎Skia,不需要要桥接,不基于webkit,解决比较彻底。
摒弃JSBridge,Flutter是直接编译成本地代码,用skia渲染展示。热重载hot reload,jsBridge需要build打包。flutter不支持热更新,适合整体app开发。

kotlin协程

49:冒泡排序&手写单例

冒泡:
 public static void main(String[] arg) {
        int arry[] = {2, 3, 1, 4};
        for (int i = 0; i < arry.length; i++) {
            boolean isOver = false;
            for (int j = 1; j < arry.length - i; j++) {
                if (arry[j - 1] > arry[j]) {
                    int temp = arry[j - 1];
                    arry[j - 1] = arry[j];
                    arry[j] = temp;
                    isOver = true;
                }
            }
            if (!isOver) {
                break;
            }
        }
        for (int num : arry) {
            System.out.println(num);
        }
    }
单例:(饿汉式)
 public class Singleton {
    // 直接创建对象
    public static Singleton instance = new Singleton();
    // 私有化构造函数
    private Singleton() {
    }
    // 返回对象实例
    public static Singleton getInstance() {
    return instance;
      }
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容