1.如何开启多进程?应用是否可以开启N个进程?
实现多进程可以通过设置service、broadcast、activity的标签android:process来实现。
多进程首先会有多个Application,数据会被初始化多次,其次进程间通信比较麻烦,还有一个就是每个进程有单独的虚拟机,多个进程就会比较占内存。
2.Activity的启动模式、任务栈以及使用场景?
standard:标准模式 每次启动一个Activity都会重新创建新的实例,不管这个实例是否已经存在。
singleTop:栈顶复用模式。如果新Activity位于栈顶,那么不会被重新创建,同时会回调onNewIntent方法。
singleTask:栈内复用模式。Activity只要在栈中存在,就不会重新创建实例,并回调onNewIntent方法。此模式默认具有clearTop效果。
singleInstance:单实例模式。这是一种加强的singleTask模式,具有singleTask的所有特性。只能单独位于一个任务栈中。
3Volley能否进行数据量很大的请求?
Volley特别适合数据量小,通信量大的客户端。
4Volley能否下载电影以及加载大图片?
#Volley的网络请求线程池默认大小为4。意味着可以并发进行4个请求,大于4个,会排在队列中。
Request#getBody() 方法返回byte[]类型,作为 Http.POST 和 Http.PUT body 中的数据。这就意味着需要把用 http 传输的数据一股脑读取到内存中。如果文件过大,内存…
考虑这样一个场景:
你同时上传4个文件,这四个文件都很大,这时候你的内存占用就很高,很容易oom。
这时候,你发网络请求,调用普通api。
所有的网络线程都被上传文件的任务占满了,你的网络请求只有在文件上传完毕后才能得到执行。体验就是,很慢!
所以Volley适合数据量小,频率快的请求。
5.final修饰一个对象,能否调用对象修改属性的方法
可以修改属性,地址不能改变
6.子线程中如何使用Handler
调用looper.prepare looper.loop
7.注解如何获取,反射为何耗性能
java反射是要解析字节码,将内存中的对象进行解析,包括了一些动态类型,所以JVM无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多!
8.Java的GC机制,分代回收策略
http://icyfenix.iteye.com/blog/715301
将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor[1]。
当回收时,将Eden和Survivor中还存活着的对象一次性地复制到另外一块Survivor空间上,最
后清理掉Eden和刚才用过的Survivor空间。 HotSpot虚拟机默认Eden和Survivor的大小比例是
8:1,也就是每次新生代中可用内存空间为整个新生代容量的90%(80%+10%),只有10%
的内存会被“浪费”。 当然,98%的对象可回收只是一般场景下的数据,我们没有办法保证每
次回收都只有不多于10%的对象存活,当Survivor空间不够用时,需要依赖其他内存(这里
指老年代)进行分配担保(Handle Promotion)。
9 ConcurrentHashMap的原理,分的段数是多少?
http://www.importnew.com/22007.html
ConcurrentHashMap采用了分段锁的设计,只有在同一个分段内才存在竞态关系,不同的分段锁之间没有锁竞争。相比于对整个Map加锁的设计,分段锁大大的提高了高并发环境下的处理能力。
并发度可以理解为程序运行时能够同时更新ConccurentHashMap且不产生锁竞争的最大线程数,实际上就是ConcurrentHashMap中的分段锁个数,即Segment[]的数组长度。ConcurrentHashMap默认的并发度为16,但用户也可以在构造函数中设置并发度。当用户设置并发度时,ConcurrentHashMap会使用大于等于该值的最小2幂指数作为实际并发度(假如用户设置并发度为17,实际并发度则为32)。运行时通过将key的高n位(n = 32 – segmentShift)和并发度减1(segmentMask)做位与运算定位到所在的Segment。segmentShift与segmentMask都是在构造过程中根据concurrency level被相应的计算出来。如果并发度设置的过小,会带来严重的锁竞争问题;如果并发度设置的过大,原本位于同一个Segment内的访问会扩散到不同的Segment中,CPU cache命中率会下降,从而引起程序性能下降。(文档的说法是根据你并发的线程数量决定,太多会导性能降低)
10Android中如何查看一个对象的回收情况
https://blog.csdn.net/u012332679/article/details/57489179
Reference和ReferenceQueue
11APP的启动流程
1在LAUNCH界面,点击一个app的图标之后,会调用startActivity来启动对应的Activity。
2通过Binder远程通知AMS启动新的Activity。
3AMS进行一系列的权限判断,创建ActivityRecord记录信息,Activity栈处理….等等一系列处理,最后会调用到startSpecificActivityLocked方法中。
4startSpecificActivityLocked方法中会进行判断,在进程没有启动的情况下,会调用startProcessLocked=>startProcessLocked=>Process.start()来启动一个进程。
5Process.start()是一个静态方法,他作为客户端会通过sockt与zygote进行通讯,Zygote作为服务端。Zygote通过JNI调用native方法fork一个它的子进程,并返回进程的pid。
6调用zygoteConnection的handleChildProc方法。关闭socoket,进行一些进程的设置,默认未捕捉异常的处理方法、时区的设置、重置log的配置,binder线程池和线程创建….
7通过反射来调用到ActivityThread的main方法,main方法中创建主线程Looper、并调用attach方法。通过Binder通讯调用AMS的attachApplicationLocked()方法,启动主线程Looper循环。
8跨进程调用ApplicationThread的bindApplication方法,通过Handler发送消息调用到ActivityThread的handleBindApplication方法,在这个方法中会完成创建Context的实现类ContextImpl对象、初始化Intrumentation对象、创建Application对象、装载Provider、调用Application的onCreate方法。
9调用到realStartActivityLocked,然后跨进程调用到applicationThread的scheduleLaunchActivity方法,scheduleLaunchActivity就会正真创建Activity。
十二Java为何引入泛型,泛型边界
泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
泛型边界:类型实参只准传入某种类型的父类或某种类型的子类。
十三ArrayMap跟SparseArray在HashMap上面的改进
android.util.ArrayMap存储结构是由int[] mHashes和Object[] mArray两个数据组成,mHashes保存key的hashCode,mArray以键值对形式保存key和value。 ArrayMap取数据时通过二分法查找index,获取相应value。
SparseArray是android v4包里提供的工具类,在某些场景下可以用来替代Hashmap进行对象的存储,其内部实现了一个矩阵压缩算法,可以进行矩阵压缩,大大减少了存储空间,节约内存。此外它的查找算法是二分法,提高了查找的效率。
SparseArray的value可以是任意类型,但key只能是int、long类型,所以key是int、long场景下,SparseArray比Hashmap更合适。
十四Java的四种引用及使用场景
在Java语言中,除了基本数据类型外,其他的都是指向各类对象的对象引用;Java中根据其生命周期的长短,将引用分为4类。
1 强引用
特点:我们平常典型编码Object obj = new Object()中的obj就是强引用。通过关键字new创建的对象所关联的引用就是强引用。 当JVM内存空间不足,JVM宁愿抛出OutOfMemoryError运行时错误(OOM),使程序异常终止,也不会靠随意回收具有强引用的“存活”对象来解决内存不足的问题。对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null,就是可以被垃圾收集的了,具体回收时机还是要看垃圾收集策略。
2 软引用
特点:软引用通过SoftReference类实现。 软引用的生命周期比强引用短一些。只有当 JVM 认为内存不足时,才会去试图回收软引用指向的对象:即JVM 会确保在抛出 OutOfMemoryError 之前,清理软引用指向的对象。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。后续,我们可以调用ReferenceQueue的poll()方法来检查是否有它所关心的对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。
应用场景:软引用通常用来实现内存敏感的缓存。如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时,不会耗尽内存。
3 弱引用
弱引用通过WeakReference类实现。 弱引用的生命周期比软引用短。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。由于垃圾回收器是一个优先级很低的线程,因此不一定会很快回收弱引用的对象。弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
应用场景:弱应用同样可用于内存敏感的缓存。
4 虚引用
特点:虚引用也叫幻象引用,通过PhantomReference类来实现。无法通过虚引用访问对象的任何属性或函数。幻象引用仅仅是提供了一种确保对象被 finalize 以后,做某些事情的机制。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
ReferenceQueue queue = new ReferenceQueue ();
PhantomReference pr = new PhantomReference (object, queue);
程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取一些程序行动。
应用场景:可用来跟踪对象被垃圾回收器回收的活动,当一个虚引用关联的对象被垃圾收集器回收之前会收到一条系统通知。
十五Webview性能优化
优化
1.常用资源预加载:
重写WebViewClient的shouldInterceptRequest方法,根据url下载好资源,保存到本地,
WebResourceResponse response = new WebResourceResponse(mime, "UTF-8", new FileInputStream(new File(getJSPath() + TPMD5.md5String(url) + style)));
返回response。
2.常用 JS 本地化及延迟加载
3.使用第三方 WebView 内核
4.在应用启动的时候可以开一个像素的 WebView ,事先去访问一下我们常用的资源,
后续打开页面的时候如果再用到这些资源他就可以从本地获取到,页面加载的时间会短一些。
WebView 导致的内存泄露
采用以下方式:
1.WebView webView = new WebView(getContext().getApplicationContext());
webFrameLayout.addView(webView, 0);
2.单独放到一个进程
js和java互相调用
对于Android调用JS代码的方法有2种:
1. 通过WebView的loadUrl()
2. 通过WebView的evaluateJavascript(),该方法的执行不会使页面刷新,而第一种方法(loadUrl )的执行则会
对于JS调用Android代码的方法有3种:
1. 通过WebView的addJavascriptInterface()进行对象映射
2. 通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url
3. 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息
对于JS调用Android代码的方法有3种:
1. 通过WebView的addJavascriptInterface()进行对象映射
2. 通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url (需要定义协议)
3. 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息
常见漏洞
https://blog.csdn.net/self_study/article/details/55046348
参考文章
//www.greatytc.com/p/95d4d73be3d1
https://blog.csdn.net/carson_ho/article/details/64904691
十六Binder机制
https://blog.csdn.net/singwhatiwanna/article/details/19756201
十七ClassLoader的理解
https://blog.csdn.net/briblue/article/details/54973413
十八Arouter的原理
https://blog.csdn.net/watertekhqx/article/details/72772400
十九组件化原理,组件化中路由的实现
https://juejin.im/entry/59cd8dd95188257e93499061
二十热修复跟插件化的原理
二十一线程池的几个参数的理解,四种线程池的使用场景
//www.greatytc.com/p/d5a3935d08df
二十二进程间为什么不能直接进行通信
安全性?
二十三Debug跟Release的APK的区别
https://blog.csdn.net/u014744118/article/details/48287897
二十四Listview跟Recyclerview的区别(刷新,缓存,各自的使用场景)
https://blog.csdn.net/fanenqian/article/details/61191532
二十五内存泄露的几种情况
非静态内部类、匿名内部类、handler、单例、注册、
二十六StringBuffer跟StringBuilder之间的区别
二十七并发相关,各种锁
ReentrantLock是Lock的实现类,是一个互斥的同步器,在多线程高竞争条件下,ReentrantLock比synchronized有更加优异的性能表现。
1 用法比较
Lock使用起来比较灵活,但是必须有释放锁的配合动作
Lock必须手动获取与释放锁,而synchronized不需要手动释放和开启锁
Lock只适用于代码块锁,而synchronized可用于修饰方法、代码块等
2 特性比较
ReentrantLock的优势体现在:
具备尝试非阻塞地获取锁的特性:当前线程尝试获取锁,如果这一时刻锁没有被其他线程获取到,则成功获取并持有锁
能被中断地获取锁的特性:与synchronized不同,获取到锁的线程能够响应中断,当获取到锁的线程被中断时,中断异常将会被抛出,同时锁会被释放
超时获取锁的特性:在指定的时间范围内获取锁;如果截止时间到了仍然无法获取锁,则返回
3 注意事项
在使用ReentrantLock类的时,一定要注意三点:
在finally中释放锁,目的是保证在获取锁之后,最终能够被释放
不要将获取锁的过程写在try块内,因为如果在获取锁时发生了异常,异常抛出的同时,也会导致锁无故被释放。
ReentrantLock提供了一个newCondition的方法,以便用户在同一锁的情况下可以根据不同的情况执行等待或唤醒的动作。
二十八service
-----------Service----处理事件时间超过20秒发生anr-------
1.启动方式
startService/stopService
bindService/unbindService
2.生命周期
startService方式启动:onCreate()、onStartCommand()、onDestroy()
bindService方式启动: onCreate()、onBind()、onUnbind()、onDestroy(0
service在8.0上有啥变化?
参考:https://blog.csdn.net/chenshengfa/article/details/71407704
当应用处于后台时:
1.在后台运行的服务在几分钟内会被stop掉(模拟器测试在1分钟左右后被kill掉)。在这段时间内,应用仍可以创建和使用服务。
2.在应用处于后台几分钟后(模拟器测试1分钟左右),应用将不能再通过startService创建后台服务,如果创建则抛出以下异常
Caused by: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.example.samsung.test/.TestService }: app is in background
应用处于后台时,虽然不能通过startService创建后台服务,但仍可以通过下面的方式创建前台服务。
NotificationManager noti = (NotificationManager)getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
noti.startServiceInForeground();
二十九Scroller的使用
https://blog.csdn.net/guolin_blog/article/details/48719871
三十Gradle生命周期
https://blog.csdn.net/woxueliuyun/article/details/54602701
初始化阶段:负责判断有多少个Projects参与构建。
配置阶段:负责对初始化阶段创建的Projects完成配置。
执行阶段:根据配置阶段的配置执行任务。
三十一View的生命周期
//www.greatytc.com/p/08e6dab7886e
三十二Activity跟Window之间的关系
https://blog.csdn.net/u011733020/article/details/49465707
三十三硬件加速
//www.greatytc.com/p/40f660e17a73
三十四为什么bindService可以跟Activity生命周期联动?
//www.greatytc.com/p/9f1729e3b8a7?utm_source=oschina-app
三十五Android的签名机制,APK包含哪些东西
https://blog.csdn.net/jiangwei0910410003/article/details/50402000