Android面试指南(二)————Android基础篇(一)(1),超硬核

本文详细探讨了Android面试中常见的基础知识,包括Activity、Service、Fragment、BroadcastReceiver以及IPC机制的生命周期、交互与优化。还涉及Handler的原理与线程安全问题,分析了不同场景下的最佳实践,旨在帮助读者深入理解Android开发的核心概念和技术要点,为面试做好充分准备。
摘要由CSDN通过智能技术生成

使用FragmentTransaction开启Fragment动画,设置自定义动画切换,进入动画和推出动画

ActivityA跳转到ActivityB,再按back键返回ActivityA,生命周期情况?

ActivityA跳转到ActivityB:onPauseA()----->onCreateB()----->onStartB()----->onResumeB()----->onStopA()

ActivityB按back键返回ActivityA:

onPauseB()----->onRestartA()----->onStartA()----->onResumeA()----->onStopB()----->onDestoryB()

如果ActivityB是窗口Activity呢?

ActivityA跳转到ActivityB:onPauseA()----->onCreateB()----->onStartB()----->onResumeB()

ActivityB按back键返回ActivityA:onPauseB()----->onResumeA()----->onStopB()----->onDestoryB()

Activity的生命周期会受Dialog影响吗?

不会,Activity生命周期不会随Dialog的显示而变化

Activity的生命周期受AMS调用,而dialog不是Activity,所以不受AMS控制,所以不会触发Activity的生命周期

Service

Service有几种创建方式?有什么区别?
  1. startService(),在不需要的时候stopService()
  2. bindService(),与生命周期相绑定,在销毁的时候进行回收unbind()

生命周期

如何理解IntentService?生命周期是什么?HandlerThread 是什么?

intentService继承自Service,持有Service的功能,同时,他是一个处理异步操作的类,当异步执行结束后会自动关闭intentService,多次执行startService(),只是执行onStartCommand方法,将消息加入到消息队列中。

其本质就是启动了一个类似于主线程Handler的机制去维护异步操作。

生命周期:onStartCommand()中执行onStart()方法,在onstart()方法中添加handler.sendMessage()方法

HandlerThread:就是将Handler+looper进行封装,允许直接在子线程中使用handler的一套逻辑。

IntentService更像是一个后台线程,但是他又是一个服务,不容易被回收,这是他的优点

JobIntentService

是IntentService的子类,在android 8.0(26)以上,IntentService的所有后台执行任务都会受到限制约束,所以要使用JobIntentService。

service不能使用后台服务,需要使用ContextCompat.startForegroundService启动前台服务,这样就会启动一个notification,对用户来说体验不是很好,所以就要使用 JobIntentService启动一个后台服务

在使用JobIntentService的时候不需要startService,stopService,在需要的时候调用

DownLoadJobIntentService.enqueueWork(MainActivity.this,DownLoadJobIntentService.class,jobId(8),intent);

而后会执行onHandleWork方法中的逻辑,执行完毕后自动销毁

onStartCommand中三个回调分别是什么?
  • START_NOT_STICKY:Service被回收后不做处理
  • START_STICKY:Service在被回收后,重新创建Service,但是不保存intent
  • START_REDELIVER_INTENT:Service在被回收后,重新创建Service,保存intent
  • START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
Service保活
  1. 设置成前台服务,绑定Notification, startForeground(1, getNotification());
  2. 单独设置为服务进程
  3. onStartCommand返回START_STICKY,START_REDELIVER_INTENT,保证服务被干掉后重启
  4. 在onDestory发送一个广播,广播接收器接收广播后拉起服务
  5. 添加系统广播拉起
  6. 提升服务的优先级

Fragment

生命周期

FragmentPagerAdapter和FragmentStatePagerAdapter的区别?

FragmentPagerAdapter:切换页面只是将Fragment分离,适合Fragment较少的情况不影响内存

FragmentStatePagerAdapter:切换页面将Fragment回收,适合Fragment较多的情况,这样不会消耗太多内存资源

Fragment的3种切换方式
  1. add方法:只是重新回到fragment
  2. replace方法:每次都会重新构建fragment
为什么不能用Fragment的构造函数进行传参?有什么劣势,应该怎么办?为什么?

Fragment在异常崩溃后重建时,默认会调用Fragment无参构造,这样会导致Fragment中的有参构造的值不会被执行,这样数据就会异常

Fragment中调用setArguments来传递参数,在Activity构造Fragment时会通过反射午餐构造实例化一个新的Fragment,并且给mArguments初始化为原先的值

Fragment的重建在那个生命周期中?

在FragmentActivity的onSaveInstanceState中做存储,将Framgent通过序列化Parcelable进行存储,在Activity的onCreate中进行恢复

当配置发生变化时,Activity进入销毁过程,FragmentManager先销毁队列中Fragment的视图,然后检查每个Fragment的retainInstance属性。如果retainInstance为false,FragmentManager会销毁该Fragment实例;如果retainInstance为true,则不会销毁该Fragment实例,Activity重建后,新的FragmentManager会找到保留的Fragment并为其创建视图。

BroadCastReceiver

简述广播的启动方式和区别
  • 静态注册:在AndroidManifest中注册,常驻型广播
  • 动态注册:使用intentFilter过滤广播,registerReceiver注册广播,跟随生命周期

Android8.0以上部分广播不允许静态注册

无序广播和有序广播的区别
  • 无序广播:所有广播接收器都可以获得,不可以拦截,不可以修改
  • 有序广播:按照优先级向下传递,可拦截广播,修改广播
本地广播和全局广播

本地广播接收器只接收本地广播,减少应用外广播干扰,高效 androidx中1.1.0-alpha01中弃用本地广播,官方推荐该用LiveData或响应式流

IPC机制

简述android中的IPC机制

进程间通信

架构:Client/Server架构,Binder机制,之间通过代理接口通信

client,server,serverManager

AndroidManifest中指定Android:process属性

  • 包名:remote为应用私有进程,其他应用不可访问
  • 包名.remote为全局进程,其他应好通过ShareUID可以和他跑在同一个进程

多进程带来的问题:四大组件共享数据失败,每个进程会单独开辟内存空间存储信息

  1. 静态成员和单例模式完全失效
  2. 线程同步机制完全失效
  3. SharedPreferences可靠性下降,不支持多进程
  4. Application会多次创建
Serializable和parcelable区别

serializable:java自带,反射后产生大量临时变量,容易引起gc,主要用于持久化存储和网络传输的序列化

parcelable:android专用,性能强,将完整对象分解为部分对象,每一部分进行intent传输,可用于ipc,内部实现Bundle,主要用于内存的序列化

Android为什么引入Parcelable?
  1. serializable通过反射,性能不好,
  2. serializable反射产生大量临时变量,容易gc,导致内存抖动
  3. serializable使用了大量的IO操作,也影响了耗时

parcelable使用复杂,但高效,适用于内存序列化

Parcelable一定比Serializable快吗?

单论内存中的传输速度,Parcelable一定快于Serializable,但是Parcelable没有缓存的概念 Serializable存在缓存,会将解析过的内容放置在HandleTable,下次解析到同一类型的对象时就可以直接复用

为什么java使用Serializable序列化对象,而不是json或者xml?

因为历史遗留问题,在json和xml出来之前,java已经设计了Serializable,对于Java的庞大体系,并不容易修改这个问题。java官方文档也推荐使用json库,因为他简单、易读、高效

简析Binder机制

在Android通信中并不是所有的进程通信都使用Binder,当fork()进程时,使用的是Socket()通信,因为fork不允许多线程,Binder是多线程模式,所以不被允许

进程空间划分

一个进程空间分为用户空间内核空间

用户空间:数据独享,其他进程无法访问

内核空间:数据共享,其他进程可以访问

所有的进程共用1个内核空间

如何看待ServiceManager?

ServiceManager管理系统中所有的服务,服务需要使用时都要在ServiceManager中进行注册,他的存在类似于DNS,提供client访问某一个服务的查询。

Binder原理

binder驱动属于进程中的内核空间,即共享空间,在client发起请求时,需要将数据从用户空间拷贝到内核空间,binder通过传输内核空间中数据存储的引用映射给服务端,供服务端调用,服务端处理后,将返回值放在内核空间,通过binder传递引用映射给客户端进行处理

img

简述通信流程

总体通信流程就是:

  • 客户端通过代理对象向服务器发送请求。
  • 代理对象通过Binder驱动发送到服务器进程
  • 服务器进程处理请求,并通过Binder驱动返回处理结果给代理对象
  • 代理对象将结果返回给客户端。
详细的通信过程
  • 服务端跨进程的类都要继承Binder类,所以也就是服务端对应的Binder实体。这个类并不是实际真实的远程Binder对象,而是一个Binder引用(即服务端的类引用),会在Binder驱动里还要做一次映射。
  • 客户端要调用远程对象函数时,只需把数据写入到Parcel,在调用所持有的Binder引用的transact()函数
  • transact函数执行过程中会把参数、标识符(标记远程对象及其函数)等数据放入到Client的共享内存,Binder驱动从Client的共享内存中读取数据,根据这些数据找到对应的远程进程的共享内存。
  • 然后把数据拷贝到远程进程的共享内存中,并通知远程进程执行onTransact()函数,这个函数也是属于Binder类。
  • 远程进程Binder对象执行完成后,将得到的写入自己的共享内存中,Binder驱动再将远程进程的共享内存数据拷贝到客户端的共享内存,并唤醒客户端线程。

通过Binder将客户端,服务端的共享内存中的数据进行读写,放入对方的共享内存中,并通知。

Binder在Android中的应用?
  • 系统服务及四大组件的启动调用工作:系统服务是通过getSystemService获取的服务
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值