android常见面试大全

一,基础部分

1,四大组件是什么

1)Activity:用户可操作的可视化界面,为用户提供一个完成操作指令的窗口。一个Activity通常是一个单独的屏幕,Activity通过Intent来进行通信。Android中会维持一个Activity Stack,当一个新Activity创建时,它就会放到栈顶,这个Activity就处于运行状态。

2)Service:服务,运行在手机后台,适合执行不需和用户交互且还需长期运行的任务。

3)ContentProvider:内容提供者,使一个应用程序的指定数据集提供给其他应用程序,其他应用可通过ContentResolver类从该内容提供者中获取或存入数据。它提供了一种跨进程数据共享的方式,当数据被修改后,ContentResolver接口的notifyChange函数通知那些注册监控特定URI的ContentObserver对象。

如果ContentProvider和调用者在同一进程中,ContentProvider的方法(query/insert/update/delete等)和调用者在同一线程中;如果ContentProvider和调用者不在同一进程,ContentProvider方法会运行在它自身进程的一个Binder线程中。

4)Broadcast Receiver: 广播接收者,运用在应用程序间传输信息,可以使用广播接收器来让应用对一个外部事件做出响应。

2,四大组件的生命周期和简单用法

1)Activity:onCreate()->onStart()->onResume()->onPause()->onStop()->onDestory()

onCreate():为Activity设置布局,此时界面还不可见;

onStart(): Activity可见但还不能与用户交互,不能获得焦点

onRestart(): 重新启动Activity时被回调

onResume(): Activity可见且可与用户进行交互

onPause(): 当前Activity暂停,不可与用户交互,但还可见。在新Activity启动前被系统调用保存现有的Activity中的持久数据、停止动画等。

onStop(): 当Activity被新的Activity覆盖不可见时被系统调用

onDestory(): 当Activity被系统销毁杀掉或是由于内存不足时调用

2)Service

a) onBind方式绑定的:onCreate->onBind->onUnBind->onDestory(不管调用bindService几次,onCreate只会调用一次,onStart不会被调用,建立连接后,service会一直运行,直到调用unBindService或是之前调用的bindService的Context不存在了,系统会自动停止Service,对应的onDestory会被调用)

b) startService启动的:onCreate->onStartCommand->onDestory(start多次,onCreate只会被调用一次,onStart会调用多次,该service会在后台运行,直至被调用stopService或是stopSelf)

c) 又被启动又被绑定的服务,不管如何调用onCreate()只被调用一次,startService调用多少次,onStart就会被调用多少次,而unbindService不会停止服务,必须调用stopService或是stopSelf来停止服务。必须unbindService和stopService(stopSelf)同时都调用了才会停止服务。

3)BroadcastReceiver

a) 动态注册:存活周期是在Context.registerReceiver和Context.unregisterReceiver之间,BroadcastReceiver每次收到广播都是使用注册传入的对象处理的。

b) 静态注册:进程在的情况下,receiver会正常收到广播,调用onReceive方法;生命周期只存活在onReceive函数中,此方法结束,BroadcastReceiver就销毁了。onReceive()只有十几秒存活时间,在onReceive()内操作超过10S,就会报ANR。

进程不存在的情况,广播相应的进程会被拉活,Application.onCreate会被调用,再调用onReceive。

4)ContentProvider:应该和应用的生命周期一样,它属于系统应用,应用启动时,它会跟着初始化,应用关闭或被杀,它会跟着结束。

3,Android 进程通讯方式

  • bundle :
    由于Activity,Service,Receiver都是可以通过Intent来携带Bundle传输数据的,所以我们可以在一个进程中通过Intent将携带数据的Bundle发送到另一个进程的组件。(bundle只能传递三种类型,一是键值对的形式,二是键为String类型,三是值为Parcelable类型)
  • ContentProvider
    :ContentProvider是Android四大组件之一,以表格的方式来储存数据,提供给外界,即Content
    Provider可以跨进程访问其他应用程序中的数据
  • 文件
    :两个进程可以到同一个文件去交换数据,我们不仅可以保存文本文件,还可以将对象持久化到文件,从另一个文件恢复。要注意的是,当并发读/写时可能会出现并发的问题。
  • Broadcast :Broadcast可以向android系统中所有应用程序发送广播,而需要跨进程通讯的应用程序可以监听这些广播。
  • AIDL :AIDL通过定义服务端暴露的接口,以提供给客户端来调用,AIDL使服务器可以并行处理。
  • Messager :Messenger封装了AIDL之后只能串行运行,所以Messenger一般用作消息传递
  • Socket通信

4,Activity各种情况下的生命周期

1)两个Activity(A->B)切换(B正常的Activity)的生命周期:onPause(A)->onCreate(B)->onStart(B)->onResume(B)->oStop(A)

这时如果按回退键回退到A onPause(B)->onRestart(A)->onStart(A)->onResume(A)->oStop(B)

如果在切换到B后调用了A.finish(),则会走到onDestory(A),这时点回退键会退出应用

2) 两个Activity(A->B)切换(B透明主题的Activity或是Dialog风格的Acivity)的生命周期:onPause(A)->onCreate(B)->onStart(B)->onResume(B)

这时如果回退到A onPause(B)->onResume(A)->oStop(B)->onDestory(B)

3) Activity(A)启动后点击Home键再回到应用的生命周期:onPause(A)->oStop(A)->onRestart(A)->onStart(A)->onResume(A)

5,横竖屏切换的时候,Activity 各种情况下的生命周期

1)切换横屏时:onSaveInstanceState->onPause->onStop->onDestory->onCreate->onStart->onRestoreInstanceState->onResume

2) 切换竖屏时:会打印两次相同的log

onSaveInstanceState->onPause->onStop->onDestory->onCreate->onStart->onRestoreInstanceState->onResume->onSaveInstanceState->onPause->onStop->onDestory->onCreate->onStart->onRestoreInstanceState->onResume

3)如果在AndroidMainfest.xml中修改该Activity的属性,添加android:configChanges=“orientation”

横竖屏切换,打印的log一样,同1)

4)如果AndroidMainfest.xml中该Activity中的android:configChanges=“orientation|keyboardHidden”,则只会打印onConfigurationChanged

6,Activity与Fragment之间生命周期比较

Fragment生命周期:onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume->onPause->onStop->onDestoryView->onDestory->onDetach

切换到该Fragment:onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume

按下Power键:onPause->onSaveInstanceState->onStop

点亮屏幕解锁:onStart->onRestoreInstanceState->onResume

切换到其他Fragment: onPause->onStop->onDestoryView

切回到该Fragment: onCreateView->onActivityCreated->onStart->onResume

退出应用:onPause->onStop->onDestoryView->onDestory->onDetach

7,Activity上有Dialog的时候按Home键时的生命周期

AlertDialog并不会影响Activity的生命周期,按Home键后才会使Activity onPause->onStop,AlertDialog只是一个组件,并不会使Activity进入后台。

8,两个Activity 之间跳转时必然会执行的是哪几个方法

前一个Activity的onPause,后一个Activity的onResume

9,前台切换后台,再回到前台,Activity生命周期回调方法。弹出Dialog,生命值周期回调方法。

1)前台切换到后台,会执行onPause->onStop,再回到前台,会执行onRestart->onStart->onResume

2)弹出Dialog,并不会影响Activity生命周期。

10,Activity的四种启动模式对比

1)standard:标准启动模式(默认),每启动一次Activity,都会创建一个实例,即使从ActivityA startActivity ActivityA,也会再次创建A的实例放于栈顶,当回退时,回到上一个ActivityA的实例。

2)singleTop:栈顶复用模式,每次启动Activity,如果待启动的Activity位于栈顶,则不会重新创建Activity的实例,即不会走onCreate->onStart,会直接进入Activity onPause->onNewIntent->onResume方法

3)singleInstance: 单一实例模式,整个手机操作系统里只有一个该Activity实例存在,没有其他Actvity,后续请求均不会创建新的Activity。若task中存在实例,执行实例的onNewIntent()。应用场景:闹钟、浏览器、电话。

4)singleTask:栈内复用,启动的Activity如果在指定的taskAffinity的task栈中存在相应的实例,则会把它上面的Activity都出栈,直到当前Activity实例位于栈顶,执行相应的onNewIntent()方法。如果指定的task不存在,创建指定的taskAffinity的task,taskAffinity的作用,进入指写taskAffinity的task,如果指定的task存在,将task移到前台,如果指定的task不存在,创建指定的taskAffinity的task. 应用场景:应用的主页面。

11,Activity状态保存于恢复

Activity被主动回收时,如按下Back键,系统不会保存它的状态,只有被动回收时,虽然这个Activity实例已被销毁,但系统在新建一个Activity实例时,会带上先前被回收Activity的信息。在当前Activity被销毁前调用onSaveInstanceState(onPause和onStop之间保存),重新创建Activity后会在onCreate后调用onRestoreInstanceState(onStart和onResume之间被调用),它们的参数Bundle用来数据保存和读取的。保存View状态有两个前提:View的子类必须实现了onSaveInstanceState; 必须要设定Id,这个ID作为Bundle的Key

12,fragment各种情况下的生命周期

正常情况下的生命周期:onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume->onPause->onStop->onDestoryView->onDestory->onDetach

1)Fragment在Activity中replace onPause(旧)->onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume->onStop(旧)->onDestoryView(旧)

2)如果添加到backStack中,调用remove()方法fragment的方法会走到onDestoryView,但不会执行onDetach(),即fragment本身的实例是存在的,成员变量也存在,但是view被销毁了。如果新替换的Fragment已在BackStack中,则不会执行onAttach->onCreate

13,说说ContentProvider、ContentResolver、ContentObserver 之间的关系

ContentProvider实现各个应用程序间数据共享,用来提供内容给别的应用操作。如联系人应用中就使用了ContentProvider,可以在自己应用中读取和修改联系人信息,不过需要获取相应的权限。它也只是一个中间件,真正的数据源是文件或SQLite等。

ContentResolver内容解析者,用于获取内容提供者提供的数据,通过ContentResolver.notifyChange(uri)发出消息

ContentObserver内容监听者,可以监听数据的改变状态,观察特定Uri引起的数据库变化,继而做一些相应的处理,类似于数据库中的触发器,当ContentObserver所观察的Uri发生变化时,便会触发它。

14,AlertDialog,popupWindow,Activity区别

1)Popupwindow在显示之前一定要设置宽高,Dialog无此限制。

2)Popupwindow默认不会响应物理键盘的back,除非显示设置了popup.setFocusable(true);而在点击back的时候,Dialog会消失。

3)Popupwindow不会给页面其他的部分添加蒙层,而Dialog会。

4)Popupwindow没有标题,Dialog默认有标题,可以通过dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)取消标题

5)二者显示的时候都要设置Gravity。如果不设置,Dialog默认是Gravity.CENTER。

6)二者都有默认的背景,都可以通过setBackgroundDrawable(new ColorDrawable(android.R.color.transparent))去掉。

7)Popupwindow弹出后,取得了用户操作的响应处理权限,使得其他UI控件不被触发。而AlertDialog弹出后,点击背景,AlertDialog会消失。

二,高级部分

1,Activity启动流程(从Launcher开始)
在这里插入图片描述

①,第一阶段: Launcher通知AMS要启动新的Activity(在Launcher所在的进程执行)

  • Launcher.startActivitySafely //首先Launcher发起启动Activity的请求
  • Activity.startActivity
  • Activity.startActivityForResult
  • Instrumentation.execStartActivity //交由Instrumentation代为发起请求
  • ActivityManager.getService().startActivity //通过IActivityManagerSingleton.get()得到一个AMP代理对象
  • ActivityManagerProxy.startActivity //通过AMP代理通知AMS启动activity

②,第二阶段:AMS先校验一下Activity的正确性,如果正确的话,会暂存一下Activity的信息。然后AMS会通知Launcher程序pause Activity(在AMS所在进程执行)

  • ActivityManagerService.startActivity
  • ActivityManagerService.startActivityAsUser
  • ActivityStackSupervisor.startActivityMayWait
  • ActivityStackSupervisor.startActivityLocked // 检查有没有在AndroidManifest中注册
  • ActivityStackSupervisor.startActivityUncheckedLocked
  • ActivityStack.startActivityLocked // 判断是否需要创建一个新的任务来启动Activity。
  • ActivityStack.resumeTopActivityLocked // 获取栈顶的activity,并通知Launcher应该pause掉这个Activity以便启动新的activity。
  • ActivityStack.startPausingLocked
  • ApplicationThreadProxy.schedulePauseActivity

③,pause Launcher的Activity,并通知AMS已经paused(在Launcher所在进程执行)

  • ApplicationThread.schedulePauseActivity
  • ActivityThread.queueOrSendMessage
  • H.handleMessage
  • ActivityThread.handlePauseActivity
  • ActivityManagerProxy.activityPaused

④,检查activity所在进程是否存在,如果存在,就直接通知这个进程,在该进程中启动Activity;不存在的话,会调用Process.start创建一个新进程(执行在AMS进程)

  • ActivityManagerService.activityPaused
  • ActivityStack.activityPaused
  • ActivityStack.completePauseLocked
  • ActivityStack.resumeTopActivityLocked
  • ActivityStack.startSpecificActivityLocked
  • ActivityManagerService.startProcessLocked
  • Process.start // 在这里创建了新进程,新的进程会导入ActivityThread类,并执行它的main函数。

⑤,创建ActivityThread实例,执行一些初始化操作,并绑定Application。如果Application不存在,会调用LoadedApk.makeApplication创建一个新的Application对象。之后进入Loop循环。(执行在新创建的app进程)

  • ActivityThread.main
  • ActivityThread.attach(false) //声明不是系统进程
  • ActivityManagerProxy.attachApplication

⑥,处理新的应用进程发出的创建进程完成的通信请求,并通知新应用程序进程启动目标Activity组件(执行在AMS进程)

  • ActivityManagerService.attachApplication // AMS绑定本地ApplicationThread对象,后续通过ApplicationThreadProxy来通信。
  • ActivityManagerService.attachApplicationLocked
  • ActivityStack.realStartActivityLocked //真正要启动Activity了!
  • ApplicationThreadProxy.scheduleLaunchActivity //AMS通过ATP通知app进程启动Activity

⑦,加载MainActivity类,调用onCreate声明周期方法(执行在新启动的app进程)

  • ApplicationThread.scheduleLaunchActivity //ApplicationThread发消息给AT
  • ActivityThread.queueOrSendMessage
  • H.handleMessage //AT的Handler来处理接收到的LAUNCH_ACTIVITY的消息
  • ActivityThread.handleLaunchActivity
  • ActivityThread.performLaunchActivity
  • Instrumentation.newActivity //调用Instrumentation类来新建一个Activity对象
  • Instrumentation.callActivityOnCreate
  • MainActivity.onCreate
  • ActivityThread.handleResumeActivity
  • AMP.activityResumed
  • AMS.activityResumed(AMS进程)

2,进程保活

此处延伸:进程的优先级是什么

当前业界的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一样躲避不了被杀的命运,为了尽量避免被杀,还是老老实实去做好优化工作吧。

所以,进程保活的根本方案终究还是回到了性能优化上,进程永生不死终究是个彻头彻尾的伪命题!

3,View,ViewGroup事件分发

1), Touch事件分发中只有两个主角:ViewGroup和View。ViewGroup包含onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent三个相关事件。View包含dispatchTouchEvent、onTouchEvent两个相关事件。其中ViewGroup又继承于View。

2),ViewGroup和View组成了一个树状结构,根节点为Activity内部包含的一个ViwGroup。

3),触摸事件由Action_Down、Action_Move、Aciton_UP组成,其中一次完整的触摸事件中,Down和Up都只有一个,Move有若干个,可以为0个。

4),当Acitivty接收到Touch事件时,将遍历子View进行Down事件的分发。ViewGroup的遍历可以看成是递归的。分发的目的是为了找到真正要处理本次完整触摸事件的View,这个View会在onTouchuEvent结果返回true。

5),当某个子View返回true时,会中止Down事件的分发,同时在ViewGroup中记录该子View。接下去的Move和Up事件将由该子View直接进行处理。由于子View是保存在ViewGroup中的,多层ViewGroup的节点结构时,上级ViewGroup保存的会是真实处理事件的View所在的ViewGroup对象:如ViewGroup0-ViewGroup1-TextView的结构中,TextView返回了true,它将被保存在ViewGroup1中,而ViewGroup1也会返回true,被保存在ViewGroup0中。当Move和UP事件来时,会先从ViewGroup0传递至ViewGroup1,再由ViewGroup1传递至TextView。

6),当ViewGroup中所有子View都不捕获Down事件时,将触发ViewGroup自身的onTouch事件。触发的方式是调用super.dispatchTouchEvent函数,即父类View的dispatchTouchEvent方法。在所有子View都不处理的情况下,触发Acitivity的onTouchEvent方法。

7),onInterceptTouchEvent有两个作用:1.拦截Down事件的分发。2.中止Up和Move事件向目标View传递,使得目标View所在的ViewGroup捕获Up和Move事件。

4,AIDL理解

AIDL: 每一个进程都有自己的Dalvik VM实例,都有自己的一块独立的内存,都在自己的内存上存储自己的数据,执行着自己的操作,都在自己的那片狭小的空间里过完自己的一生。而aidl就类似与两个进程之间的桥梁,使得两个进程之间可以进行数据的传输,跨进程通信有多种选择,比如 BroadcastReceiver , Messenger 等,但是 BroadcastReceiver 占用的系统资源比较多,如果频繁的跨进程通信显然是不可取的;Messenger 进行跨进程通信时请求队列是同步进行的,无法并发执行。

Binder机制简单理解:

在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接口的能力。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章