Android 面试题整理

1.Application生命周期:
 Application是APP全局的一个实例,它会管理APP的所有组件,它的生命周期直接影响了APP的生命周期
@Override
public void onCreate() {
super.onCreate();
}
onCreate方法,APP创建的时候会调用,早于任何Activity,Service,Receiver(不包括contentprovider是因为它具有跨进程提供数据的功能,不强制要求app启动),
所以整个应用的初始化代码在这里写,但要注意不要耗时过长,阻塞主线程。
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
onConfigurationChanged这个方法是配置发生变化的时候调用,最常用的场景就是横竖屏切换,另外键盘变化,系统字体大小变化等都会调用该方法。

 @Override
public void onLowMemory() {
    super.onLowMemory();
}

onLowMemory整个系统内存不足的时候调用,会在回调后马上回收进程,所以可以做一些数据保存的操作,尽量避免数据丢失。
它已经被onTrimMemory取代
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
}
系统内存的紧张情况,在这些状况发生时,会根据不同level回收不同级别的进程,你可以做一些操作减少内存占用,降低你的进程被回收的风险。
2. Activity生命周期
onCreate()->onStart()->onResume()->onPause()->onStop()->onDestroy()
按键对生命周期的影响:
BACK键:
当我们按BACK键时,我们这个应用程序将结束,这时候我们将先后调用onPause()->onStop()->onDestory()三个方法。
再次启动App时,会执行onCreate()->onStart()->onResume()
HOME键:
当我们打开一个应用A时,这时候我们会选择按HOME键,然后去打开应用B;而当我们按HOME的时候,Activity先后执行了onPause()->onStop()这两个方法,这时候应用程序并没有销毁。
而当我们从桌面再次启动应用A时,则先后分别执行了onRestart()->onStart()->onResume()三个方法。
Activity的启动模式:

  1. Standard模式(默认)
    我们平时直接创建的Activity都是这种模式的Activity,这种模式的Activity的特点是:只要你创建了Activity实例,一旦激活该Activity,
    则会向任务栈中加入新创建的实例,退出Activity则会在任务栈中销毁该实例。standard模式是所启动的Activity都是在同一个task容器栈下,
    不会重新创建新的task容器栈。先压入栈的Activity实例按顺序入栈底,后入栈在栈顶,处于栈的顶部Activity实例处于活动状态,其他处于非活动状态。
    按物理返回键,退出当前所处活动状态Activity窗口,这样就会从task容器栈中弹出,显示在手机主屏幕上,从而,有非活动状态转换成活动的状态。
    其次,standard容器栈可能会存在着相同的Activity实例,只有没调用一次startActivity方法,就会创建目标Activity实例对象压入task容器栈。
    如果Activity启动顺序为A->B->B->A->D,栈中的Acitivy为ABBAD(最先创建的A位于栈底,最后创建的D位于栈顶)

  2. SingleTop模式
    这种模式会考虑当前要激活的Activity实例在任务栈中是否正处于栈顶,如果处于栈顶则无需重新创建新的实例,会重用已存在的实例,
    否则会在任务栈中创建新的实例。SingleTop有个不错的用法是防止多次点击创建多个Activity,无论start几次,SingleTop模式能保证栈顶只有一个实例。
    如果Activity启动顺序为A->B->B->A->D,栈中的Acitivy为ABAD(当B位于栈顶时,再次启动B的时候,B不会重新创建)

  3. SingleTask模式
    如果任务栈中存在该模式的Activity实例,则把栈中该实例以上的Activity实例全部移除,调用该实例的newInstance()方法重用该Activity,使该实例处於栈顶位置,
    否则就重新创建一个新的Activity实例。singletask模式,特别需要注意了。启动的目标Activity实例如果已经存在task容器栈中,不管当前实例处于栈的任何位置,
    是栈顶也好,栈底也好,还是处于栈中间,只要目标Activity实例处于task容器栈中,都可以重用该Activity实例对象,然后,把处于该Activity实例对象上面全部Activity实例清除掉,
    并且,task容器栈中永远只有唯一实例对象,不会存在两个相同的实例对象。所以,如果你想你的应用不管怎么启动目标Activity,都只有唯一一个实例对象,就使用这种启动模式。
    如果Activity启动顺序为A->B->B->A->D,栈中的Acitivy为AD(当A再次被启动时,A会被移到栈顶,位于A上面的Acitivity全部会出栈)

  4. SingleInstance模式
    当该模式Activity实例在任务栈中创建后,只要该实例还在任务栈中,即只要激活的是该类型的Activity,都会通过调用实例的newInstance()方法重用该Activity,此时使用的都是同一个Activity实例,
    它都会处于任务栈的栈顶。此模式一般用于加载较慢的,比较耗性能且不需要每次都重新创建的Activity。singleInstance启动模式,简单说就是可以共享某个Activity。
    比如,应用1的任务容器栈中创建了MainActivity实例,应用2也要激活MainActivity,则不需要创建MainActivity实例,直接可以公用MainActivity实例。
    尤其值得注意:应用1启动MainActivity,按home键;打开应用2启动应用1的MainActivity实例。在按home键,打开应用1,这时候应用1的界面是应该是处于MainActivity界面实例。 SingleInstance的一个任务栈中只有一个Activity,并保证不再有其他Activity实例进入。
    特别需要注意的生命周期onNewIntent
    当一个Activity被start,而不需要重新创建时,就会执行onNewIntent生命周期。如果一个Activity的启动模式是SingleTask,我们可以在onNewIntent中执行一些刷新操作等。
    我们一般会把MainAcitivy设置为SingleTask,除了保证MainActivity的唯一,还可以利用singleTask的特性做一些清理工作。自动管理栈,销毁无用的Acitivity.
    3.Service、IntentService,Service和组件间通信
    Service:
    创建Service,需要继承Service类。并重写它的回调方法,这些回调方法反应了Service的生命周期,并提供了绑定Service的机制。
    Service的生命周期回调方法如下所示:
    onStartCommand():当其他组件调用startService()方法请求启动Service时,该方法被回调。一旦Service启动,它会在后台独立运行。
    当Service执行完以后,需调用stopService()方法停止Service。
    onBind():当其他组件调用bindService()方法请求绑定Service时,该方法被回调。该方法返回一个IBinder接口,该接口是Service与绑定的组件进行交互的桥梁。若Service未绑定其他组件,该方法应返回null。
    onCreate():当Service第一次创建时,回调该方法。该方法只被回调一次,并在onStartCommand() 或 onBind()方法被回调之前执行。若Service处于运行状态,该方法不会回调。
    onDestroy():当Service被销毁时回调,在该方法中应清除一些占用的资源,如停止线程、接触绑定注册的监听器或broadcast receiver 等。该方法是Service中的最后一个回调
    4.Activity的onNewIntent

    1.android:launchMode=“singleTask” 配置在 Mainifest 中,它保证了栈中此Activity总是只有一个,无论你启动它多少次;
    Activiy配置成android:launchMode=“singleTask” ,在点Home键退出Activity而再次启动新的Intent进来时onNewIntent(Intent intent) 方法会被调用到;
    2.利用已有的Acivity去处理别的Intent时,你就可以利用onNewIntent来处理,通常被用在有搜索请求的activity,而其该activity有好几个intent-filter,该方法被调用的前提
    a、该activity设置如下属性 android:launchMode=“singleTop”。
    b、该activity已经处在栈的顶端,通过其他的方法又重新启动该acitvity时被调用,如搜索,这时oncreate()方法不调用。

5.Fragment的懒加载实现,参数传递与保存: 保证在任何情况下,只有可见的那一个 Fragment才会执行 耗时操作,网络请求和UI操作 其余不可见的,一律不执行任何操作,并且已有的操作(比如 定时器,
已经发出的网络请求)都要手动终止
1. Fragment 会听从 ViewPager的缓存机制,只要 ViewPager觉得一个 Fragment应该被初始化(无论是不是可见),然后缓存起来,那么 Fragment就会执行完整的生命周期 ,
2.至于具体初始化几个,这个 与 ViewPager的 setOffscreenPageLimit()缓存设置有关当所在的 Activity发生跳转,其中的已经被实例化的
Fragment都会执行:onPause-onStop当回到所在 Activity时,onStart-onResume -

6.ContentProvider实例详解
1.ContentProvider:内容提供者,对外提供增删改查的方法。
2.ContentResolver:内容解析者,通过URI获取ContentProvider的接口实现数据的增删改查。
3.ContentObserver:内容监听者,通过URI,可以监听到ContentProvider的数据变化。

7.BroadcastReceiver使用总结
1.当系统或应用发出广播时,将会扫描系统中的所有广播接收者,通过action匹配将广播发送给相应的接收者,接收者收到广播后将会产生一个广播接收者的实例,
执行其中的onReceiver()这个方法;特别需要注意的是这个实例的生命周期只有10秒,如果10秒内没执行结束onReceiver(),系统将会报错。       
在onReceiver()执行完毕之后,该实例将会被销毁,所以不要在onReceiver()中执行耗时操作,也不要在里面创建子线程处理业务(因为可能子线程没处理完,
接收者就被回收了,那么子线程也会跟着被回收掉);正确的处理方法就是通过in调用activity或者service处理业务。
2.静态广播接收的处理器是由PackageManagerService负责,当手机启动或者新安装了应用的时候,PackageManagerService会扫描手机中所有已安装的APP应用,
将AndroidManifest.xml中有关注册广播的信息解析出来,存储至一个全局静态变量当中。动态广播接收的处理器是由ActivityManagerService负责,当APP的服务或者进程起来之后,
执行了注册广播接收的代码逻辑,即进行加载,最后会存储在一个另外的全局静态变量中。需要注意的是:

8.Android消息机制
1.首先Looper.prepare()创建Looper并初始化Looper持有的消息队列MessageQueue,创建好后将Looper保存到ThreadLocal中方便Handler直接获取。
2.然后Looper.loop()开启循环,从MessageQueue里面取消息并调用handler的 dispatchMessage(msg) 方法处理消息。如果MessageQueue里没有消息,
循环就会阻塞进入休眠状态,等有消息的时候被唤醒处理消息。
3.再然后我们new Handler()的时候,Handler构造方法中获取Looper并且拿到Looper的MessageQueue对象。然后Handler内部就可以直接往MessageQueue里面插入消息了,
插入消息即发送消息,这时候有消息了就会唤醒Looper循环去处理消息。处理消息就是调用dispatchMessage(msg) 方法,最终调用到我们重写的Handler的handleMessage()方法。

9.Binder机制,共享内存实现原理
Binder机制:为了实现IPC,进程间通信。
Binder模型的4个角色:Binder驱动,ServiceManager,Server,Client
这里用:MediaPlayer代表 Client,MediaPlayerService 代表Server
Binder驱动:当Client向Server发起请求,Client会先将请求数据从用户空间拷贝到内核空间(将数据从MediaPlayer发给Binder驱动);数据被拷贝到内核空间之后,
再通过驱动程序,将内核空间中的数据拷贝到Server位于用户空间的缓存中(Binder驱动将数据发给MediaPlayerService)。
这样,就成功的将Client进程中的请求数据传递到了Server进程中。实际上,Binder驱动是整个Binder机制的核心
ServiceManager:ServiceManager也是运行在用户空间的一个独立进程。
对于Binder驱动而言,ServiceManager是一个守护进程,更是Android系统各个服务的管理者。Android系统中的各个服务,都是添加到ServiceManager中进行管理的,
而且每个服务都对应一个服务名。当Client获取某个服务时,则通过服务名来从ServiceManager中获取相应的服务。
对于MediaPlayerService和MediaPlayer而言,ServiceManager是一个Server服务端,是一个服务器。
当要将MediaPlayerService等服务添加到ServiceManager中进行管理时,ServiceManager是服务器,它会收到MediaPlayerService进程的添加服务请求。
当MediaPlayer等客户端要获取MediaPlayerService等服务时,它会向ServiceManager发起获取服务请求。
为什么采用binder机制:
第一. Binder能够很好的实现Client-Server架构
第二. Binder的传输效率和可操作性很好
第三. Binder机制的安全性很高
Binder 通信过程:
(01) Server进程启动之后,会进入中断等待状态,等待Client的请求。
(02) 当Client需要和Server通信时,会将请求发送给Binder驱动。
(03) Binder驱动收到请求之后,会唤醒Server进程。
(04) 接着,Binder驱动还会反馈信息给Client,告诉Client:它发送给Binder驱动的请求,Binder驱动已经收到。
(05) Client将请求发送成功之后,就进入等待状态。等待Server的回复。
(06) Binder驱动唤醒Server之后,就将请求转发给Server进程。
(07) Server进程解析出请求内容,并将回复内容发送给Binder驱动。
(08) Binder驱动收到回复之后,唤醒Client进程。
(09) 接着,Binder驱动还会反馈信息给Server,告诉Server:它发送给Binder驱动的回复,Binder驱动已经收到。
(10) Server将回复发送成功之后,再次进入等待状态,等待Client的请求。
(11) 最后,Binder驱动将回复转发给Client。
10.Android 事件分发机制

       事件分发机制是一个责任链模式:
       在不拦截不处理事件的情况下,事件的分的过程是有
 acttivity.dispatchTouchEvent(MotionEvent ev) -> viewGroup.dispatchTouchEvent(MotionEvent ev) ->onInterceptTouchEvent(MotionEvent ev)
 -> view.dispatchTouchEvent(MotionEvent ev)->view.onTouchevent(otionEvent ev)->viewGroup.onTouchevent(otionEvent ev)->activity.onTouchevent(otionEvent ev)
      从对View和viewGroup以及activity中的事件分析我们可以看到事件的分发处理过程是这样的:首先由activity优先分发给他的根视图,而根视图会优先判断是否拦截事件,
不拦截则对事件做继续分发,直到在某一级视图事件被消耗了才会停止分发这个事件,否则,在最后一层视图,因为它没有子视图了,那么事件的分发就结束了,
从而转入对onTouchevent()的调用,当onTouchevent()执行结束,它的dispatchTouchEvent(ev)执行结束即它的父视图的getChildAt(0).dispatchTouchEvent(ev)执行结束。
事件传给最底层的View,如果他的onTouchEvent()方法返回true,则事件由最底层的View消耗并处理了,如果返回false则表示该View不做处理,
则传递给父View的onTouchEvent()处理,如果父View的onTouchEvent()仍旧返回返回false,则继续传递给改父View的父View处理,如此的反复下去。
举例:
     技术总监(顶层ViewGroup)→技术经理(中层ViewGroup)→工程师(底层View)
           技术总监不拦截,把bug分给了技术经理,技术经理不拦截把bug分给了工程师,工程师没有下属只有自己处理了。
  
           事件由上而下传递返回值规则为:true,拦截,不继续向下传递;false,不拦截,继续向下传递。
  
  再返回我们现实的例子,工程师发现这个bug太难搞不定(onTouchEvent()返回false),
  他只能交给上级技术经理处理,如果技术经理也搞不定(onTouchEvent()返回false),
  那就把bug传给技术总监,技术总监一看bug很简单就解决了(onTouchEvent()返回true)。
  
           事件由下而上传递返回值规则为:true,处理了,不继续向上传递;false,不处理,继续向上传递。

点击事件传递时的其他问题
如果我们设置了OnTouchListener并且onTouch()方法返回true,则onTouchEvent()方法不会被调用,否则则会调用onTouchEvent()方法,
可见OnTouchListener的优先级要比onTouchEvent()要高。在OnTouchEvent()方法中,如果当前设置了OnClickListener则会执行它的onClick()方法。
View的OnTouchEvent()方法默认都会返回true,除非它是不可点击的也就是CLICKABLE和LONG_CLICKABLE都为false。
11.Android 多线程的实现:Thread、HandlerThread、AsyncTask、IntentService、RxJava

       **12.谈谈消息机制Handler作用 ?有哪些要素 ?流程是怎样的 ?**

参考回答:负责跨线程通信,这是因为在主线程不能做耗时操作,而子线程不能更新UI,
所以当子线程中进行耗时操作后需要更新UI时,通过Handler将有关UI的操作切换到主线程中执行。
具体分为四大要素:
Message(消息):需要被传递的消息,消息分为硬件产生的消息(如按钮、触摸)和软件生成的消息。
MessageQueue(消息队列):负责消息的存储与管理,负责管理由 Handler发送过来的Message。
读取会自动删除消息,单链表维护,插入和删除上有优势。在其next()方法中会无限循环,不断判断是否有消息,有就返回这条消息并移除。
Handler(消息处理器):负责Message的发送及处理。主要向消息池发送各种消息事件(Handler.sendMessage())和处理相应消息事件(Handler.handleMessage()),
按照先进先出执行,内部使用的是单链表的结构。
Looper(消息池):负责关联线程以及消息的分发,在该线程下从 MessageQueue获取 Message,分发给Handler,Looper创建的时候会创建一个 MessageQueue,
调用loop()方法的时候消息循环开始,其中会不断调用messageQueue的next()方法,当有消息就处理,否则阻塞在messageQueue的next()方法中。
当Looper的quit()被调用的时候会调用messageQueue的quit(),此时next()会返回null,然后loop()方法也就跟着退出
流程:
在主线程创建的时候会创建一个Looper,同时也会在在Looper内部创建一个消息队列。而在创键Handler的时候取出当前线程的Looper,并通过该Looper对象获得消息队列,
然后Handler在子线程中通过MessageQueue.enqueueMessage在消息队列中添加一条Message。通过Looper.loop() 开启消息循环不断轮询调用 MessageQueue.next(),
取得对应的Message并且通过Handler.dispatchMessage传递给Handler,最终调用Handler.handlerMessage处理消息。

13.RecyclerView与ListView(缓存原理,区别联系,优缺点)
ListView :ListView的缓存机制相对比较好理解,它只有两级缓存,一级缓存Active View是负责屏幕内的ItemView快速复用,而Scrap View是缓存屏幕外的数据,
当该数据从屏幕外滑动到屏幕内的时候需要走一遍getView()方法。
RecyclerView:Scrap Cache ViewCacheExtension RecycledViewPool
Scrap:对应ListView 的Active View,就是屏幕内的缓存数据,可以直接拿来复用。
Cache:刚刚移出屏幕的缓存数据,默认大小是2个,当其容量被充满同时又有新的数据添加的时候,会根据FIFO原则,把优先进入的缓存数据移出并放到下一级缓存中,
然后再把新的数据添加进来。Cache里面的数据是干净的,也就是携带了原来的ViewHolder的所有数据信息,数据可以直接来拿来复用。需要注意的是,
cache是根据position来寻找数据的,这个postion是根据第一个或者最后一个可见的item的position以及用户操作行为(上拉还是下拉)。
ViewCacheExtension:是google留给开发者自己来自定义缓存的
RecycledViewPool:刚才说了Cache默认的缓存数量是2个,当Cache缓存满了以后会根据FIFO(先进先出)的规则把Cache先缓存进去的ViewHolder移出并缓存到RecycledViewPool中,
RecycledViewPool默认的缓存数量是5个。RecycledViewPool与Cache相比不同的是,从Cache里面移出的ViewHolder再存入RecycledViewPool之前ViewHolder的数据会被全部重置,
相当于一个新的ViewHolder,而且Cache是根据position来获取ViewHolder,而RecycledViewPool是根据itemType获取的,如果没有重写getItemType()方法,
itemType就是默认的。因为RecycledViewPool缓存的ViewHolder是全新的,所以取出来的时候需要走onBindViewHolder()方法。
ListView有两级缓存,分别是Active View和Scrap View,缓存的对象是ItemView;而RecyclerView有四级缓存,分别是Scrap、Cache、ViewCacheExtension和RecycledViewPool,
缓存的对象是ViewHolder。Scrap和Cache分别是通过position去找ViewHolder可以直接复用;ViewCacheExtension自定义缓存,目前来说应用场景比较少却需慎用;
RecycledViewPool通过type来获取ViewHolder,获取的ViewHolder是个全新,需要重新绑定数据。

14.View、SurfaceView 与 TextureView
SurfaceView:优点:可以在一个独立的线程中进行绘制,不会影响主线程 使用双缓冲机制,播放视频时画面更流畅
缺点:Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换,也不能放在其它ViewGroup中。SurfaceView 不能嵌套使用
双缓冲:在运用时可以理解为:SurfaceView在更新视图时用到了两张Canvas,一张frontCanvas和一张backCanvas,每次实际显示的是frontCanvas,backCanvas存储的是上一次更改前的视图,
当使用lockCanvas()获取画布时,得到的实际上是backCanvas而不是正在显示的frontCanvas,之后你在获取到的backCanvas上绘制新视图,再unlockCanvasAndPost(canvas)此视图,
那么上传的这张canvas将替换原来的frontCanvas作为新的frontCanvas,原来的frontCanvas将切换到后台作为backCanvas。例如,如果你已经先后两次绘制了视图A和B,
那么你再调用lockCanvas()获取视图,获得的将是A而不是正在显示的B,之后你讲重绘的C视图上传,那么C将取代B作为新的frontCanvas显示在SurfaceView上,原来的B则转换为backCanvas。
TextureView:SurfaceView不同,它不会在WMS中单独创建窗口,而是作为View hierachy中的一个普通View,因此可以和其它普通View一样进行移动,旋转,缩放,动画等变化。
值得注意的是TextureView必须在硬件加速的窗口中。它显示的内容流数据可以来自App进程或是远端进程。从类图中可以看到,TextureView继承自View,
它与其它的View一样在View hierachy中管理与绘制。TextureView重载了draw()方法,其中主要SurfaceTexture中收到的图像数据作为纹理更新到对应的HardwareLayer中

优点:支持移动、旋转、缩放等动画,支持截图
缺点:必须在硬件加速的窗口中使用,占用内存比SurfaceView高,在5.0以前在主线程渲染,5.0以后有单独的渲染线程。

15:主线程Looper.loop为什么不会造成死循环
1.耗时操作本身并不会导致主线程卡死, 导致主线程卡死的真正原因是耗时操作之后的触屏操作, 没有在规定的时间内被分发。
2.Looper 中的 loop()方法, 他的作用就是从消息队列MessageQueue 中不断地取消息, 然后将事件分发出去。
16.ViewPager的缓存实现
17.AndroidP新特性

1.限制非Activity场景启动Activity从Android P开始,只有当Intent flag中指定了FLAG_ACTIVITY_NEW_TASK,才允许在非Activity场景启动Activity。
如果不在Intent添加FLAG_ACTIVITY_NEW_TASK,将无法通过非Activity的Context启动一个Activity,并且会抛异常。
2.前台服务需要添加权限在安卓P版本之后,必须要授予FOREGROUND_SERVICE权限,才能够使用前台服务,否则会抛出异常。
3.限制静态广播的接收,升级安卓P之后,隐式广播将会被全面禁止,在AndroidManifest中注册的Receiver将不能够生效,如果你的清单文件中有如下的监听器
4.非全屏透明Activity禁用设置orientation非全屏透明页面不允许设置方向,否则会抛Caused by: java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation异常,
解决方案:android:windowIsTranslucent设置为false。
5.非 SDK 接口访问限制

18.Android两种虚拟机
1.Dalvik:
2.ART: 在Android5.0中,ART取代了Dalvik虚拟机(安卓在4.4中发布了ART)。ART虚拟机直接执行本地机器码;而Dalvik虚拟机运行的是DEX字节码需要通过解释器执行。(空间换时间)
ART的运行原理
1.在Android系统启动过程中创建的Zygote进程利用ART运行时导出的Java虚拟机接口创建ART虚拟机。
2.APK在安装的时候,打包在里面的classes.dex文件会被工具dex2oat翻译成本地机器指令,最终得到一个ELF格式的oat文件。
3.APK运行时,上述生成的oat文件会被加载到内存中,并且ART虚拟机可以通过里面的oatdata和oatexec段找到任意一个类的方法对应的本地机器指令来执行。
?oat文件中的oatdata包含用来生成本地机器指令的dex文件内容
?oat文件中的oatexec包含有生成的本地机器指令。
通过两者的对比可以得出如下结论(与Dalvik大同小异)
?非并行GC在垃圾回收的整个过程中暂停了所有非gc线程
?并行GC在一开始只是对堆进行加锁,对于那些暂时并不会在堆中分配的内存的线程不起作用,它们依然可以运行,但是会造成对象的引用发生变化,但是这段时间的引用发生的变化被记录了下来。
之后系统会停止所有线程,对上面记录的数据进行处理,然后唤起所有线程,系统进入垃圾回收阶段。

20.ADB常用命令
检测APP:
adb shell am start -W packageName/.MainActivity
//启动时间
adb shell dumpsys meminfo P I D / / 指 定 程 序 内 存 使 用 情 况 a d b s h e l l d u m p s y s m e m i n f o p a c k a g e N a m e / / 指 定 程 序 内 存 使 用 情 况 a d b s h e l l d u m p s y s c p u i n f o p a c k a g e N a m e / / 指 定 程 序 C P U 使 用 情 况 a d b s h e l l c a t / p r o c / u i d s t a t / PID // 指定程序内存使用情况 adb shell dumpsys meminfo packageName //指定程序内存使用情况 adb shell dumpsys cpuinfo packageName //指定程序CPU使用情况 adb shell cat /proc/uid_stat/ PID//使adbshelldumpsysmeminfopackageName//使adbshelldumpsyscpuinfopackageName//CPU使adbshellcat/proc/uidstat/PID/tcp_rcv
//接收的数据流量
adb shell cat /proc/uid_stat/$PID/tcp_snd
//发送的数据流量
adb shell dumpsys batterystats packageName | more
//指定程序电量消耗信息
adb shell dumpsys batterystats | more
//综合电量消耗
adb shell dumpsys battery
//电池信息
adb shell “ps | grep packageName”
//查指定程序pid
其他常用命令:
adb shell getprop
//查看手机信息
adb shell getprop ro.serialno
//查看手机序列号
adb shell cat /proc/cpuinfo
//查看手机CPU信息
adb shell cat /proc/meminfo
//查看手机内存信息
adb uninstall packageName
//卸载apk
adb reboot
//重启手机
adb reboot recovery
//重启手机到recovery
adb reboot bootloader
//重启手机到bootloader界面
adb kill-server
//关闭adb服务
adb start-server
//启动adb服务

21.Asset目录与res目录的区别
assets:不会在 R 文件中生成相应标记,存放到这里的资源在打包时会打入程序安装包中。(通过 AssetManager 类访问这些文件)
res:会在 R 文件中生成 id 标记,资源在打包时如果使用到则打包到安装包中,未使用到不会打入安装包中。
22.包管理机制
1. 根据Uri的Scheme协议不同,跳转到不同的界面,content协议跳转到InstallStart,其他的跳转到PackageInstallerActivity。
如果是Android7.0以及更高版本会跳转到InstallStart。
2.InstallStart将content协议的Uri转换为File协议,然后跳转到PackageInstallerActivity。
3.PackageInstallerActivity会分别对package协议和file协议的Uri进行处理,如果是file协议会解析APK文件得到包信息PackageInfo。
4.PackageInstallerActivity中会对未知来源进行处理,如果允许安装未知来源或者根据Intent判断得出该APK不是未知来源,就会初始化安装确认界面,
如果管理员限制来自未知源的安装, 就弹出提示Dialog或者跳转到设置界面。
5. 将APK的信息通过IO流的形式写入到PackageInstaller.Session中。
6.调用PackageInstaller.Session的commit方法,将APK的信息交由PMS处理。
7.PackageInstaller安装APK时会将APK的信息交由PMS处理,PMS通过向PackageHandler发送消息来驱动APK的复制和安装工作。
8.PMS发送INIT_COPY和MCS_BOUND类型的消息,控制PackageHandler来绑定DefaultContainerService,完成复制APK等工作。
9.复制APK完成后,会开始进行安装APK的流程,包括安装前的检查、安装APK和安装后的收尾工作。
PMS的创建过程,分为两个部分,分别是SyetemServer处理部分和PMS构造方法,PMS构造方法又分为5个部分,分别是开始阶段、扫描系统阶段、扫描Data分区阶段、扫描结束阶段和准备阶段。

23.Activity的构成:
Activity包含一个window对象,这个对象是由PhoneWindow来实现的,PhoneWindow将DecorView做为整个应用窗口的根View,
而这个DecorView又将屏幕划分为两个区域一个是TitleView一个是ContentView,而我们平常做应用所写的布局正是展示在ContentView中的。

24. View的draw流程
1.如果有设置背景,则绘制背景
2.保存canvas层
3.绘制自身内容
4.如果有子元素则绘制子元素
5.绘制效果
6.绘制装饰品(scrollbars)

25.根Activity工作流程
Launcher请求AMS过程------>AMS到ApplicationThread的调用过程-------->ActivityThread启动Activity
1.Launcher请求AMS过程:
startActivitySafely(Launcher.java)------->startActivity(Activity.java)------->startActivityForResult(Activity.java)-------->
execStartActivity(Instrumentation.java 要用来监控应用程序和系统的交互)------>getService(ActivityManager.java)------>得到IBinder类型的AMS的引用,再转换为IActivityManager类型的对象,采用AIDL的接口实现
回到Instrumentation类的execStartActivity方法中,从上面得知execStartActivity方法最终调用的是AMS的startActivity方法。
2.AMS到ApplicationThread的调用过程
startActivity(ActivityManagerService.java)--------->startActivityAsUser(ActivityManagerService.java 这个方法会获得调用者的UserId,AMS会根据这个UserId来确定调用者的权限)
------>startActivityLocked(ActivityStarter.java)-----startActivity(ActivityStarter.java 获取Launcher进程 获取Launcher进程的pid和uid并赋值
创建即将要启动的Activity的描述类ActivityRecord)------->startActivityUnchecked(ActivityStarter.java)-------->resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java)
------->resumeTopActivityUncheckedLocked----->resumeTopActivityInnerLocked------->startSpecificActivityLocked------->realStartActivityLocked(ActivityStackSupervisor.java)
app.thread指的是IApplicationThread,它的实现是ActivityThread的内部类ApplicationThread,其中ApplicationThread继承了IApplicationThread.Stub。
app指的是传入的要启动的Activity的所在的应用程序进程,当前代码逻辑运行在AMS所在的进程(SyetemServer进程),通过ApplicationThread来与应用程序进程进行Binder通信,
换句话说,ApplicationThread是AMS所在进程(SyetemServer进程)和应用程序进程的通信桥梁
3.ActivityThread启动Activity
scheduleLaunchActivity(ActivityThread.java scheduleLaunchActivity方法会将启动Activity的参数封装成ActivityClientRecord ,
sendMessage方法向H类发送类型为LAUNCH_ACTIVITY的消息,并将ActivityClientRecord 传递过去)----->handleMessage(H 应用程序进程要启动Activity时需要将该Activity所属的APK加载进来,
而LoadedApk就是用来描述已加载的APK文件 获取 packageInfo)-------->handleLaunchActivity-------->performLaunchActivity-------callActivityOnCreate(启动Activity)------performCreate
-----onCreate
performCreate方法中会调用Activity的onCreate方法,这样Activity就启动了,即应用程序就启动了。

26.Context关联类
ContextImpl和ContextWrapper继承自Context,ContextThemeWrapper、Service和Application继承自ContextWrapper。
ContextWrapper和ContextThemeWrapper都是Context的包装类,它们都含有Context类型的mBase对象,mBase具体指向的是ContextImpl,
这样通过ContextWrapper和ContextThemeWrapper也可以使用Context的方法。ContextThemeWrapper中包含和主题相关的方法(比如: getTheme方法),
因此,需要主题的Activity继承ContextThemeWrapper,而不需要主题的Service则继承ContextWrapper

27.Glide加载原理,缓存方案,LRU算法
1.Glide加载原理:
with()方法:创建了一个RequestManager,主要目的是获取对应的FragmentManager,创建一个透明的(无UI)Fragment;getRequestManagerFragment()负责获取或者创建
SupportRequestManagerFragment(其实就是Fragment),RequestManager实现了生命周期的绑定,RequestManager通过生命周期调用requestTracker来控制 Request(请求)
load()方法: 大致上就是配置一下model 模型参数,表示我要加载的是什么model 模型参数,可以是uri、bitmap等,load() 目的是创建一个RequestBuilder,并配置各类参数
into()方法: 调用requestTracker.runRequest(request);把请求加入请求队列(requests),如果生命周期是 isPaused这时请request 就加入等待队列(pendingRequests)
这两个队列都是通过生命周期来维护的
当调用到 request.begin();会执行 SingleRequest中的begin();begin会调用到engine.load()方法,通过EngineKey 去活动缓存获取数据,获取不到再去内存缓存中获取数据
获取不到,就去硬盘获取数据(开启线程的形式),再获取不到就去网络获取数据
优势:生命周期管理
支持gif
三级缓存机制:内存缓存分为:活动缓存和内存缓存,活动缓存是正在使用的图片用弱引用缓存,再到磁盘缓存
占用内存小 采用的是 RGB565 格式
LRU算法:
定义:Least Recently Used,即 近期最少使用算法
算法原理:当缓存满时,优先淘汰 近期最少使用的缓存对象

28.Android 动画可以归纳为以下几种:
视图动画(View 动画):View 一般会用作直接作用页面中的 View 上,实现基本的动画效果:平移、旋转、缩放、透明度、或前几者的交集
帧动画(Frame 动画、Drawable 动画):开机动画等 一张张图片连续播放
属性动画:提供了 Getter 和 Setter 方法的对象的属性上,通过动态改变 View 相关属性的方式来改变 View 的显示效果
触摸反馈动画(Ripple Effect):所谓触摸反馈动画就是一种点击效果,作用在可点击的 View 上时,当有点击事件时会有涟漪般的反馈效果
揭露动画(Reveal Effect):揭露动画在系统中很常见,就是类似波纹的效果, 从某一个点向四周展开或者从四周向某一点聚合起来
转场动画 & 共享元素(Activity 切换动画):转场效果我们一般用在 Activity 切换时的动画效果上;共享元素一般我们使用在转换的前后两个页面有共同元素[注1]时;同时也可以在 Activity 布局发生场景变化时,让其中的 View 产生相应的过渡动画。
视图状态动画(Animate View State Changes)
矢量图动画(Vector 动画)
约束布局实现的关键帧动画(ConstraintSet 动画)

29.View 绘制工作原理
1.Activity,Window(PhoneWindow),DecorView之间的关系
Activity包含了一个PhoneWindow,
PhoneWindow就是继承于Window
Activity通过setContentView将View设置到了PhoneWindow上
PhoneWindow里面包含了DecorView,最终布局被添加到Decorview上.
当Activity准备好后,ActivityThread最终会调用到handleResumeActivity再调用到Activity中的makeVisible,并通过WindowManagerGlobal 中的 addView 添加View
在这个方法里面通过 ViewRootImpl 的setView方法----》requestLayout方法去View的绘制流程
2.ViewRootImpl,WindowManager,WindowManagerService(WMS)之间的关系
ViewRootImpl(客户端):View中持有与WMS链接的mAttachInfo,mAttachInfo持有ViewRootImpl.ViewRootImpl是ViewRoot的的实现,
WMS管理窗口时,需要通知客户端进行某种操作,比如事件响应等.ViewRootImpl有个内部类W,W继承IWindow.Stub,实则就是一个Binder,他用于和WMS IPC交互。
ViewRootHandler也是其内部类继承Handler,用于与远程IPC回来的数据进行异步调用.
WindowManger(客户端):客户端需要创建一个窗口,而具体创建窗口的任务是由WMS完成,WindowManger就像一个部门经理,谁有什么需求就告诉它,它和WMS交互,
客户端不能直接和WMS交互.WindowManagerService(WMS)(服务端):负责窗口的创建,显示等.
3.View的绘制流程
performTraversals()的是被WMS IPC调用执行的.View的绘制流程一般是从performTraversals -> performMeasure() -> performLayout() -> performDraw().
4.Android屏幕绘制关于绘制,就要从performDraw()说起,拿到了Java层的canvas,然后进行一系列绘制操作.而canvas是通过Suface.lockCanvas()得到的。
Suface通过调用JNI接口获取到底层 Skia绘图驱动

30.Android页面恢复
Android的页面恢复采用以下两个方法:
onSaveInstanceState(Bundle outState)
onRestoreInstanceState(Bundle savedInstanceState)
onSaveInstanceState: 当Activity容易被系统销毁时,会触发该方法。具体的说用户点击Home键,用户点击Home键,切换到其他应用程序有电话来了等附加操作
流程:调用了mWindow的saveHierarchyState()方法,将返回值保存在了outState中,其中mWindow是PhoneWindow类型再调用了saveHierarchyState()方法
调用了mContentParent的saveHierarchyState()方法,mContentParent是ViewGroup类型的变量,它的唯一子View是我们通过setContentView()添加进去的View。
ViewGroup并没有声明saveHierarchyState()方法,saveHierarchyState()方法是在View中声明的,再调用View的dispatchSaveInstanceState()方法
从上面的流程可以看到,mWindow.saveHierarchyState()方法,以深度优先的方法遍历了整个View树,将View的状态信息以键值对的形式存储到SparseArray中,
然后包装存储到Bundle中。有保存就有恢复,View的状态恢复在Activity的onRestoreInstanceState()方法中,非常对称得调用了PhoneWindow的restoreHierarchyState()方法,
进而调用了mContentParent的restoreHierarchyState()方法,按照id从SparseArray中取出保存的状态信息,并通过View的onRestoreInstanceState()方法进行恢复
Fragment的数据恢复:
是在在onCreate()中进行数据恢复的,当savedInstanceState不为空时,也就是当页面是销毁后重建时,会调用mFragments当restoreAllState()方法,
其中mFragments是FragmentController类型的对象,它的restoreAllState()方法只是直接调用了FragmentManager的restoreAllState()方法
状态信息的存储:状态信息的存储时保存在内存中的,并且时保存在ActivityManagerService所在的进程中的内存里面,就算应用进程结束后还是能收到ActivityManagerService返回的恢复数据

31.Android Studio编译过程
其中使用到的编译工具:aapt、aidl、Java Compiler、dex、 zipalign
主要步骤描述:
通过aapt打包res资源文件,生成R.java、resources.arsc和res文件(二进制 & 非二进制如res/raw和pic保持原样)
处理.aidl文件,生成对应的Java接口文件
通过Java Compiler编译R.java、Java接口文件、Java源文件,生成.class文件
通过dex命令,将.class文件和第三方库中的.class文件处理生成classes.dex
通过apkbuilder工具,将aapt生成的resources.arsc和res文件、assets文件和classes.dex一起打包生成apk
通过Jarsigner工具,对上面的apk进行debug或release签名
通过zipalign工具,将签名后的apk进行对齐处理。

32.Dagger依赖注入
Dagger是一种对Java和Android的静态的,编译时依赖注入(Dependency Injection)框架。
它主要用来解决很多由于大量使用反射reflection而带来的开发和性能问题。
Dagger可以用来帮你来建立之前需要写的Factory class。它主要用来代码生成。
Dagger也是根据@Inject注解来进行代码生成的。

以学习和做笔记为目的,有不对之处请指出,谢谢

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值