Android面试复习(Android篇一)

1. 四大组件

  1. 活动
  2. 服务
  3. 内容提供器
  4. 广播接收器

2. 活动

2.1 启动模式

1 standard
每次启动一个Activity都会创建一个新的实例,不管这个实例是否存在。
2 singleTop
栈顶复用。如果Activity已经位于栈顶,那么此Activity不会被重新创建,如果Activity已存在但不在栈顶,那么新的Activity会被重新创建。
3 singleTask
栈内复用。这是一种单例模式。只要Activity在一个栈内已存在,就不会创建新的实例。
首先查看Activity想要的任务栈是否存在,如果不存在就重新创建一个任务栈,然后创建该Activity实例并放入新栈中。如果存在Activity想要的任务栈。看该Activity是否在栈中存在实例,如果存在,则将该实例上面所有的Activity出栈。
4 singleInstance
单例模式。具有此种模式的Activity创建一个单独的任务栈。除非该任务栈被销毁,否则不会重新创建该Activity。

2.2 Activity的Flags

  1. FLAG_ACTIVITY_NEW_TASK:这个标记作用是为Activity指定“singleTask”启动模式,其效果和在XML中指定该启动模式相同。
  2. FLAG_ACTIVITY_SINGLE_TOP:这个标记位作用是为Activity指定“singleTop”启动模式,其效果和在XML中指定该启动模式相同。
  3. FLAG_ACTIVITY_CLEAR_TOP:具有此标记的Activity,当它启动时,在同一个任务栈中所有位于它上面的Activity都要出栈。这个标记一般会和singleTask启动模式一起出现,在这种情况下,被启动Activity的实例如果已经存在,那么系统会调用它的onNewIntent。如果被启动的Activity采用standard模式启动,那么它连同它之上的Activity都要出栈,系统会创建新的Activity实例,并放入栈顶。singleTask默认就具有此标记效果。
  4. FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有这个标记的Activity不会出现在历史Activity的列表中,当某些情况下,我们不希望用户通过历史列表回到我们的Activity的时候这个标记比较有用。它等同于在XML中指定Activity的属性:android:excudeFromRecents=”true”

2.3 IntentFilter的匹配规则

只有action类别、category类别和data类别同时匹配,才能成功启动Activity。另外,一个Activity可用有多个intent-filter,一个Intent只要能匹配任何一组intent-filter即可成功启动对应的Activity。

2.3.1 Activity中Intent Filter 的匹配过程

加载所有的Intent Filter列表
去掉action匹配失败的Intent Filter
去掉url匹配失败的Intent Filter
去掉Category匹配失败的Intent Filter
判断剩下的Intent Filter数目是否为0。如果为0查找失败返回异常;如果大于0,就按优先级排序,返回最高优先级的Intent Filter

2.3.2 action匹配规则

至少要有一个action与之相同

2.3.3 category匹配规则

必须为其子集。
注意,系统在调用startActivity或startActivityForResult的时候,会默认给Intent加上“android.intent.category.DEFAULT”这个category,所以,为了我们的Activity能接收隐式调用,必须在intent-filter中加“android.intent.category.DEFAULT”这个category。

2.3.4 data匹配规则

至少有一个data与之相同

2.4Activity与Fragment生命周期

  1. Activity生命周期
    注意Activity有七个生命周期,除了onRestart()别的一一对应
  2. Fragment生命周期
  3. 两者之间的对比
    Activity与Fragment主要差别在于create与Destroy阶段不同

2.5Activity状态保存

Activity状态保存也就是异常情况下的生命周期有两种情况一就是系统资源配置文件发生改变二就是当内存不足是也会出现异常情况下的生命周期。

  • 情况1:资源相关的系统配置发生改变导致activity被杀死并重新创建
    比如说当前activity处于竖屏状态,如果突然旋转屏幕,由于系统配置发生了改变,在默认情况下,activity就会被销毁并且重新创建,当然我们也可以组织系统重新创建我们的activity。activity被销毁要用onSaveInstanceState,这个发生在onStop()之前与onPause()没有明确的时序关系。后来要恢复activity。要使用onRestoreInstanceState().发生在onStart()之后

  • 情况2:内存不足导致低优先级的activity被杀死。
    1)前台activity—正在和用户交互的activity,优先级最高
    (2)可见但非前台activity—比如activity中弹出了一个对话框,导致activity可见但是位于后台无法和用户直接交互。
    (3)后台activity—已经被暂停的activity,比如执行了onStop,优先级最低。

2.5.1 什么时候onSaveInstanceState被调用

注意上面的双引号,何为“即将”?言下之意就是该Activity还没有被销毁,而仅仅是一种可能性。这种可能性有哪些?通过重写一个Activity的所有生命周期的onXXX方法,包括onSaveInstanceState和onRestoreInstanceState方法,我们可以清楚地知道当某个Activity(假定为Activity A)显示在当前task的最上层时,以下几种情况会导致onSaveInstanceState方法会被执行:

  1. 当用户按下HOME键时。这是显而易见的,系统不知道你按下HOME后要运行多少其他的程序,自然也不知道Activity A是否会被销毁,故系统会调用onSaveInstanceState,让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则
  2. 长按HOME键,选择运行其他的程序时。
  3. 按下电源按键(关闭屏幕显示)时。
  4. 从Activity A中启动一个新的Activity时。

总而言之,onSaveInstanceState的调用遵循一个重要原则,即当系统“未经你许可”时销毁了你的Activity,则onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然你不保存那就随便你了)。

2.5.2什么时候onRestoreInstanceState被调用

至于onRestoreInstanceState方法,需要注意的是,onSaveInstanceState方法和onRestoreInstanceState方法“不一定”是成对的被调用的,onRestoreInstanceState被调用的前提是,Activity A“确实”被系统销毁了,而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示Activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到Activity A,这种情况下Activity A一般不会因为内存的原因被系统销毁,故Activity A的onRestoreInstanceState方法不会被执行。
另外,onSaveInstanceState的bundle参数也会传递到onCreate方法中,你也可以选择在onCreate方法中做数据还原。

2.5.3各个回调函数执行顺序:

  • onCreate
  • onStart
  • onRestoreInstanceState
  • onResum

2.6Activity卡顿原因

  • 内存泄漏导致内存占用较高,导致JVM频繁触发GC。解决办法:尽可能的减少生命周期长的对象引用生命周期短的对象。导致内存泄漏的原因有以下几个:
    1. 查询数据库后没有关闭游标cursor,各种资源文件没有close。
    2. 构造Adapter时,没有使用convertView重用
    3. Bitmap对象不再使用时没有调用recycle释放内存
    4. 静态变量引用对象,Application引用对象。
    5. Handler造成内存泄漏。new Handler(){};创建Handler的方法会导致Handler对外部类Activity一个引用。而Message会存有对Handler引用,因此,如果Activity退出时这个Message还未处理,就会一直有Activity的引用。解决方法:创建一个Handler子类,而不是直接通过new Handler(){};的方式,在Handler里保持一个对Activity的弱引用。在handleMessage时首先判断引用的Activity不为空。然后具体针对Activity的操作可以通过这个引用的Activity做相应的业务处理。
  • 加载大数据,占用太多内存,同样导致JVM频繁GC。解决办法:主要是Bitmap占用太多内存。可以通过根据需要显示的Bitmap宽高设定采样率来压缩图片。另外,通过采用LRUCache方法避免。如果是其他的大数据比如3D模型数据,可以通过使用Native空间,使用ByteBuffer.allocate(size);
  • UI线程做耗时任务(数据库操作,数据计算等),1秒绘制60帧才不会卡顿,即16.6ms要刷新一次才不会卡顿。解决方法:另起线程做耗时任务。
  • UI OverDraw。
  • 在包含ImageView的ListView中,等滑动停止后加载图片。

2.7如何加速启动Acivity

2.7.1 减少onCreate时间

减少onCreate的时间,那就精简onCreate里的代码。放在onResume里好了。为了用户体验更好一些:

  • 把页面显示的View细分一下,放在AsyncTask里逐步显示,如果你够熟练,用handler更好
  • 这样用户的看到的就是有层次有步骤的一个个的view的展示,不会是先看到一个黑屏,然后一下显示所有view。
  • 最好作成动画,效果更自然些。
  • 利用多线程的目的就是尽可能的减少onCreate和onReume的时间,使得用户能尽快看到页面,操作页面。

   
但是,很多操作是只需要一次初始化的,都放在onResume里每次进入activity都会浪费初始化时间。这个好解决:

  • 定义一个boolean变量
  • 在onCreate里标记为true
  • 在onResume里判断为true就进行初始化,初始化完成立刻置为false。

2.7.2 减小主线程的阻塞时间 

导致ANR时间:

  • 用户无响应5秒
  • 网络和数据库阻塞10秒
  • 广播接收者执行超过10秒会导致ANR
    若一个操作耗时过长(导致ANR),我们应该将其放入后台线程中执行,只在需要修改UI界面时通知主线程进行修改。

2.7.3 提高Adapter和AdapterView的效率

  • 重用已生成过的Item View
  • 添加ViewHolder
  • 缓存Item的数据
  • 分段显示 

2.7.4 优化布局文件

如果我们的布局层次过多,那么在我们用findViewById的时间必然会变多,一个变多可能不要紧,但是有很多调用必然会影响性能。

  • 使用观察布局的工具 Hierarchy Viewer
  • 使用布局优化工具: Layoutopt
  • 优化布局的层次结构,使用include、merge、ViewStub等

更多相关文章

  1. 在Ubuntu中和Android中添加开机自启动的守护进程
  2. Android(安卓)从启动到程序运行发生的事情
  3. Android(安卓)应用初始化及窗体事件的分发
  4. Android启动脚本init.rc
  5. Android(安卓)LayoutInflater原理分析,带你一步步深入了解View(一
  6. Android中包含多个Activity的应用退出按钮实现
  7. 我的android 第36天 -服务--Service
  8. Android的webview研究
  9. Android系统开机启动流程及init进程浅析

随机推荐

  1. Android(安卓)ACTION_TIME_TICK Broadcas
  2. android ril 代码逻辑分析
  3. android 蓝牙功能
  4. Android(安卓)Toast 保持一直显示。
  5. how the Android(安卓)IPC system works
  6. cmd>>android
  7. Android(安卓)Banner 广告条
  8. android startService小例子
  9. android edittext 键盘弹出屏幕自适应
  10. Android(安卓)监听程序的安装、卸载、替