本文是Android面试题整理中的一篇,结合右下角目录食用更佳,包括:html
分为四个层次:linux内核;libraies和Android runntime;framework;Application java
![]()
- Activity:Activity是Android程序与用户交互的窗口,对用户来讲是可见的
- service:后台服务于Activity,是一个服务,不可见
- Content Provider:对外提提供数据
- BroadCast Receiver:接受一种或者多种Intent做触发事件,接受相关消息,作一些简单处理
- 前台进程
- 可见进程
- 服务进程
- 后台进程
- 空进程
- res目录下的资源文件会在R文件中生成对应的id,asset不会\
- res目录下的文件在生成apk时,除raw(即res/raw)目录下文件不进行编译外,都会被编译成二进制文件;asset目录下的文件不会进行编译
- asset目录容许有子目录
- 沙箱化能够提高安全性和效率
- Android的底层内核为Linux,所以继承了Linux良好的安全性,并对其进行了优化。在Linux中,一个用户对应一个uid,而在Android中,(一般)一个APP对应一个uid,拥有独立的资源和空间,与其余APP互不干扰。若有两个APP A和B,A并不能访问B的资源,A的崩溃也不会对B形成影响,从而保证了安全性和效率
- 没有任何设置时,会调用整个生命周期方法,而且会调用onSaveInstance和onRestoreInstanceState方法
- 在Manifest中为Activity设置android:configChanges="orientation"时,只调用onConfigChanges方法
- android:configChanges="orientation"属性有可能不起做用,依然会调用整个生命周期方法,这是由于不一样版本处理方式可能不一样,有时候还须要加上android:configChanges="orientation|keyboardHidden|screenSize"等。
- 非用户主动明确结束(按back键,自定义click方法调用finish)时都会调用onSaveInstanceState:
- 屏幕旋转
- 按HOME键
- 内存不足
- 从一个activity启动另外一个activity
- 这个方法的调用时机是在onStop前,可是它和onPause没有既定的时序关系
- View有惟一的ID
- View的初始化时要调用setSaveEnabled(true)
对Activity配置了android:configChanges="xxx"属性以后,Activity就不会在对应变化发生时从新建立,而是调用Activity的onConfigurationChanged方法。经常使用的有local:设备的本地位置发生了变化,通常指切换了系统语言;keyboardHidden:键盘的可访问性发生了变化,好比用户调出了键盘;orientation:屏幕方向发生了变化,好比旋转了手机屏幕。linux
- A启动B:A.onPause()→B.onCreate()→B.onStart()→B.onResume()→A.onStop
- B返回A:B.onPause()→A.onRestart()/A.onCreate()→A.onStart()→A.onResume()→B.onStop()
- 在onCreate中执行:onCreate -> onDestroy
- 在onStart中执行:onCreate -> onStart -> onStop -> onDestroy
- 在onResume中执行:onCreate -> onStart -> onResume -> onpause -> onStop -> onDestroy
- 能够用Google的LifeCycle框架 0. 引入LifeCycle框架
- 将控件实现LifecycleObserver接口
- 在Activity中中注册控件:getLifeCycle().addObderver(View);
- 在控件中使用: @OnLifecycleEvent(Lifecycle.Event.ON_START)
- standard:每一次启动,都会生成一个新的实例,放入栈顶中
- singleTop:经过singelTop启动Activity时,若是发现有须要启动的实例正在栈顶,责直接重用,不然生成新的实例
- singleTask:经过singleTask启动Activity时,若是发现有须要启动的实例正在栈中,责直接移除它上边的实例,并重用该实例,不然生成新的实例
- singleInstance:经过singleTask启动Activity时,会启用一个新的栈结构,并将新生成的实例放入栈中。
- 任务相关性,标识一个Activity所需的任务栈的名字。默认状况下,全部的Activity所需的任务栈的名字是应用的包名,固然也能够单独指定TaskAffinity属性。
- TaskAffinity属性主要和singleTask启动模式和allowTaskRepeating属性配对使用,在其余状况下使用没有意义
- 当TaskAffinity和singleTask启动模式配对使用的时候,它是具备该模式的Activity的目前任务栈的名字,待启动的Activity会运行在名字和TaskAffinity相同的任务栈中
- 当TaskAffinity和allowTaskReparenting结合的时候,当一个应用A启动了应用B的某个Activity C后,若是Activity C的allowTaskReparenting属性设置为true的话,那么当应用B被启动后,系统会发现Activity C所需的任务栈存在了,就将Activity C从A的任务栈中转移到B的任务栈中。
- TaskAffinity配合singleTask使用,指定任务栈:若是没有TaskAffinity指定的任务栈,则开启新栈
- allowTaskReparenting配合standard和singleTop使用,标明该Activity的任务栈能够从新设置
设置了singleTask启动模式的Activity,它在启动的时会先在系统中查看属性值affinity等于它的属性值taskAffinity ( taskAffinity默认为包名 ) 的任务栈是否存在。若是存在这样的任务栈,它就会在这个任务栈中启动,不然就会在新任务栈中启动。android
当Intent对象包含FLAG_ACTIVITY_NEW_TASK标记时,系统在查找时仍然按Activity的taskAffinity属性进行匹配,若是找到一个任务栈的taskAffinity与之相同,就将目标Activity压入此任务栈中,若是找不到则建立一个新的任务栈。git
设置了singleTask启动模式的Activity在已有的任务栈中已经存在相应的Activity实例,再启动它时会把这个Activity实例上面的Activity所有结束掉。也就是说singleTask自带clear top的效果。github
IntentFilter中的过滤信息有action、category、data,为了匹配过滤列表,须要同时匹配过滤列表中的action、category、data信息,不然匹配失败。面试
- PackageManager的resolveActivity方法或者Intent的resolveActivity方法:若是找不到就会返回null
- PackageManager的queryIntentActivities方法:它返回全部成功匹配的Activity信息
经过在Application中注册Activity生命周期的监听函数Application.registerActivityLifecycleCallbacks()shell
一个Activity已经启动,当再次启动它时,若是他的启动模式(如SingleTask,SingleTop)标明不须要从新启动,会调用onNewIntent数据库
使用adb shell am 命令 :如adb shell am start com.example.fuchenxuan/.MainActivity 或者 adb shell am broadcast -a magcomm.action.TOUCH_LETTER缓存
- activity.runOnUiThread(runnable)
- 经过主线程中的Handler进行更新
- 经过View的post()或者postDelayed方法进行更新
- Intent
- BroadCast或者LocalBroadCast
- 数据存储的方式
- 静态变量
- start
- bind
- 如上Activity和Activity的通讯方式
- bind方式启动时能够经过ServiceConnection通讯:在SerVice的onBind方法中返回一个binder,该binder能够是AIDL方法产生的,也能够是Messenger方法产生的
- 这是没用任何关系的两个概念,servie是系统的组件,Thread是CPU运行的最小单元
- Service不可见,咱们能够把Service当成是不可见的Activity,用于在后台执行一些服务;
- Service能够运行在任意线程上,若是咱们生成它时没有作特殊说明,那么它运行在主线程上
- 不少时候咱们须要在Activity中开启一个Service,再在Service中开启一个线程,这么作的缘由是Service只会初始化一次,咱们能够随时找到Service中生成的thread,使用场景举例:
- 如咱们须要在多个Activity中对同一个thread进行控制时;
- 若是你的 Thread 须要不停地隔一段时间就要链接服务器作某种同步的话,该 Thread 须要在 Activity 没有start的时候也在运行。这个时候当你 start 一个 Activity 就没有办法在该 Activity 里面控制以前建立的 Thread。所以你便须要建立并启动一个 Service ,在 Service 里面建立、运行并控制该 Thread,这样便解决了该问题
这是由于Activity很难对Thread进行控制,当Activity被销毁以后,就没有任何其它的办法能够再从新获取到以前建立的子线程的实例。并且在一个Activity中建立的子线程,另外一个Activity没法对其进行操做。可是Service就不一样了,全部的Activity均可以与Service进行关联,而后能够很方便地操做其中的方法,即便Activity被销毁了,以后只要从新与Service创建关联,就又可以获取到原有的Service中Binder的实例。所以,使用Service来处理后台任务,Activity就能够放心地finish,彻底不须要担忧没法对后台任务进行控制的状况。
- IntentService 是继承自 Service,内部经过HandlerThread启动一个新线程处理耗时操做么,能够看作是Service和HandlerThread的结合体,在完成了使命以后会自动中止,适合须要在工做线程处理UI无关任务的场景
- 若是启动 IntentService 屡次,那么每个耗时操做会以工做队列的方式在 IntentService 的 onHandleIntent 回调方法中执行,依次去执行,使用串行的方式,执行完自动结束。
- 在全部任务执行完毕后,自动结束生命
- 在manifest中静态注册:广播是常驻的,App关闭后仍能接收广播,唤醒App
- 动态的注册和注销:动态注册的广播生命周期和他的宿主相同,或者调用注销方法注销广播
- 无序广播:经过mContext.sendBroadcast(Intent)或mContext.sendBroadcast(Intent, String)发送的是无序广播(后者加了权限);
- 经过mContext.sendOrderedBroadcast(Intent, String, BroadCastReceiver, Handler, int, String, Bundle)发送的是有序广播(再也不推荐使用)。
- 在无序广播中,全部的Receiver会接收到相同广播;而在有序广播中,咱们能够为Receiver设置优先级,优先级高的先接收广播,并有权对广播进行处理和决定要不要继续向下传送
- BroadcastReceiver的生命周期只有一个回调方法onReceive(Context context, Intent intent);没法进行耗时操做,即便启动线程处理,也是出于非活动状态,有可能被系统杀掉。
- 若是须要进行耗时操做,能够启动一个service处理。
- 继承BroadcastReceiver,重写onReceive()方法。
- 经过Binder机制向ActivityManagerService注册广播。
- 经过Binder机制向ActivityMangerService发送广播。
- ActivityManagerService查找符合相应条件的广播(IntentFilter/Permission)的BroadcastReceiver,将广播发送到BroadcastReceiver所在的消息队列中。
- BroadcastReceiver所在消息队列拿到此广播后,回调它的onReceive()方法。
- 广播是经过Intent携带须要传递的数据的
- Intent是经过Binder机制实现的
- Binder对数据大小有限制,不一样room不同,通常为1M
本地广播,只有本进程中的receivers能接收到此广播
实现原理(监听者模式):
- LocalBroadcastManager是一个单例
- 在LocalBroadcastManager实例中维护一个Action和ReceiverRecord的Map.(ReceiverRecord是reveiver和intentfilter的组合)
- 当调用LocalBroadcastManager的sendBroadcast方法时,会从2中的map找到合适的receiver,让后加到待执行的队列mPendingBroadcasts,并经过Handler发送一个空消息(此Handler运行在主线程中,是建立manager时建立的)
- handler 的handle方法收到消息,从mPendingBroadcasts取出receiver并调用onreceive方法
其余:删除方法是经过一个辅助的hashmap实现的,hashmap存储了receiver和receiverRecord
- 准确的说,ContentProvider是一个APP间共享数据的接口。一个程序能够经过实现一个Content provider的抽象接口将本身的数据彻底暴露出去,数据能够是SqLite中的,也能够是文件或者其余类型。
- 使用方式:
- 在A APP中实现建ContentProvider,并在Manifest中生命它的Uri和权限
- 在B APP中注册权限,并经过ContentResolver和Uri进行增删改查
- 扩展:ContentProvider底层是经过Binder机制来实现跨进程间通讯,经过匿名共享内存方式进行数据的传输 一个应用进程有16个Binder线程去和远程服务进行交互,而每一个线程可占用的缓存空间是128KB,超过会报异常。
- ContentProvider和调用者在同一个进程,ContentProvider的方法(query/insert/update/delete等)和调用者在同一线程中
- ContentProvider和调用者在不一样的进程,ContentProvider的方法会运行在它自身所在进程的一个Binder线程中
- ContentProvider:管理数据,提供数据的增删改查操做,数据源能够是数据库、文件、XML、网络等,ContentProvider为这些数据的访问提供了统一的接口,能够用来作进程间数据共享。
- ContentResolver:ContentResolver能够不一样URI操做不一样的ContentProvider中的数据,外部进程能够经过ContentResolver与ContentProvider进行交互。
- ContentObserver:观察ContentProvider中的数据变化,并将变化通知给外界。
onAttach -> onCreate -> onCreateView -> onActivityCreate -> onStart -> onResume -> onPause -> onStop -> onDestoryView -> onDestory -> onDetach
举例:getActivity()空指针:这种状况通常发生在在异步任务里调用getActivity(),而Fragment已经onDetach()。
- Fragment为了解决Andriod碎片化而产生的
- Fragment和View都有助于界面复用
- Fragment的复用粒度更大,包含生命周期和业务逻辑,一般包含好几个View
- View一般更关注视图的实现
https://www.nowcoder.com/discuss/3043
http://weixin.niurenqushi.com/article/2017-03-17/4790406.html
https://blog.csdn.net/vfush/article/details/51481127
https://blog.csdn.net/vfush/article/details/51790079