Android 面试基础篇

本文是Android面试题整理中的一篇,结合右下角目录食用更佳,包括:html

  • 架构
  • Activity
  • Service
  • BroadCast
  • ContentProvider
  • Fragment

架构


Android的大致架构图

分为四个层次:linux内核;libraies和Android runntime;framework;Application java

Android的四大组件是哪些,它们的做用?

  1. Activity:Activity是Android程序与用户交互的窗口,对用户来讲是可见的
  2. service:后台服务于Activity,是一个服务,不可见
  3. Content Provider:对外提提供数据
  4. BroadCast Receiver:接受一种或者多种Intent做触发事件,接受相关消息,作一些简单处理

Android 中进程的优先级

  1. 前台进程
  2. 可见进程
  3. 服务进程
  4. 后台进程
  5. 空进程

Android中asset和res目录的区别

  1. res目录下的资源文件会在R文件中生成对应的id,asset不会\
  2. res目录下的文件在生成apk时,除raw(即res/raw)目录下文件不进行编译外,都会被编译成二进制文件;asset目录下的文件不会进行编译
  3. asset目录容许有子目录

Android中App 是如何沙箱化的,为什么要这么作

  1. 沙箱化能够提高安全性和效率
  2. Android的底层内核为Linux,所以继承了Linux良好的安全性,并对其进行了优化。在Linux中,一个用户对应一个uid,而在Android中,(一般)一个APP对应一个uid,拥有独立的资源和空间,与其余APP互不干扰。若有两个APP A和B,A并不能访问B的资源,A的崩溃也不会对B形成影响,从而保证了安全性和效率

Activity


Activity 生命周期

Activity在屏幕旋转时的生命周期

  1. 没有任何设置时,会调用整个生命周期方法,而且会调用onSaveInstance和onRestoreInstanceState方法
  2. 在Manifest中为Activity设置android:configChanges="orientation"时,只调用onConfigChanges方法
  3. android:configChanges="orientation"属性有可能不起做用,依然会调用整个生命周期方法,这是由于不一样版本处理方式可能不一样,有时候还须要加上android:configChanges="orientation|keyboardHidden|screenSize"等。

onSaveInstanceState 何时调用

  1. 非用户主动明确结束(按back键,自定义click方法调用finish)时都会调用onSaveInstanceState:
    1. 屏幕旋转
    2. 按HOME键
    3. 内存不足
    4. 从一个activity启动另外一个activity
  2. 这个方法的调用时机是在onStop前,可是它和onPause没有既定的时序关系

自定义View控件的状态被保存须要知足两个条件

  1. View有惟一的ID
  2. View的初始化时要调用setSaveEnabled(true)

configChanges属性

对Activity配置了android:configChanges="xxx"属性以后,Activity就不会在对应变化发生时从新建立,而是调用Activity的onConfigurationChanged方法。经常使用的有local:设备的本地位置发生了变化,通常指切换了系统语言;keyboardHidden:键盘的可访问性发生了变化,好比用户调出了键盘;orientation:屏幕方向发生了变化,好比旋转了手机屏幕。linux

A activity启动B activity和B activity返回A activity的生命周期执行过程

  1. A启动B:A.onPause()→B.onCreate()→B.onStart()→B.onResume()→A.onStop
  2. B返回A:B.onPause()→A.onRestart()/A.onCreate()→A.onStart()→A.onResume()→B.onStop()

Activity执行finish后的生命周期

  1. 在onCreate中执行:onCreate -> onDestroy
  2. 在onStart中执行:onCreate -> onStart -> onStop -> onDestroy
  3. 在onResume中执行:onCreate -> onStart -> onResume -> onpause -> onStop -> onDestroy

若是用了一些解耦的策略,怎么管理生命周期的?

  1. 能够用Google的LifeCycle框架 0. 引入LifeCycle框架
    1. 将控件实现LifecycleObserver接口
    2. 在Activity中中注册控件:getLifeCycle().addObderver(View);
    3. 在控件中使用: @OnLifecycleEvent(Lifecycle.Event.ON_START)

Activity的启动流程

Android中Activity的启动模式

  1. standard:每一次启动,都会生成一个新的实例,放入栈顶中
  2. singleTop:经过singelTop启动Activity时,若是发现有须要启动的实例正在栈顶,责直接重用,不然生成新的实例
  3. singleTask:经过singleTask启动Activity时,若是发现有须要启动的实例正在栈中,责直接移除它上边的实例,并重用该实例,不然生成新的实例
  4. singleInstance:经过singleTask启动Activity时,会启用一个新的栈结构,并将新生成的实例放入栈中。

TaskAffinity 属性

  1. 任务相关性,标识一个Activity所需的任务栈的名字。默认状况下,全部的Activity所需的任务栈的名字是应用的包名,固然也能够单独指定TaskAffinity属性。
  2. TaskAffinity属性主要和singleTask启动模式和allowTaskRepeating属性配对使用,在其余状况下使用没有意义
  3. 当TaskAffinity和singleTask启动模式配对使用的时候,它是具备该模式的Activity的目前任务栈的名字,待启动的Activity会运行在名字和TaskAffinity相同的任务栈中
  4. 当TaskAffinity和allowTaskReparenting结合的时候,当一个应用A启动了应用B的某个Activity C后,若是Activity C的allowTaskReparenting属性设置为true的话,那么当应用B被启动后,系统会发现Activity C所需的任务栈存在了,就将Activity C从A的任务栈中转移到B的任务栈中。

Activity启动模式的TaskAffinity和allowTaskReparenting

  1. TaskAffinity配合singleTask使用,指定任务栈:若是没有TaskAffinity指定的任务栈,则开启新栈
  2. allowTaskReparenting配合standard和singleTop使用,标明该Activity的任务栈能够从新设置

当前应用有两个Activity A和B,B的 android:launchMode 设置了singleTask模式,A是默认的standard,那么A startActivity启动B,B会新启一个Task吗?若是不会,那么startActivity的Intent加上FLAG_ACTIVITY_NEW_TASK这个参数会不会呢?

设置了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的匹配规则

IntentFilter中的过滤信息有action、category、data,为了匹配过滤列表,须要同时匹配过滤列表中的action、category、data信息,不然匹配失败。面试

验证是否有当前Activity

  1. PackageManager的resolveActivity方法或者Intent的resolveActivity方法:若是找不到就会返回null
  2. PackageManager的queryIntentActivities方法:它返回全部成功匹配的Activity信息

如何获取当前屏幕Activity的对象?

经过在Application中注册Activity生命周期的监听函数Application.registerActivityLifecycleCallbacks()shell

onNewIntent调用时机

一个Activity已经启动,当再次启动它时,若是他的启动模式(如SingleTask,SingleTop)标明不须要从新启动,会调用onNewIntent数据库

除了用Intent 去启动一个Activity,还有其余方法吗

使用adb shell am 命令 :如adb shell am start com.example.fuchenxuan/.MainActivity 或者 adb shell am broadcast -a magcomm.action.TOUCH_LETTER缓存

Android中子线程更新UI的方式

  1. activity.runOnUiThread(runnable)
  2. 经过主线程中的Handler进行更新
  3. 经过View的post()或者postDelayed方法进行更新

Activity之间的通讯方式

  1. Intent
  2. BroadCast或者LocalBroadCast
  3. 数据存储的方式
  4. 静态变量

Service


Service的启动方式

  1. start
  2. bind

Service生命周期

Service 和Activity 的通讯方式

  1. 如上Activity和Activity的通讯方式
  2. bind方式启动时能够经过ServiceConnection通讯:在SerVice的onBind方法中返回一个binder,该binder能够是AIDL方法产生的,也能够是Messenger方法产生的

Service和Thread的区别

  1. 这是没用任何关系的两个概念,servie是系统的组件,Thread是CPU运行的最小单元
  2. Service不可见,咱们能够把Service当成是不可见的Activity,用于在后台执行一些服务;
  3. Service能够运行在任意线程上,若是咱们生成它时没有作特殊说明,那么它运行在主线程上
  4. 不少时候咱们须要在Activity中开启一个Service,再在Service中开启一个线程,这么作的缘由是Service只会初始化一次,咱们能够随时找到Service中生成的thread,使用场景举例:
    1. 如咱们须要在多个Activity中对同一个thread进行控制时;
    2. 若是你的 Thread 须要不停地隔一段时间就要链接服务器作某种同步的话,该 Thread 须要在 Activity 没有start的时候也在运行。这个时候当你 start 一个 Activity 就没有办法在该 Activity 里面控制以前建立的 Thread。所以你便须要建立并启动一个 Service ,在 Service 里面建立、运行并控制该 Thread,这样便解决了该问题

为何有时须要在Service中建立子线程而不是Activity中

这是由于Activity很难对Thread进行控制,当Activity被销毁以后,就没有任何其它的办法能够再从新获取到以前建立的子线程的实例。并且在一个Activity中建立的子线程,另外一个Activity没法对其进行操做。可是Service就不一样了,全部的Activity均可以与Service进行关联,而后能够很方便地操做其中的方法,即便Activity被销毁了,以后只要从新与Service创建关联,就又可以获取到原有的Service中Binder的实例。所以,使用Service来处理后台任务,Activity就能够放心地finish,彻底不须要担忧没法对后台任务进行控制的状况。

IntentService

  1. IntentService 是继承自 Service,内部经过HandlerThread启动一个新线程处理耗时操做么,能够看作是Service和HandlerThread的结合体,在完成了使命以后会自动中止,适合须要在工做线程处理UI无关任务的场景
  2. 若是启动 IntentService 屡次,那么每个耗时操做会以工做队列的方式在 IntentService 的 onHandleIntent 回调方法中执行,依次去执行,使用串行的方式,执行完自动结束。

IntentService生命周期是怎样的

  1. 在全部任务执行完毕后,自动结束生命

BroadCast


BroadCast的注册方式与区别

  1. 在manifest中静态注册:广播是常驻的,App关闭后仍能接收广播,唤醒App
  2. 动态的注册和注销:动态注册的广播生命周期和他的宿主相同,或者调用注销方法注销广播

Android中发送BroadCast的方式

  1. 无序广播:经过mContext.sendBroadcast(Intent)或mContext.sendBroadcast(Intent, String)发送的是无序广播(后者加了权限);
  2. 经过mContext.sendOrderedBroadcast(Intent, String, BroadCastReceiver, Handler, int, String, Bundle)发送的是有序广播(再也不推荐使用)。
  3. 在无序广播中,全部的Receiver会接收到相同广播;而在有序广播中,咱们能够为Receiver设置优先级,优先级高的先接收广播,并有权对广播进行处理和决定要不要继续向下传送

BroadCastReceiver处理耗时操做

  1. BroadcastReceiver的生命周期只有一个回调方法onReceive(Context context, Intent intent);没法进行耗时操做,即便启动线程处理,也是出于非活动状态,有可能被系统杀掉。
  2. 若是须要进行耗时操做,能够启动一个service处理。

广播发送和接收的原理了解吗

  1. 继承BroadcastReceiver,重写onReceive()方法。
  2. 经过Binder机制向ActivityManagerService注册广播。
  3. 经过Binder机制向ActivityMangerService发送广播。
  4. ActivityManagerService查找符合相应条件的广播(IntentFilter/Permission)的BroadcastReceiver,将广播发送到BroadcastReceiver所在的消息队列中。
  5. BroadcastReceiver所在消息队列拿到此广播后,回调它的onReceive()方法。

广播传输的数据是否有限制,是多少,为何要限制?

  1. 广播是经过Intent携带须要传递的数据的
  2. Intent是经过Binder机制实现的
  3. Binder对数据大小有限制,不一样room不同,通常为1M

Localbroadcast

本地广播,只有本进程中的receivers能接收到此广播

实现原理(监听者模式):

  1. LocalBroadcastManager是一个单例
  2. 在LocalBroadcastManager实例中维护一个Action和ReceiverRecord的Map.(ReceiverRecord是reveiver和intentfilter的组合)
  3. 当调用LocalBroadcastManager的sendBroadcast方法时,会从2中的map找到合适的receiver,让后加到待执行的队列mPendingBroadcasts,并经过Handler发送一个空消息(此Handler运行在主线程中,是建立manager时建立的)
  4. handler 的handle方法收到消息,从mPendingBroadcasts取出receiver并调用onreceive方法
    其余:删除方法是经过一个辅助的hashmap实现的,hashmap存储了receiver和receiverRecord

ContentProvider


请介绍下ContentProvider是如何实现数据共享的

  1. 准确的说,ContentProvider是一个APP间共享数据的接口。一个程序能够经过实现一个Content provider的抽象接口将本身的数据彻底暴露出去,数据能够是SqLite中的,也能够是文件或者其余类型。
  2. 使用方式:
    1. 在A APP中实现建ContentProvider,并在Manifest中生命它的Uri和权限
    2. 在B APP中注册权限,并经过ContentResolver和Uri进行增删改查
  3. 扩展:ContentProvider底层是经过Binder机制来实现跨进程间通讯,经过匿名共享内存方式进行数据的传输 一个应用进程有16个Binder线程去和远程服务进行交互,而每一个线程可占用的缓存空间是128KB,超过会报异常。

每一个ContentProvider的操做是在哪一个线程中运行的呢(其实咱们关心的是UI线程和工做线程)?好比咱们在UI线程调用getContentResolver().query查询数据,而当数据量很大时(或者须要进行较长时间的计算)会不会阻塞UI线程呢?

  1. ContentProvider和调用者在同一个进程,ContentProvider的方法(query/insert/update/delete等)和调用者在同一线程中
  2. ContentProvider和调用者在不一样的进程,ContentProvider的方法会运行在它自身所在进程的一个Binder线程中

ContentProvider、ContentResolver与ContentObserver之间的关系是什么?

  1. ContentProvider:管理数据,提供数据的增删改查操做,数据源能够是数据库、文件、XML、网络等,ContentProvider为这些数据的访问提供了统一的接口,能够用来作进程间数据共享。
  2. ContentResolver:ContentResolver能够不一样URI操做不一样的ContentProvider中的数据,外部进程能够经过ContentResolver与ContentProvider进行交互。
  3. ContentObserver:观察ContentProvider中的数据变化,并将变化通知给外界。

Fragment


Fragment生命周期

onAttach -> onCreate -> onCreateView -> onActivityCreate -> onStart -> onResume -> onPause -> onStop -> onDestoryView -> onDestory -> onDetach

遇到过哪些关于Fragment的问题,如何处理的

举例:getActivity()空指针:这种状况通常发生在在异步任务里调用getActivity(),而Fragment已经onDetach()。

Fragment 有什么优势, Fragment和View能够相互替换嘛

  1. Fragment为了解决Andriod碎片化而产生的
  2. Fragment和View都有助于界面复用
  3. Fragment的复用粒度更大,包含生命周期和业务逻辑,一般包含好几个View
  4. View一般更关注视图的实现

Fragment add replace 区别

  1. replace 先删除容器中的内容,再添加
  2. add直接添加,能够配合hide适用

参考资料

LearningNotes

40 个 Android 面试题

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

相关文章
相关标签/搜索