Android面试基础(一)
in Android with 0 comment

四大组件

Activity

生命周期

生命周期

生命周期衍生

  1. onSaveInstanceState 调用时机

在onStop()方法回调之前,系统会自动调用onSaveInstanceState(Bundle outState)
该方法用于存储当前Activity状态,并在onCreate时拿到之前保存的数据

  1. onSaveInstanceState 使用场景

    1. 存储数据为bundle,一定是可序列化的数据
    2. 页面被异常销毁,需要存储之前显示状态
    3. 如屏幕旋转,切换深色模式都会导致页面重建,保存用户当前浏览状态可以提高用户体验
  2. 页面旋转不重建页面

配置的变化都会导致页面重建,如果想要在配置发生变化时不重建页面,可进行如下设置

  1. manifest增加权限

<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />

  1. activity 增加状态监听

android:configChanges="orientation|keyboard"

  1. onConfigurationChanged回调中处理变化的属性

  2. 开源库 LifeCycle

https://www.jianshu.com/p/1ae41dc6c828

Activity启动模式

4个启动模式

  1. manifest中配置
  2. intent添加flag
    1. FLAG_ACTIVITY_CLEAR_TOP -> singleTask
    2. FLAG_ACTIVITY_SINGLE_TOP -> singleTop
    3. FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS -> android:excludeFromRecents="true" 不会出现在最近任务

taskAffinity

可以为activity指定存放的堆栈名,只和singleTask启动模式共同使用
不可声明为包名,因为默认堆栈名为包名

Activity 打开方式

显式启动
指定包名类名启动,常见于应用内部页面间跳转
隐式启动
声明action,category

Activity启动流程(重要)

https://www.jianshu.com/p/56023d8902ee
时序图已经比较细致,过一遍文章然后看时序图即可
image.png

Service

启动方式

image.png

进程保活

1px大小Activity

监听系统广播,锁屏时启动一个1px大小的页面放置左上角,亮屏时关闭。背景透明,无启动动画。

前台服务

ContentProvider

BroadcastReceiver

注册方式

静态注册

Manifest中声明,接收广播的优先级低,在无序广播时,晚于动态注册。

新特性:Android8.0以后静态注册的广播无法通过隐式的方式调用,必须指定包名

动态注册

Java代码中实例化一个Receiver,通过registerReceiver的方式注册

广播类型

默认广播(无序)

context.sendBroadcast方法发送广播,每个接受者都可以收到广播,互相无影响,接受者无法中止广播。

有序广播

context.sendOrderedBroadcast 发送广播,接受者需要定义优先级,传递从高优先级传递至低优先级,高优先级有能力中止传送
应用场景:辣鸡短信拦截。

View

Fragment

生命周期

使用

Fragment fragment1 = new Fragment1();
getFragmentManager().beginTransaction().replace(R.id.main_layout,fragment1).commit();
  1. 获取FragmentManager
  2. 开启一个事物,可以通过beginTransaction() 方法获取
  3. 加入fragment,一般通过replace实现
  4. 提交事物commit

数据通信

Arguments(Bundle)

延伸

replace/add/remove

replace :直接替换
add/remove:可以一直往里添加,不可重复添加
共同点
replace/add 时都会走生命周期
差异点
每次replace都要走生命周期,add时走了一次之后,后面可以通过show/hide方法动态控制Fragment的显示,此时不会再重走生命周期

应用于ViewPager

多tab页面一般基于ViewPager去做,ViewPager不仅可以展示图片,简单布局等,也可以展示Fragment

FragmentPagerAdapter与FragmentStatePagerAdapter的区别

  1. 所有add进来的Fragment都是visible的,需要手动控制show hide

如果仅add去覆盖,会导致点击事件的透传

  1. 为了节省内存提高展示效率,一般使用add添加

    ListView

    使用

    缺陷

作用:作用几乎很小,低版本的Android 在首次刷新界面的时候可能会重复的onLayout,不同sdk的首次渲染到屏幕上的onLayout次数是不同的,所以一级缓存是复用界面上已有的View,避免首次重复onLayout

2.复用划出界面的View避免重复的绑定(findViewById)

ScrapViews数组列表(二维)

通过ViewType找到被缓存的View,重新加载数据

ListView的RecycleBin对应RecyclerView的Recycler

使用

RecyclerView

使用

LayoutManager

Animator

Adapter

遇过的坑(面试可以装逼用)

  1. getItemId(int position)

这个id应当是独一无二的
在做删除动画时,出现remove+notifyRangeChanged时闪退,报下标越界的问题,识别item的唯一标识就是通过这个id判断

四级缓存

各级缓存意义的区别:
一级缓存:意义是为了重新更新界面上已有的UI(与复用无关)
二三四级缓存:复用UI

两种缓存类型

Scrap (view):在布局期间进入临时分离状态的子视图。指那些连数据都不需要改变的ViewHolder (第一级缓存)
Recycle (view):先前用于显示适配器特定位置的数据的视图可以放置在高速缓存中以供稍后重用再次显示相同类型的数据。这可以通过跳过初始布局或构造来显着提高性能。类型相同的ViewHolder (其他级缓存)
image.png
一级缓存:mAttachedScrap 和 mChangedScrap ,用来缓存还在屏幕内的 ViewHolder(实际上不是缓存,只是暂存,就是在一次界面的重新布局的时候暂存View,onLayout结束的时候即使有没复用到的View也会从mAttachedScrap中移除到RecycledViewPool中)
mAttachedScrap 存储的是当前还在屏幕中的 ViewHolder;按照 id 和 position 来查找 ViewHolder
mChangedScrap 表示数据已经改变的 ViewHolder 列表, 存储 notifyXXX 方法时需要改变的 ViewHolder
一般调用adapter的notifyItemRangeChanged被移除的viewholder会保存到mChangedScrap,其余的notify系列方法 (不包括notifyDataSetChanged)移除的viewholder会被保存到mAttachedScrap中

二级缓存:mCachedViews ,用来缓存移除屏幕之外的 ViewHolder,默认情况下缓存容量是 2,可以通过 setViewCacheSize 方法来改变缓存的容量大小。如果 mCachedViews 的容量已满,则会根据 FIFO 的规则移除旧 ViewHolder,这里被复用的View不会触发onBindViewHolder
三级缓存(可略):ViewCacheExtension ,开发给用户的自定义扩展缓存,需要用户自己管理 View 的创建和缓存。个人感觉这个拓展脱离了 Adapter.createViewHolder 使用的话会造成 View 创建 与 数据绑定及其它代码太分散,不利于维护,使用场景很少仅做了解
四级缓存:RecycledViewPool ,ViewHolder 缓存池,在有限的 mCachedViews 中如果存不下新的 ViewHolder 时,就会把 ViewHolder 存入RecyclerViewPool 中。

ConstraintLayout

特色

优点

基础Layout

  1. FrameLayout
  2. LinearLayout
  3. RelativeLayout
Responses