Android常见问题简单总结

纵然是瞬间 提交于 2019-12-18 10:46:52

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

一、https,如何避免Client和Server中间劫持?

客户端是如何校验证书的呢?这里发生在第三步,客户端接收到服务端的证书,里面主要包含公钥和签名。根据证书上的签发机构去浏览器内置的CA签发证书里面找到保存的证书公钥,然后用这个公钥解开签名,得到数字摘要(digest,证书内容的hash值),和服务端的证书进行对比验证。 所以https可以被拦截,但是不能被劫持。

二、插件化hook IActivityManager采用什么代理方式?为什么?

** hook IActivityManager是采用动态代理的方式。因为它并没有一个具体的实现类,而是使用代理的方式。

三、找车App白屏问题,内存泄漏

找车app是汽车之家主app里面很重要的一个模块,在无网络的情况下也需要能够展示默认数据。这些默认数据会在app第一次启动的时候需要序列化到数据库里面,由于在主线程做的会有一会儿白屏。
需要把这个序列化放在后端做处理,这里我用AsyncTask,在后端去做处理。但是这里如果匿名内部类会有持有Activity的引用,这样如果退出Activity后台操作还没有处理完成,那么activity就没法被回收,会有内存泄漏问题。
这里使用静态内部类来解决这个问题,但是如果想要在onPostExecute里面去去处理调用activity的成员变量就变得不可能了,那么怎么办?这里用到弱引用,用弱引用保存当前Activity引用,那么久可以通过get获取到Activity了。

四、HashMap的数据结构

(1)HashMap是链表的数组,是Entry的集合,Entry是队列也是健值对。在Java8的时候链表长度大于8则采用红黑树。

五、为什么HashMap线程不安全?

  1. 因为HashMap在put的时候有可能两个线程put一个hashCode相同的key,这个时候在相同的bucket上,A线程获取了链表的头节点;正好A的时间片用完了,切换到了B,B在这个节点头上挂了一个元素,在切换成A线程,A也直接把B给替换了,这样B线程的元素就丢失了。

  2. resize会导致死循环链表。 综合上面两点,可以说明HashMap是线程不安全的。 ConcurrentHashMap在Java1.7采用的架构是segment+hashEntry+ReentrantLock。而在Java1.8中采用的是Node + CAS + Synchronized的结构。为什么Java1.8的get操作不需要枷锁都能保证数据安全呢?那是因为在Java1.8的Node节点和value是volatile修饰,保证了线程的可见性。

  3. 既然volatile修饰数组对get操作没有效果那加在数组上的volatile的目的是什么呢?
    其实就是为了使得Node数组在扩容的时候对其他线程具有可见性而加的volatile

  4. 在1.8中ConcurrentHashMap的get操作全程不需要加锁,这也是它比其他并发集合比如hashtable、用Collections.synchronizedMap()包装的hashmap;安全效率高的原因之一。

  5. get操作全程不需要加锁是因为Node的成员val是用volatile修饰的和数组用volatile修饰没有关系。 数组用volatile修饰主要是保证在数组扩容的时候保证可见性。

六、AsyncTask可以设置线程池吗?

可以的,通过excuteOnExecutor(Executor exec, Params... params)来设置线程

七、线程如何同步?

join、wait/notify

八、有哪些跨进城的方式,底层是binder的算一种,能说说binder吗?

1、Intent跨进程访问别的Activity
2、ContentProvider的底层是采用 Android中的Binder机制
3、广播(Broadcast)
4、AIDL服务
5、文件
6、socket
  • Android Jetpack 一个有生命周期的可观察的数据持有者。
    LiveData如何实现数据可观察: 其实LiveData的原理还是订阅。从observe方法开始,注册owner,和Observer,把owner封装成LifecycleBoundObserver包装类,让这个监听者安全,即inactive的时候不回调。然后把这个包装类put进去课迭代的Map中。最后,更改数据都会走到setValue();这个方法把map里面的观察者遍历出来,挨个判断与之关联的owner是不是mActive,是就调用onChanged方法。

MutableLiveData 数据持有者的最简单的实现类
MediatorLiveData
可以合并多个Livedata的数据持有者
Transformations.map()
可以对数据流做一些链式操作的的方法,入加入一些数据
Transformations.switchMap() 可以根据条件选择监听那个数据持有者(LiveData) 看源码可知道,LiveData可被监听数据的变化的原理就是订阅。 里面维护着可以迭代的健值对数组

Lifecycle 和 LifecycleObserver ,让我们做MVP的时候Presenter层可以完美和View分离开来。 Lifecycle源码解读 ViewModel是通过ViewModelFactory反射创建的,同时保存在ViewModelStore里面。

  • 单例模式有几种写法?

  • AsyncTask的优缺点 优点:简单、好用,封装性好 缺点: 1、容易内存泄漏
    2、AsyncTask是默认(execute())在线程池串行执行的,并没有完全发挥线程池的作用。可以通过setDefaultExcutor()设置自己的线程池,也可以通过execueOnExcutor()设置自己的线程池,达到并行的目的。
    3、很多开发者会认为一个在Activity中创建的AsyncTask会随着Activity的销毁而销毁,事实并不是,没有及时取消AsyncTask所带来的问题,AsyncTask.cancel()进行取消。

防止handler带来的内存泄漏: 1、弱引用(没有第二种好,因为Google说它的虚拟机不擅长处理非强引用的对象)
2、在onDestroy 移除消息
handler.removeMessages();
handler.removeCallbacksAndMessages();

  • Android系统架构 应用层 //应用
    Framework层 //应用框架层 ContentProvider ViewSystem 各大Manager
    Library层 Native C/C++ 一些三方库比如SQLite, WebKit OpenGL Android Runtime
    HAL层 硬件层BlueTooth Audio Camera Sensors
    Linux内核层 Linux kernel (BlueTooth Audio Camera)的驱动

  • 如果开启多个页面,如何避免OOM?(目前还不知道,知道的请告知我) Okhttp设置支持https、封装缓存配置,封装get、post请求
    Okhttp的缓存设置:
    Okhttp是通过Cache对象来设置缓存路径和缓存大小的。之后通过读取后端数据的header的Cache-Control配置来决定多久更新数据。如果后弹没有设置可以自己配置缓存的CacheInterceptor。实现intercept方法,在里面给Response添加Cache-Control配置。当然个性化配置Okhttp还提供了CacheConCrol来个性化配置缓存过期时间。

  • 如何计算一张图片大小,Lrucache 加载一张本地资源图片,那么它占用的内存 = 一、图像占用空间的大小计算: 大小=分辨率位深/8 (位深: 一个像素所占的内存。) 分辨率=宽高(如:1024768,640480) 位深:如24位,16位,8位 /8计算的是字节数。

例如:
一幅图像分辨率:1024768,24位,则其大小计算如下: 大小=1024768×24/8=2359296byte=2304KB

  • SQLite、资源保存性能、总结有深度的技术点 SQLite性能优化: 1、使用Sql语句预编译,即sql语句生成SQLiteStatement,需要传的参数使用?占坑。 这样不用每次的编译语句,变化的只是参数。

2、显示的使用事务优化写操作,频繁的开闭IO是很耗性能的,用事务来提交多条语句,会先把数据缓存到系统中,然后再一次性提交更改到数据文件,此时数据文件的IO只需要开闭一次。大大提高性能。

3、使用索引提高查询效率。

4、查询尽量只查询需要的信息

5、合理调整ContentValues容量,减少扩容次数。

6、提前获取索引,cursor.getColumnIndex放在循环外

  • Android虚拟机Dalvik和Art用什么算法来进行垃圾回收?

  • 1、如何实现进程间通信的总线订阅模式?

  • 2、自定义控件的过程

  • 举例自定义GroupView:

  • 1、重写onMeasure(),在方法里面迭代子View,然后调用measureChild,测量每个字View的长度和宽度,计算。然后根据父View传来的建议宽高,和mode决定是否选择建议宽高还是计算的,AT_MOST酒选择我们计算的否则选择建议的,就是match_parent的意思。

  • 2、重写onLayout,迭代子View,根据measure的宽高,调用child的layout来布局子View。

  • 3、如果要在布局里面设置可以创建attr文件,在里面创建属性,然后在构造方法的attrs入餐获取用户传来的参数来做计算。

自定义View: 重写onDraw()方法,不要在里面做耗时长的操作,减少创建对象。不要在里面创建bitmap等大的对象在构造方法创建。

  • React native 和 原生的相互通信RN->native、native->RN

(1)以引用模块的方式调用原声方法RN->native: 自定义module类继承自ReactContextBaseJavaModule,重写getName,返回react层的调用名。 创建一个方法,方法里面使用@ReactMoudle,方法里面可以传Callback callback(或者Promise promise),来返回数据给RN。 在RN层使用NativeModules调用相应模块。示例: NativeModus.[ToastExample中getName的返回值].[ToastExample中的方法]来调用原生的方法

(2)原生调用RN native->RN:

reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName,params); 再原生可以通过 DeviceEventEmitter.addListener('EventName',(msg)=>{});来注册监听。

6、requestLayout、invalidate、postInvalidate

一般来说,如果View确定自身不再适合当前区域,比如说它的LayoutParams发生了改变,需要父布局对其进行重新测量、布局、绘制这三个流程,往往使用requestLayout。而invalidate则是刷新当前View,使当前View进行重绘,不会进行测量、布局流程,因此如果View只需要重绘而不需要测量,布局的时候,使用invalidate方法往往比requestLayout方法更高效。
postInvalidate与invalidate方法的作用是一样的,都是使View树重绘,但两者的使用条件不同,postInvalidate是在非UI线程中调用,invalidate则是在UI线程中调用。

接下来我们分析postInvalidate方法的原理。

  • 1、另一个进程的Service被杀死了,怎么知道? onStartCommand() 返回START_STICKY可以重启一次Service。

  • 2、如何减少读取磁盘的次数

  • 3、binder的原理,为什么只需要拷贝一次。弄懂、用binder通信一次。

  • 4、用什么取代SharedPreferences跨进城同步数据?
    SharedPreferences底层是通过读写XML来实现的,多进程并发显然是可能出问题的,所以SharedPreferences不支持多进程。可以用ContentProvider替代。通过ContentProvider对于数据的操作都是同步的,不过contentResolver.notifyChange通知是异步的。所以ContentProvider可以替代SharedPreferences。

5、* 构建者模式的好处是什么?(对比构造方法) 目的: 为了将构建对象的过程和构建部件解耦开来,使得构建过程和部件的表示隔离开来。 定义: 讲一个复杂的对象的构建和他的表示分离开来,使得一个形同的构建能够=创建不同的表示。

1、动态代理和静态代理的区别 静态代理类:由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 动态代理类:在程序运行时,运用反射机制动态创建而成。

  • 3、为什么 Activity 间传递对象需要序列化?
    Intent在启动其他组件时,会离开当前应用程序进程,进入ActivityManagerService进程(intent.prepareToLeaveProcess())
    这也就意味着,Intent所携带的数据要能够在不同进程间传输。
    首先我们知道,Android是基于Linux系统,不同进程之间的java对象是无法传输,
    所以我们此处要对对象进行序列化,从而实现对象在 应用程序进程 和 ActivityManagerService进程 之间传输。

送给自己的话:

很多东西不是会用就可以 了的,你要深入去解剖它的原理,你需要了解的不是一样东西,而是一类东西。

最后

今年金九银十我花一个月的时间收录整理了一套知识体系,如果有想法深入的系统化的去学习的,可以点击传送门,我会把我收录整理的资料都送给大家,帮助大家更快的进阶。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!