当即或许是Android最经典的面试题(2017.11.01)

转载请注明出处


synchronized函数和synchronized代码块的界别


    1. 先是synchronized函数和synchronized代码快之意范围来分别,synchronized函数一般锁定的是时下接近对象,synchronized代码块锁定作用域可以挑选是比照对象,也可是字符串等等.
    1. 眼前好像对象锁没有放的当儿,本类的富有synchronized(this)同步代码块都打断。如果有并发请求synchronized函数,同一时间只能发出一个央执行
      .
    1. 可是目前类似对象锁没有放的时候,其他请求可以拜本类中无牵动synchronized(this)的代码块,也得拜非同一把锁的代码块例如synchronized(Str)等.
    1. 是因为企图范围来分别,一般作用范围更加聊执行效率进一步强,平时开销被貌似选作用范围比较小之synchronized.

什么判断一个目标是可被回收的


    1. 之前java虚拟机使用引用计数器的算法,当引用计数器为0时表示该目标没引用了接下来于清理。但是这艺术大为难化解循环引用问题,所以时停止使用了。
    1. 眼前采取的是可达性分析算法来规定一个靶是无是可为回收。
    1. 原理是:通过一个给GC
      Roots的对象当作根对象,然后起于下搜寻,搜索的路子叫做引用链,当对象到GC
      Roots没有另外引用链相连的时光,则证实这个目标是未可用的.
    1. 匪可用对象并无是这就是推行回收措施,执行清理措施之前至少要经历两不成标记过程.
  • ①如果对象在进行可达性分析后发现并未跟GC
    Roots相连接的引用链,那它以会见于第一破标记并且开展相同糟罗,筛选的标准化是此目标是否发必要履行finalize()方法。当目标没覆盖finalize()方法,或者finalize()方法都为虚拟机调用了,虚拟机将即时简单种植状态尚且实属“没有必要履行”。(即表示一直回收).

  • ②若此目标为判定为出必不可少实施finalize()方法,那么这个目标将见面停放在一个名F-Queue的阵之中,并于稍后由一个出于虚拟机自动建立之、低优先级的Finalizer线程去实践其。这里所谓的“执行”是借助虚拟机会接触这个法,但并无承诺会等待她运行了,这样做的因是,如果一个目标在finalize()方法中尽款,或者有了死循环(更绝的情形),将充分可能会见招F-Queue队列中任何对象永久处于等候,甚至导致整个内存回收系统崩溃.
    1. finalize()方法是目标回收前的终极一坏机遇,稍后GC将本着F-Queue中之目标进行第二次稍圈圈之符号,如果目标要于finalize()中未让回收,只要还与引用链上之另外一个靶建立关联即可,譬如把好(this关键字)赋值给某类变量或者目标的积极分子变量,那在亚不好标记时它们以被移除出“即将回收”的汇聚;如果目标就时刻还没有避让,那大多它就是真正让回收了。
    1. 旁一个目标的finalize()方法都单会受网自动调用一次于,如果目标面临下一样坏回收,它的finalize()方法不见面让重新实施,因此次段子代码的自救行动挫折了。因为finalize()方法就深受虚拟机调用了,虚拟机都说是“没有必要履行”。(即表示一直回收).

形容一个函数,输入一个屡屡如38,拆分 3 + 8 = 11,1 + 1 = 2,最后2无法拆分就回到


    public  int  getNum(int num) {
        while (num >= 10) {
            num = num / 10 + num % 10;
        }
        return num;
    }

大多单过程而调用一个ContentProvider的query获取数据,ContentPrvoider是怎么影响的吧?


  • 分析:
    我们领略Activity这样的组件,它生命周期的回调函数是以UI线程中推行之,ContentProvider的onCreate()方法为是在UI线程中运行的,回答这个题材面前,我们第一要整清楚ContentProvider的Query(),insert(),delete(),updata()这几单办法是否为是在UI线程中运作。
  • 发觉问题:
    若以上几乎只措施是于UI线程中运作的,那么多单线程并发去调用就挺有或出现ANR;如果不是在UI线程运行的,那她是于一个做事线程中运行的还是当差不多个线程中运作的吧?即ContentProvider是否支持并发操作为?
  • 剖析问题:
    ContentResolver及ContentProvider类隐藏了落实细节,但是ContentProvider所提供的Query(),insert(),delete(),updata()这几个法子都是以ContentProvider进行的线程池中运行的,而未是于经过的主线程遭遇运行,以为这些方式来或被多个地方调用,所以它是线程安全的。
    ContentProvider实现进程通信是依赖于Binder机制的,所以上述问题会见回归到Binder线程处理问题,并无是各一个ContentProvider都见面生出一个线程池,而是一个历程同用一个线程池,共用底线程池就是Binder线程池。
  • 标准答案:
    一个content
    provider可以接受来自另外一个进程的多少要。尽管ContentResolver与ContentProvider类隐藏了落实细节,但是ContentProvider所提供的query(),insert(),delete(),update()都是在ContentProvider进程的线程池中叫调用执行之,而休是过程的主线程中。这个线程池是有Binder创建及掩护的,其实使用的即是每个应用进程中之Binder线程池。

Android设计ContentProvider的目的是啊?


    1. 隐形数据的实现方式,对外提供联合之数看接口;
    1. 还好的数额看权限管理。ContentProvider可以针对开发的多寡进行权力设置,不同之URI可以本着承诺不同的权限,只有符合权限要求的零件才能够看到ContentProvider的具体操作。
    1. ContentProvider封装了超进程共享的逻辑,我们才需要Uri即可访问数。由网来保管ContentProvider的始建、生命周期及拜的线程分配,简化我们在使用中共享数据(进程中通信)的方。我们尽管通过ContentResolver访问ContentProvider所提示的数量接口,而不需操心她所于过程是启动还是勿启动。

运作在主线程的ContentProvider为什么不会见影响主线程的UI操作?


    1. ContentProvider的onCreate()是运行在UI线程的,而query(),insert(),delete(),update()是运行在线程池中的劳作线程的,所以调用这为只办法并无见面死ContentProvider所在进程的主线程,但恐怕会见卡住调用者所于的长河的UI线程!
    1. 所以,调用ContentProvider的操作照旧使放在子线程中失去举行。虽然一直的CRUD的操作是于干活线程的,但系统会让你的调用线程等待这异步的操作完成,你才堪延续线程之前的干活。

伸手详细描述Android事件分发机制:


即时道题是多寒面试公司见面问到之一律志经典给试题,但与此同时每每于面试者忽略。

圈了无数博客也扣了无数代码,大部分都是拖泥带水,不便民阅读固总结如下:

主线传递只出三步:Activity->ViewGroup->View

Activity和View唯有发生一定量只章程控制事件传递:dispatchTouchEvent(),onTouchEvent
();

ViewGroup生三个措施控制传递:dispatchTouchEvent(),onInterceptTouchEvent(),onTouchEvent
();

紧接下用平等摆放图给大家讲述下实际是怎一步一步分发的。

总结:
1.对于 dispatchTouchEvent,onTouchEvent,return
true
是结束事件传递。return false
是想起至父View的onTouchEvent方法。
2.ViewGroup
怀念拿温馨分发给好的onTouchEvent,需要拦截器onInterceptTouchEvent方法return
true 把事件拦截下来。
3.ViewGroup 的遏止器onInterceptTouchEvent 默认是免挡的,所以return
super.onInterceptTouchEvent()=return false;
4.View
无拦截器,为了为View可以管事件分发给好的onTouchEvent,View的dispatchTouchEvent默认实现(super)就是把事件分发给协调的onTouchEvent。

ViewGroup和View 的dispatchTouchEvent
是开事件分发,那么这个波或者分发出去的季单对象
流淌:——> 后面代表事件目标需要怎么开。
1、 自己花,终结传递。——->return true
2、 给好的onTouchEvent处理——->
调用super.dispatchTouchEvent()系统默认会错过调用
onInterceptTouchEvent,在onInterceptTouchEvent return
true就见面失去管事件分吃好之onTouchEvent处理。
3、 传给子View——>调用super.dispatchTouchEvent()默认实现会晤失去调用
onInterceptTouchEvent 在onInterceptTouchEvent return
false,就见面管事件传给子类。
4、
不招为子View,事件已于下传递,事件初步回忆,从父View的onTouchEvent开始事件从下到上回归执行每个控件的onTouchEvent——->return
false

流动: 由于View没有子View所以不需onInterceptTouchEvent
来控件是否拿事件传递给子View还是拦,所以View的波分发调用super.dispatchTouchEvent()的时光默认把事件传被自己的onTouchEvent处理(相当给阻挡),对比ViewGroup的dispatchTouchEvent
事件分发,View的波分发只有dispatchTouchEvent()和onTouchEvent()不待onInterceptTouchEvent()参与。

至这事件分发总结收尾。如果想详细询问事件分发机制的呼吁看即首博客:
http://blog.csdn.net/w525721508/article/details/78227154


View的渲染过程,或者为View的绘图流程


当即道题吗是比一直的一致志题了,但是无论BAT还是小创业公司受到冒出的频率相当强
接通下便总结性的叙述一不折不扣View绘制流程,避免长,接下的讲述一切从简
盼各位读者耐心看罢,相信你晤面生老要命之得!
View绘图流程是以ViewRoot.java类的performTraversals()函数中开展的
绘制有共计需要三步:

measure() -> layout() -> draw();

1. 判读是否再次计算视图大小(measure)

此描绘图片描述

原理:从顶层父View像子View递归调用view.measure(),measure方法被掉调onMeasure()
MeasureSpec是View的测内部类,测量法为int型,值由大2位规格模式specMode和亚30各的具体尺寸specSize组成。

specMode有三种价值

MeasureSpec.UPSPECIFIED :
父容器对于子容器没有另外限制,子容器想使多好就是基本上好
MeasureSpec.EXACTLY:
父容器已经为子容器设置了尺寸,子容器应当从这些边界,不论子容器想使多大的半空中。
MeasureSpec.AT_MOST:子容器可以是声称大小内之擅自大小

  • View的measure方法是final,不得以重载,只能重载inMeasure完成好的测量逻辑

  • 顶层的DecorView的MeasureSpec是由ViewRootImpl中的getRootMeasureSpec方法确定(LayoutParams宽高参数都为MATCH_PARENT,specMode是EXACTLY,specSize为大体屏幕尺寸)。

  • ViewGroup类提供了measureChild,measureChild和measureChildWithMargins方法,简化了父子View的尺码计算。

  • 若果是ViewGroup的子类就必要求LayoutParams继承子MarginLayoutParams,否则无法以layout_margin参数。

  • View的布局大小由父View和子View共同决定。

  • 应用View的getMeasuredWidth()和getMeasuredHeight()方法来取得View测量的富足高,必须确保这片只办法在onMeasure流程之后为调用才会返有效值。

2. 是否重新分配视图的职务(layout)

此处描绘图片描述

原理:
layout也是由顶层父View向子View的递归调用View.layout方法的历程,父View根据上等同步measure子View得到的布局大小及布局参数,将子View放在合适的位置及。

  • View.layout方法好叫重载,ViewGroup.layout为final不可以让重载,ViewGroup.onLayout为abstract的子类必须重载实现和谐之职位逻辑

  • measure结束后获的凡每个View经测量后底measuredWidth和measuredHeight,Layout操作了以后获得的凡每个View进行岗位分配后底mLeft,mTop、mRight、mBottom,这些价值都是对立父View

  • 凡是layout_XXX的布局属性都是针对父级View的,如果View没有父级容器则layout_XXX属性是从未有过其余意义之

  • 利用View
    的getWidth()和getHright()方法得到View测量的方便高要保证及时片个法子以当onLayout流程之后。

3. 是不是再次绘制(draw)

此间描绘图片描述

原理:
draw过程为是于ViewRootImpl的performTraversals()内部调运的,其调用顺序以measure()和layout()之后,这里的mView对于Actiity来说就是PhoneWindow.DecorView,ViewRootImpl中的代码会创造一个Canvas对象,然后调用View的draw()方法来实施实际的绘制工。所以又回归至了ViewGroup与View的树状递归draw过程

  • 只要该View是一个ViewGroup,则需要递归绘制其所蕴涵的持有子View。

  • View默认不绘制任何内容,真正的绘图都在和谐的子类中贯彻

  • View的绘图是借助onDraw()方法传入的Canvas类来进行的

  • 分别View
    动画以及ViewGroup动画,前者是View自身的卡通可以透过setAnimation添加,后者可以透过xml布局之layoutAnimation属性添加

  • 于得到画布剪切区(每个View的draw中流传的Canvas)时见面自动处理掉padding,子View获得Canvas不用关爱这些逻辑,只关注如何绘制即可

  • 默认情况下子View的ViewGroup.drawChild绘制顺序及子View被添加底次第一致,但是若啊得重载ViewGroup.getChildDrawingOrder()以提供不同的相继

4. invalidate()

原理:
invalidate方法要重绘View树(也便是draw方法),如果View大小没有发生变化就未会见调用layout过程,并且就绘制那些“需要重绘的”View,也尽管是何许人也View(View只绘制该View,ViewGroup绘制整个ViewGroup)请求invalidate系列措施,就绘制该View。

  • 直接调用invalidate方法.请求重draw,但仅仅会绘制调用者本身。

  • 触发setSelection方法。请求重draw,但偏偏会绘制调用者本身。

  • 触发setVisibility方法。
    当View可视状态在INVISIBLE转换VISIBLE时会间接调用invalidate方法,继而绘制该View。当View的可视状态在INVISIBLE\VISIBLE
    转换为GONE状态时会见间接调用requestLayout和invalidate方法,同时由View树大小有了变动,所以会呈请measure过程与draw过程,同样只有绘制需要“重新绘制”的视图。

  • 触发setEnabled方法。请求又draw,但无会见又绘制任何View包括该调用者本身。

  • 触发requestFocus方法。请求View树的draw过程,只绘制“需要重绘”的View。

例:
当我们描绘一个Activity时,我们定会通过setContentView方法将我们而显的界面传入该法,该方法会讲我们界面通过addView追加到id为content的一个FrameLayout(ViewGroup)中,然后addView方法中经过调运invalidate(true)去通知触发ViewRootImpl类的performTraversals()方法,至此递归绘制我们于定义之保有布局。

5.requestLayout()

原理:
View的requestLayout时那面目就是是偶发提高传递,直到ViewRootImpl为止,然后触发ViewRootImpl的requestLayout方法
requestLayout()方法会调用measure过程与layout过程,不见面调用draw过程,也无会见又绘制任何View包括该调用者本身。

以上也View渲染的整过程,如产生题目欢迎指正。