Android中高级工程师面试题

https://www.cnblogs.com/huangjialin/p/8657565.html(存在很多答案错误,可参照知识点复习,答案不可全信)  上html

https://www.cnblogs.com/huangjialin/p/8657696.html  下  2五、java

 

https://www.cnblogs.com/huangjialin/p/8622506.html  面试经历linux

 

19String为何要设计成不可变的? android

一、字符串池的需求ios

字符串池是方法区(Method Area)中的一块特殊的存储区域。当一个字符串已经被建立而且该字符串在 池 中,该字符串的引用会当即返回给变量,而不是从新建立一个字符串再将引用返回给变量。若是字符串是可变的,那么改变一个引用(如: string2)的字符串将会致使另外一个引用(如: string1)出现脏数据。面试

二、容许字符串缓存哈希码api

在java中经常会用到字符串的哈希码,例如: HashMap 。String的不变性保证哈希码始终一,所以,他能够不用担忧变化的出现。 这种方法意味着没必要每次使用时都从新计算一次哈希码——这样,效率会高不少。数组

三、安全缓存

String普遍的用于java 类中的参数,如:网络链接(Network connetion),打开文件(opening files )等等。若是String不是不可变的,网络链接、文件将会被改变——这将会致使一系列的安全威胁。操做的方法本觉得链接上了一台机器,但实际上却不是因为反射中的参数都是字符串,一样,也会引发一系列的安全问题。安全

 

39、如何控制某个方法容许并发访问线程的个数?

semaphore.acquire() 请求一个信号量,这时候的信号量个数-1(一旦没有可以使用的信号量,也即信号量个数变为负数时,再次请求的时候就会阻塞,直到其余线程释放了信号量)

semaphore.release() 释放一个信号量,此时信号量个数+1

 

45、线程间操做List 

List list = Collections.synchronizedList(new ArrayList());  //封装好的使用synchronized实现的线程安全List

 

5三、死锁的发生必须知足如下四个条件

  • 互斥条件:一个资源每次只能被一个进程使用。
  • 请求与保持条件:一个进程因请求资源而阻塞时,对已得到的资源保持不放。
  • 不可剥夺条件:进程已得到的资源,在末使用完以前,不能强行剥夺。
  • 循环等待条件:若干进程之间造成一种头尾相接的循环等待资源关系。

避免死锁最简单的方法就是阻止循环等待条件,将系统中全部的资源设置标志位、排序,规定全部的进程申请资源必须以必定的顺序(升序或降序)作操做来避免死锁。

56、什么是线程池,如何使用?

建立线程要花费昂贵的资源和时间,若是任务来了才建立线程那么响应时间会变长,并且一个进程能建立的线程数有限。为了不这些问题,在程序启动的时候就建立若干线程来响应处理,它们被称为线程池,里面的线程叫工做线程。

从JDK1.5开始,Java API提供了Executors框架让你能够建立不一样的线程池。好比

单线程池:newSingleThreadExecutor,每次处理一个任务;

数目固定的线程池:newFixedThreadPool

缓存线程池:newCachedThreadPool,适合不少生存期短的任务的可扩展线程池)

周期性执行线程池:newScheduledThreadPool

5八、线程间通讯

Android中主要是使用handler。handler经过调用sendmessage方法,将保存消息的Message发送到Messagequeue中,而looper对象不断的调用loop方法,从messageueue中取出message,交给同一个handler处理,从而完成线程间通讯。

 

59.Binder的工做机制

 直观来讲,Binder是Android中的一个类,它实现了IBinder接口,从IPC的角度来讲,Binder是Android中的一种跨进程通讯的一种方式,同时还能够理解为是一种虚拟的物理设备,它的设备驱动是/dev/binder/。从Framework角度来讲,Binder是ServiceManager的桥梁。从应用层来讲,Binder是客户端和服务端进行通讯的媒介。

咱们先来了解一下这个类中每一个方法的含义:

DESCRIPTOR:Binder的惟一标识,通常用于当前Binder的类名表示。

asInterface(android.os.IBinder obj):用于将服务端的Binder对象转换成客户端所需的AIDL接口类型的对象,这种转化过程是区分进程的,若是客户端和服务端位于同一个进程,那么这个方法返回的是服务端的stub对象自己,不然返回的是系统封装后的Stub.proxy对象。 

asBinder():用于返回当前Binder对象

onTransact:该方法运行在服务端的Binder线程池中,当客户端发起跨进程通讯请求的时候,远程请求经过系统底层封装后交给该方法处理。注意这个方法public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags),服务端经过code能够肯定客户端所请求的目标方法是什么,接着从data中取出目标方法所需的参数,而后执行目标方法。当目标方法执行完毕后,就向reply中写入返回值。这个方法的执行过程就是这样的。若是这个方法返回false,客户端是会请求失败的,因此咱们能够在这个方法中作一些安全验证。 

Binder的工做机制可是要注意一些问题:

一、当客户端发起请求时,因为当前线程会被挂起,直到服务端返回数据,若是这个远程方法很耗时的话,那么是不可以在UI线程,也就是主线程中发起这个远程请求的。

二、因为Service的Binder方法运行在线程池中,因此Binder方法无论是耗时仍是不耗时都应该采用同步的方式,由于它已经运行在一个线程中了。

 

60、Android中性能优化

因为手机硬件的限制,内存和CPU都没法像pc同样具备超大的内存,Android手机上,过多的使用内存,会容易致使oom,过多的使用CPU资源,会致使手机卡顿,甚至致使anr。我主要是从一下几部分进行优化:

App启动优化,布局优化,绘制优化,内存泄漏优化,响应速度优化,listview优化,图片优化,线程优化,电池优化,网络优化

 

App启动优化
App启动的方式有三种:
冷启动:App没有启动过或App进程被killed, 系统中不存在该App进程, 此时启动App即为冷启动。
热启动:热启动意味着你的App进程只是处于后台, 系统只是将其从后台带到前台, 展现给用户。
暖启动:介于冷启动和热启动之间, 通常来讲在如下两种状况下发生:
(1)用户back退出了App, 而后又启动. App进程可能还在运行, 可是activity须要重建。
(2)用户退出App后, 系统可能因为内存缘由将App杀死, 进程和activity都须要重启, 可是能够在onCreate中将被动杀死所保存的状态(onSaveInstanceState)恢复。
 
优化(针对冷启动):
Application的onCreate(特别是第三方SDK初始化),首屏Activity的渲染都不要进行耗时操做,若是有,就能够放到子线程或者IntentService中
 

布局优化:工具 hierarchyviewer,解决方式:

一、删除无用的空间和层级。

二、选择性能较低的viewgroup,如Relativelayout,若是能够选择Relativelayout也可使用LinearLayout,就优先使用LinearLayout,由于相对来讲Relativelayout功能较为复杂,会占用更多的CPU资源。

三、使用标签<include/>重用布局,<Merge/>减小层级,<viewStub/>进行预加载,使用的时候才加载。

 

绘制优化

绘制优化指view在ondraw方法中避免大量的耗时操做,因为ondraw方法可能会被频繁的调用。

一、ondraw方法中不要建立新的局部变量,ondraw方法被频繁的调用,很容易引发GC。

二、ondraw方法不要作耗时操做。

 

内存优化(部分)

1)少用枚举,枚举占用空间大。

2)使用Android特有的数据结构,如SparseArray来代替hashMap。

3)适当的使用软引用和弱引用。

 

响应优化

ANR方面:主线程不能作耗时操做,触摸事件5s,广播10s,service20s。

UI刷新方面:Android系统每隔16ms会发出VSYNC信号重绘咱们的界面(Activity)。
页面卡顿的缘由:
(1)过于复杂的布局.
(2)UI线程的复杂运算
(3)频繁的GC,致使频繁GC有两个缘由:  一、内存抖动, 即大量的对象被建立又在短期内立刻被释放 -->对象池  .二、瞬间产生大量的对象会严重占用内存区域  -->避免。

 

listview优化

一、getview方法中避免耗时操做。

二、view的复用和viewholder的使用。

三、滑动不适合开启异步加载。

四、分页处理数据。

 

图片优化
(1)对图片自己进行操做。尽可能不要使用setImageBitmap、setImageResource、BitmapFactory.decodeResource来设置一张大图,由于这些方法在完成decode后,最终都是经过java层的createBitmap来完成的,须要消耗更多内存.
(2)等比例压缩图片。另外,图片进行缩放的比例,SDK中建议其值是2的指数值,值越大会致使图片不清晰。
(3)不用的图片记得调用图片的recycle()方法
(4)图片加载使用三级缓存。

 

线程优化

线程优化的思想是使用线程池来管理和复用线程,避免程序中有大量的Thread,同时能够控制线程的并发数,避免相互抢占资源而致使线程阻塞。 

电池使用优化(使用工具:Batterystats & bugreport)
(1)优化网络请求
(2)定位中使用GPS, 请记得及时关闭
(3)JobService唤醒频率及条件控制
(4)减小IO交互
 
网络优化(网络链接对用户的影响:流量,电量,用户等待)可在Android studio下方logcat旁边那个工具Network Monitor检测
API设计:App与Server之间的API设计要考虑网络请求的频次, 资源的状态等. 以便App能够以较少的请求来完成业务需求和界面的展现.
Gzip压缩: 使用Gzip来压缩request和response, 减小传输数据量, 从而减小流量消耗.
图片的Size:能够在获取图片时 告知服务器须要的图片的宽高, 以便服务器给出合适的图片, 避免浪费.
网络缓存:适当的 缓存, 既可让咱们的应用看起来更快, 也能避免一些没必要要的流量消耗.

 

四、广播是分为有序广播和无序广播。

 

五、HttpClient与HttpUrlConnection的区别 
此处延伸:Volley里用的哪一种请求方式(2.3前HttpClient,2.3后HttpUrlConnection)
 
首先HttpClient和HttpUrlConnection 这两种方式都支持Https协议,都是以流的形式进行上传或者下载数据,也能够说是以流的形式进行数据的传输,还有ipv6,以及链接池等功能。HttpClient这个拥有很是多的API,因此若是想要进行扩展的话,而且不破坏它的兼容性的话,很难进行扩展,也就是这个缘由,Google在Android6.0的时候,直接就弃用了这个HttpClient.
而HttpUrlConnection相对来讲就是比较轻量级了,API比较少,容易扩展,而且可以知足Android大部分的数据传输。比较经典的一个框架volley,在2.3版本之前都是使用HttpClient,在2.3之后就使用了HttpUrlConnection。
 
七、进程保活(不死进程)
此处延伸:进程的优先级是什么
当前业界的Android进程保活手段主要分为** 黑、白、灰 **三种,其大体的实现思路以下:
黑色保活:不一样的app进程,用广播相互唤醒(包括利用系统提供的广播进行唤醒)
白色保活:启动前台Service
灰色保活:利用系统的漏洞启动前台Service
黑色保活
所谓黑色保活,就是利用不一样的app进程使用广播来进行相互唤醒。举个3个比较常见的场景:
场景1:开机,网络切换、拍照、拍视频时候,利用系统产生的广播唤醒app
场景2:接入第三方SDK也会唤醒相应的app进程,如微信sdk会唤醒微信,支付宝sdk会唤醒支付宝。由此发散开去,就会直接触发了下面的 场景3
场景3:假如你手机里装了支付宝、淘宝、天猫、UC等阿里系的app,那么你打开任意一个阿里系的app后,有可能就顺便把其余阿里系的app给唤醒了。(只是拿阿里打个比方,其实BAT系都差很少)
白色保活
白色保活手段很是简单,就是调用系统api启动一个前台的Service进程,这样会在系统的通知栏生成一个Notification,用来让用户知道有这样一个app在运行着,哪怕当前的app退到了后台。以下方的LBE和QQ音乐这样:
灰色保活
灰色保活,这种保活手段是应用范围最普遍。它是利用系统的漏洞来启动一个前台的Service进程,与普通的启动方式区别在于,它不会在系统通知栏处出现一个Notification,看起来就如同运行着一个后台Service进程同样。这样作带来的好处就是,用户没法察觉到你运行着一个前台进程(由于看不到Notification),但你的进程优先级又是高于普通后台进程的。那么如何利用系统的漏洞呢,大体的实现思路和代码以下:
思路一:API < 18,启动前台Service时直接传入new Notification();
思路二:API >= 18,同时启动两个id相同的前台Service,而后再将后启动的Service作stop处理
熟悉Android系统的童鞋都知道,系统出于体验和性能上的考虑,app在退到后台时系统并不会真正的kill掉这个进程,而是将其缓存起来。打开的应用越多,后台缓存的进程也越多。在系统内存不足的状况下,系统开始依据自身的一套进程回收机制来判断要kill掉哪些进程,以腾出内存来供给须要的app。这套杀进程回收内存的机制就叫 Low Memory Killer ,它是基于Linux内核的 OOM Killer(Out-Of-Memory killer)机制诞生。
进程的重要性,划分5级:
前台进程 (Foreground process)
可见进程 (Visible process)
服务进程 (Service process)
后台进程 (Background process)
空进程 (Empty process)
 
了解完 Low Memory Killer,再科普一下oom_adj。什么是oom_adj?它是linux内核分配给每一个系统进程的一个值,表明进程的优先级,进程回收机制就是根据这个优先级来决定是否进行回收。对于oom_adj的做用,你只须要记住如下几点便可:
进程的oom_adj越大,表示此进程优先级越低,越容易被杀回收;越小,表示进程优先级越高,越不容易被杀回收
普通app进程的oom_adj>=0,系统进程的oom_adj才可能<0
有些手机厂商把这些知名的app放入了本身的白名单中,保证了进程不死来提升用户体验(如微信、QQ、陌陌都在小米的白名单中)。若是从白名单中移除,他们终究仍是和普通app同样躲避不了被杀的命运,为了尽可能避免被杀,仍是老老实实去作好优化工做吧。
因此,进程保活的根本方案终究仍是回到了性能优化上,进程永生不死终究是个彻头彻尾的伪命题!
 
八、讲解一下Context 
Context是一个抽象基类。在翻译为上下文,也能够理解为环境,是提供一些程序的运行环境基础信息。Context下有两个子类,ContextWrapper是上下文功能的封装类,而ContextImpl则是上下文功能的实现类。而ContextWrapper又有三个直接的子类, ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是一个带主题的封装类,而它有一个直接子类就是Activity,因此Activity和Service以及Application的Context是不同的,只有Activity须要主题,Service不须要主题。Context一共有三种类型,分别是Application、Activity和Service。这三个类虽然分别各类承担着不一样的做用,但它们都属于Context的一种,而它们具体Context的功能则是由ContextImpl类去实现的,所以在绝大多数场景下,Activity、Service和Application这三种类型的Context都是能够通用的。不过有几种场景比较特殊,好比启动Activity,还有弹出Dialog。出于安全缘由的考虑,Android是不容许Activity或Dialog凭空出现的,一个Activity的启动必需要创建在另外一个Activity的基础之上,也就是以此造成的返回栈。而Dialog则必须在一个Activity上面弹出(除非是System Alert类型的Dialog),所以在这种场景下,咱们只能使用Activity类型的Context,不然将会出错。
 
getApplicationContext()和getApplication()方法获得的对象都是同一个application对象,只是对象的类型不同。
Context数量 = Activity数量 + Service数量 + 1 (1为Application)
 
1三、保存Activity状态
onSaveInstanceState(Bundle)会在activity转入后台状态以前被调用,也就是onStop()方法以前,onPause方法以后被调用;
 
1五、Android中跨进程通信的几种方式
Android 跨进程通讯,像intent,contentProvider,广播,service均可以跨进程通讯。
intent:这种跨进程方式并非访问内存的形式,它须要传递一个uri,好比说打电话。
contentProvider:这种形式,是使用数据共享的形式进行数据共享。
service:远程服务,aidl
广播
 
1六、AIDL理解
AIDL: 每个进程都有本身的Dalvik VM实例,都有本身的一块独立的内存,都在本身的内存上存储本身的数据,执行着本身的操做,都在本身的那片狭小的空间里过完本身的一辈子。而aidl就相似与两个进程之间的桥梁,使得两个进程之间能够进行数据的传输,跨进程通讯有多种选择,好比 BroadcastReceiver , Messenger 等,可是 BroadcastReceiver 占用的系统资源比较多,若是是频繁的跨进程通讯的话显然是不可取的;Messenger 进行跨进程通讯时请求队列是同步进行的,没法并发执行。
 
Binde机制简单理解:
在Android系统的Binder机制中,是有Client,Service,ServiceManager,Binder驱动程序组成的,其中Client,service,Service Manager运行在用户空间,Binder驱动程序是运行在内核空间的。而Binder就是把这4种组件粘合在一块的粘合剂,其中核心的组件就是Binder驱动程序,Service Manager提供辅助管理的功能,而Client和Service正是在Binder驱动程序和Service Manager提供的基础设施上实现C/S 之间的通讯。其中Binder驱动程序提供设备文件/dev/binder与用户控件进行交互,
Client、Service,Service Manager经过open和ioctl文件操做相应的方法与Binder驱动程序进行通讯。而Client和Service之间的进程间通讯是经过Binder驱动程序间接实现的。而Binder Manager是一个守护进程,用来管理Service,并向Client提供查询Service接口的能力。
 

1九、QQ空间热修复的原理
咱们知道Java虚拟机 —— JVM 是加载类的class文件的,而Android虚拟机——Dalvik/ART VM 是加载类的dex文件,
而他们加载类的时候都须要ClassLoader,ClassLoader有一个子类BaseDexClassLoader,而 BaseDexClassLoader下有一个
数组——DexPathList,是用来存放dex文件,当BaseDexClassLoader经过调用findClass方法时,实际上就是遍历数组,
找到相应的dex文件,找到,则直接将它return。而热修复的解决方法就是将新的dex添加到该集合中,而且是在旧的dex的前面,
因此就会优先被取出来而且return返回。
 
2五、HybridApp WebView和JS交互
(一)Android调用JS的代码
1. 经过WebView的loadUrl(),使用该方法比较简洁,方便。可是效率比较低,获取返回值比较困难。
2. 经过WebView的evaluateJavascript(),能够直接传入结果的回调方法。该方法效率高,可是4.4以上的版本才支持,4.4如下版本不支持。因此建议二者混合使用。
 
(二)JS调用Android的代码
1.经过WebView的addJavascriptInterface()进行对象映射
该方法使用简单,仅将Android对象和JS对象映射便可,可是存在比较大的漏洞。漏洞产生缘由是:当JS拿到Android这个对象后,就 能够调用这个Android对象中全部的方法,包括系统类(java.lang.Runtime 类),从而进行任意代码执行。
解决方式:
(1)Google 在Android 4.2 版本中规定对被调用的函数以 @JavascriptInterface进行注解从而避免漏洞攻击。
(2)在Android 4.2版本以前采用拦截prompt()进行漏洞修复
2.经过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url
这种方式的优势:不存在方式1的漏洞; 缺点:JS获取Android方法的返回值复杂。(ios主要用的是这个方式)
(1)Android经过 WebViewClient 的回调方法shouldOverrideUrlLoading ()拦截 url
(2)解析该 url 的协议
(3)若是检测到是预先约定好的协议,就调用相应方法
3. 经过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt()消息
这种方式的优势:不存在方式1的漏洞;缺点:JS获取Android方法的返回值复杂。
 https://www.cnblogs.com/zhangqie/p/6387433.html
https://www.cnblogs.com/itpepe/p/4882012.html
相关文章
相关标签/搜索