android 面试题总结

  • 阐述一下 Activity 的生命周期。

创建 onCreate - 启动onStart – 开始 onResume – 暂停 onPause – 结束 onStop – 销毁onDestroy

每一个活动( Activity )都处于某一个状态,对于开发者来说,是无法控制其应用程序处于某一个状态的,这些均由系统来完成。 但是当一个活动的状态发生改变的时候,开发者可以通过调用 onXX() 的方法获取到相关的通知信息。

在实现 Activity 类的时候,通过覆盖( override )这些方法即可在你需要处理的时候来调用。

•onCreate :当活动第一次启动的时候,触发该方法,可以在此时完成活动的初始化工作。 onCreate 方法有一个参数,该参数可以为空( null ),也可以是之前调用 onSaveInstanceState()方法保存的状态信息。

•onStart :该方法的触发表示所属活动将被展现给用户。

•onResume :当一个活动和用户发生交互的时候,触发该方法。

•onPause :当一个正在前台运行的活动因为其他的活动需要前台运行而转入后台运行的时候,触发该方法。这时候需要将活动的状态持久化,比如正在编辑的数据库记录等。

•onStop :当一个活动不再需要展示给用户的时候,触发该方法。如果内存紧张,系统会直接结束这个活动,而不会触发 onStop 方法。 所以保存状态信息是应该在onPause时做,而不是onStop时做。活动如果没有在前台运行,都将被停止或者Linux管理进程为了给新的活动预留足够的存储空间而随时结束这些活动。因此对于开发者来说,在设计应用程序的时候,必须时刻牢记这一原则。在一些情况下,onPause方法或许是活动触发的最后的方法,因此开发者需要在这个时候保存需要保存的信息。

•onRestart :当处于停止状态的活动需要再次展现给用户的时候,触发该方法。

•onDestroy :当活动销毁的时候,触发该方法。和 onStop 方法一样,如果内存紧张,系统会直接结束这个活动而不会触发该方法。

•onSaveInstanceState :系统调用该方法,允许活动保存之前的状态,比如说在一串字符串中的光标所处的位置等。 通常情况下,开发者不需要重写覆盖该方法,在默认的实现中,已经提供了自动保存活动所涉及到的用户界面组件的所有状态信息。

  1. 横竖屏的切换

    在横竖屏切换的过程中,会发生Activity被销毁并被重建的过程。

    在了解这种情况下的生命周期,首先应该了解这两个回调:onSaveInstance State 和 onRestoreInstance State。

    在Activity由于异常情况下终止时,系统会调用 onSaveInstanceState 来保存当前 Activity 的状态。这个方法的调用是在onStop之前,它和onPause没有既定的时序关系,该方法只有在Activity被异常终止的情况下调用。当异常终止的Activity被重建之后,系统会调用onRestoreInstanceState,并且把Activity销毁时onSaveInstanceState方法所保存的Bundle对象参数同时传递给onRestoreInstanceState和onCreate方法。因为,可以通过onRestoreInstanceState方法来恢复Activity的状态,该方法的调用时机是在onStart之后。其中,onCreate和onRestoreInstanceState方法来恢复Activity状态的区别:onRestoreInstanceState回调则表明其中Bundle对象非空,不用加非空判断,而onCreate需要非空判断,建议使用onRestoreInstanceState。

  2. 横竖屏切换的生命周期:onPause() --> onSaveInstanceState() --> onStop() --> onDestory() --> onCreate() --> onStart() --> onRestoreInstanceState() --> onResume() 

    可以通过在AndroidManifest文件的Activity中指定如下属性:

    android:configChanges = "orientation| screenSize"

    来避免横竖屏切换时,Activity的销毁和重建,而是回调了下面的方法:  

  3.  @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
        }

  4. 2.资源内存不足导致优先级低的Activity被杀死

  5. 优先级:前台Activity > 可见但非前台Activity > 后台Activity

  6. 启动模式:

  7. Android 提供了四种Activity启动方式:

    标准模式:standard

    栈顶复用模式:singleTop

    栈内复用模式:singleTask

    单例模式:singleInstance

  8. 标准模式 standard

    每启动一次Activity,就会创建一个新的Activity实例并置于栈顶。谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈中。

    特殊情况下,如果在Service或Application中启动一个Activity,其并没有所谓的任务栈,可以使用标记位Flag来解决。解决办法:为待启动的Activity指定FLAG_ACTIVITY_NEW_TASK标记位,创建一个新栈。

  9. 栈顶复用模式 singleTop

    如果需要新建的Activity位于任务栈栈顶,那么此Activity的实例就不会重建,而是复用栈顶的实例。并回调:

  10.     @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
        }

  11. 由于不会重建一个Activity实例,则不会回调其他生命周期方法。

    应用场景:在通知栏点击收到的通知,然后需要启动一个Activity,这个Activity就可以用singleTop,否则每次点击都会新建一个Activity。

  12. 栈内复用模式 singleTask

    该模式是一种单例模式,即一个栈内只有一个该Activity实例。该模式,可以通过在AndroidManifest文件的Activity中指定该Activity需要加载到哪个栈中,即singleTask的Activity可以指定想要加载的目标栈。singleTask和taskAffinity配合使用,指定开启的Activity加入到哪个栈中。

  13. <activity android:name=".Activity1"
        android:launchMode="singleTask"
        android:taskAffinity="com.lvr.task"
        android:label="@string/app_name">
    </activity>

  14. 关于taskAffinity的值:每个Activity都有taskAffinify属性,这个属性指出了它希望进入的Task。如果一个Activity没有显式的指明该Activity的taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,如果Application也没有指明,那么该taskAffinity的值就等于包名。

    执行逻辑:

    在这种模式下,如果Activity指定的栈不存在,则创建一个栈,并把创建的Activity压入栈内。如果Activity指定的栈存在,如果其中没有该Activity实例,则会创建Activity并压入栈顶,如果其中有该Activity实例,则把该Activity实例之上的Activity杀死清除出战,重用并让该Activity实例处在栈顶,然后调用onNewIntent()方法。

    应用场景:

    在大多数App的主页,对于大部分应用,当我们在主界面点击返回按钮都是退出应用,那么当我们第一次进入主界面之后,主界面位于栈底,以后不管我们打开了多少个Activity,只要我们再次回到主界面,都应该使用将主界面Activity上所有的Activity移除的方式来让主界面Activity处于栈顶,而不是往栈顶新加一个主界面Activity的实例,通过这种方式能够保证退出应用时所有的Activity都能被销毁。

  15. 单例模式 singleInstance

    作为栈内复用的加强版,打开该Activity时,直接创建一个新的任务栈,并创建该Activity实例放入栈中。一旦该模式的Activity实例已经存在于某个栈中,任何应用在激活该Activity时都会重用该栈中的实例。

    应用场景:呼叫来电界面

  16. 调用SingleTask模式的后台任务栈的Activity,会把整个栈的Activity压入当前栈的栈顶。singleTask会具有clearTop特性,会把之上的栈内Activity清除。

  17. Activity的Flags:

  18. Activity的Flags很多,这里介绍集中常用的,用于设定Activity的启动模式,可以在启动Activity时,通过Intent.addFlags()方法设置。

  19. FLAG_ACTIVITY_NEW_TASK 即 singleTask
  20. FLAG_ACTIVITY_SINGLE_TOP 即 singleTop
  21. FLAG_ACTIVITY_CLEAR_TOP 当他启动时,在同一个任务栈中所有位于它之上的Activity都要出栈。如果和singleTask模式一起出现,若被启动的Activity已经存在栈中,则清除其之上的Activity,并调用该Activity的onNewIntent方法。如果被启动的Activity采用standard模式,那么该Activity连同之上的所有Activity出栈,然后创建新的Activity实例并压入栈中。

Activity的启动过程

 应用启动过程

  1. Launcher通过Binder进程间通信机制通知AMS,它要启动一个Activity
  2. AMS通过Binder进程间通信机制通知Launcher进入Paused状态
  3. Launcher通过Binder进程间通信机制通知AMS,它已经准备就绪进入Paused状态,于是AMS就创建一个新的线程,用来启动一个ActivityThread实例,即将要启动的Activity就是在这个ActivityThread实例中运行
  4. ActivityThread通过Binder进程间通信机制将一个ApplicationThread类型的Binder对象传递给AMS,以便以后AMS能够通过这个Binder对象和它进行通信
  5. AMS通过Binde进程间通信机制通知ActivityThread,现在一切准备就绪,它可以真正执行Activity的启动操作了

Service

是Android中实现程序后台运行的解决方案,它非常适用于去执行那些不需要和用户交互而且还要长期运行的任务。Service默认并不会运行在子线程中,它也不运行在一个独立的进程中,它同样执行在UI线程中,因此,不要在Service中执行耗时的操作,因此,不要在Service中执行耗时的操作,除非你在Service中创建了子线程来完成耗时操作。

Service生命周期

startService() --> onCreate() --> onStartCommand() --> Service running --> onDestory()

bindService() --> onCreate() --> onBind() --> Service running --> onUnbind() --> onDestory()

onCreate():

系统在Service第一次创建时执行此方法,来执行只运行一次的初始化工作,如果service已经运行,这个方法不会调用。

onStartCommand():

每次客户端调用startService()方法启动该Service都会回调该方法(多次调用),一旦这个方法执行,service就启动并且在后台长期运行,通过调用stopSelf()或stopService()来停止服务。

onBind():

当组件调用bindService()想要绑定到service时,系统调用此方法(一次调用),一旦绑定后,下次在调用bindService()不会回调该方法。在你的实现中,你必须提供一个返回一个IBinder来使客户端能够使用它与service通讯,你必须总是实现这个方法,但是如果你不允许绑定,那么你应返回null

onUnbind():

当前组件调用unbindService(),想要解除与service的绑定时系统调用此方法(一次调用,一旦解除绑定后,下次再调用unbindService()会抛异常)

onDestory():

系统在service不在被使用并且要销毁的时候调用此方法(一次调用)。service应在此方法中释放资源,比如线程,已注册的监听器、接收器等等。

三种情况下Service的生命周期
  1. startService / stopService

    生命周期:onCreate --> onStartCommand --> onDestory

    如果一个Service被某个Activity调用Context.startService 方法启动,那么不管是否有Activity使用bindService绑定或unbindService解除绑定到该Service,该Service都在后台运行,直到被调用stopService,或自身的stopSelf方法。当然如果系统资源不足,Android系统也可能结束服务,还有一种方法可以关闭服务,在设置中,通过应用 --> 找到自己应用 --> 停止。

    注意:

    第一次startService会触发onCreate和onStartCommand,以后在服务运行过程中,每次startService都只会触发onStartCommand

    不论startService多少次,stopService一次就会停止服务

  2. bindService / unbindService

    生命周期:onCreate --> onBind --> onUnbind --> onDestory

    如果一个Service在某个Activity中被调用bindService方法启动,不论bindService被调用几次,Service的onCreate方法只会执行一次,同时onStartCommand方法始终不会调用。

    当建立连接后,Service会一直运行,除非调用unbindService来解除绑定、断开连接或调用该Service的Context不存在了(如Activity被finish --- 即通过bindService启动的Service的生命周期依附于启动它的Context),系统会在这时候自动停止该Service。

    注意:

    第一次bindService会触发onCreate和inBind,以后在服务运行过程中,每次bindService都不会触发任何回调

  3. 混合型

    当一个Service再被启动(startService)的同时又被绑定(bindService),该Service将会一直在后台运行,不管调用几次,onCreate方法始终只会调用一次,onStartCommand的调用次数与startService调用的次数一致(使用bindService方法不会调用onStartCommand)。同时,调用unBindService将不会停止Service,必须调用stopService或Service自身的stopSelf来停止服务。

BroadcastReceiver 

广播接收器

作用:用于监听 / 接收 应用发出的广播消息,并作出响应

应用场景:

  1. 不同组件之间的通信(包括应用内 / 不同应用之间)
  2. 与Android系统在特定情况下的通信,如当电话呼入时,网络可用时
  3. 多线程通信
实现原理
  • 使用了观察者模式:基于消息的发布/订阅事件模型。

  • 模型中有三个角色:消息订阅者(广播接收者)、消息发布者(广播发布者)和消息中心(AMS,即Activity Manager Service)

  • 原理描述

    1. 广播接收者通过Binder机制在AMS注册
    2. 广播发送者通过Binder机制向AMS发送广播
    3. AMS根据广播发送者要求,在已注册列表中,寻找合适的广播接收者,寻找依据:IntentFilter / Permission
    4. AMS将广播发送到合适的广播接收者相应的消息循环队列
    5. 广播接收者通过消息循环拿到此广播,并回调onReceive()

    注意:广播发送者和广播接收者的执行是异步的,发出去的广播不会关心有没有接收者接收,也不确定接收者何时能接受到。

自定义广播接收者BroadcastReceiver
  • 继承至BroadcastReceiver基类

  • 重写onReceiver()方法

    广播接收器收到相应广播后,会自动回调onReceiver()方法;一般情况下,onReceiver方法会涉及与其他组件之间的交互,如发送Notification、启动service等等;默认情况下,广播接收器运行在UI线程,因此onReceiver方法不能执行耗时操作,否则可能ANR

广播接收器注册

注册方式分为两种:静态注册和动态注册。

注意:

动态广播最好在Activity的onResume()注册,onPause()注销,否则会导致内存泄漏,当然,重复注册和重复注销也不允许。

广播发送者向AMS发送广播
广播的发送
  • 广播是用意图(Intent)标识
  • 定义广播的本质:定义广播所具备的意图(Intent)
  • 广播发送:广播发送者将此广播的意图通过sendBroadcast()方法发送出去
广播的类型

广播的类型主要分为5类:

  • 普通广播(Normal Broadcast)
  • 系统广播(System Broadcast)
  • 有序广播(Ordered Broadcast)
  • 粘性广播(Sticky Broadcast)
  • App应用内广播(Local Broadcast)

普通广播:

即开发者自身定义Intent的广播(最常用),发送广播使用如下:


Intent intent = new Intent();
//对应BroadcastReceiver中intentFilter的action
intent.setAction(BROADCAST_ACTION);
//发送广播
sendBroadcast(intent);

若被注册了的广播接收者中注册时IntentFilter的action与上述匹配,则会接收此广播(即进行回调onReceiver()),如下mBroadcastReceiver则会接收上述广播:

<receiver 
    //此广播接收者类是mBroadcastReceiver
    android:name=".mBroadcastReceiver" >
    //用于接收网络状态改变时发出的广播
    <intent-filter>
        <action android:name="BROADCAST_ACTION" />
    </intent-filter>
</receiver>

APP应用内广播

 

原理

ContentProvider的底层采用Android中的Binder机制

具体使用

  • 若发送广播有相应权限,那么广播接收者也需要相应权限

  • 有序广播
  • 定义:发送出去的广播被接收者按照先后顺序接收,有序是针对广播接收者而言的
  • 广播接收者接收广播的顺序规则(同时面向静态和动态注册的广播接收者)
    • 按照Priority属性值从大到小排序
    • Priority属性相同者,动态注册的广播优先
  • Android中的广播可以跨App直接通信(exported对于有intent-filter情况下默认为true)

  • 冲突可能出现的问题:

    • 其他App针对性发出与当前App intent-filter 相匹配的广播,由此导致当前App不断接收广播并处理;
    • 其他App注册与当前App一致的intent-filter用于接收广播,获取广播具体信息。即会出现安全性&效率性的问题
  • 解决方案 使用App应用内广播(Local Broadcast)

    • App应用内广播可以理解为一种局部广播,广播的发送者和接收者都同属于一个App
    • 相比于全局广播(普通广播),App应用内广播优势体现在:安全性高 & 效率高
  • 具体使用1 将全局广播设置成局部广播

    • 注册广播时将exported属性设置为false,使得非本App内部发出的此广播不被接受
    • 在广播发送和接收时,增设相应权限permission,用于权限验证
    • 发送广播时指定该广播接收器所在的包名,此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中,通过intent.setPackage(packageName)指定包名
  • 具体使用2 使用封装好的LocalBroadcastManager类

    使用方式上与全局广播几乎相同,只是注册 / 取消注册广播接收器和发送广播时将参数的context变成了LocalBroadcastManager的单一实例

    注:对于LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册,不能静态注册。

    • 特点:
      • 接收广播按顺序接收
      • 先接收的广播接收者可以对广播进行截断,即后接收的广播接收者不在接收到此广播
      • 先接收的广播接收者可以对广播进行修改,那么后接收的广播接收者将接收到被修改后的广播
    • 具体使用有序广播的使用过程和普通广播非常类似,差异仅在于广播的发送方式:sendOrderedBroadcast(intent);
    • //注册应用内广播接收器
      //步骤1:实例化BroadcastReceiver子类 & IntentFilter mBroadcastReceiver 
      mBroadcastReceiver = new mBroadcastReceiver(); 
      IntentFilter intentFilter = new IntentFilter(); 

      //步骤2:实例化LocalBroadcastManager的实例
      localBroadcastManager = LocalBroadcastManager.getInstance(this);

      //步骤3:设置接收广播的类型 
      intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);

      //步骤4:调用LocalBroadcastManager单一实例的registerReceiver()方法进行动态注册 
      localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);

      //取消注册应用内广播接收器
      localBroadcastManager.unregisterReceiver(mBroadcastReceiver);

      //发送应用内广播
      Intent intent = new Intent();
      intent.setAction(BROADCAST_ACTION);
      localBroadcastManager.sendBroadcast(intent);

    • ContentProvider

      内容提供者

      作用

      进程间进行数据交互&共享,即跨进程通信

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值