面试题学习与复习一(1),2024年最新kotlin协程代码

只是用bindService()绑定服务:onCreate() -> onBind() -> onUnBind() -> onDestory

同时使用startService()启动服务与bindService()绑定服务:onCreate() -> onStartCommnad() -> onBind() -> onUnBind() -> onDestory

3、广播分为哪几种,应用场景是什么?

==================

普通广播:调用sendBroadcast()发送,最常用的广播。

有序广播:调用sendOrderedBroadcast(),发出去的广播会被广播接受者按照顺序接收,广播接收者按照Priority属性值从大-小排序,Priority属性相同者,动态注册的广播优先,广播接收者还可以选择对广播进行截断和修改。

4、广播的两种注册方式有什么区别?

=================

静态注册:常驻系统,不受组件生命周期影响,即便应用退出,广播还是可以被接收,耗电、占内存。

动态注册:非常驻,跟随组件的生命变化,组件结束,广播结束。在组件结束前,需要先移除广播,否则容易造成内存泄漏。

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

================

继承BroadcastReceiver,重写onReceive()方法。

通过Binder机制向ActivityManagerService注册广播。

通过Binder机制向ActivityMangerService发送广播。

ActivityManagerService查找符合相应条件的广播(IntentFilter/Permission)的BroadcastReceiver,将广播发送到BroadcastReceiver所在的消息队列中。

BroadcastReceiver所在消息队列拿到此广播后,回调它的onReceive()方法。

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

==========================================================

ContentProvider的简单使用

ContentProvider:管理数据,提供数据的增删改查操作,数据源可以是数据库、文件、XML、网络等,ContentProvider为这些数据的访问提供了统一的接口,可以用来做进程间数据共享。

ContentResolver:ContentResolver可以不同URI操作不同的ContentProvider中的数据,外部进程可以通过ContentResolver与ContentProvider进行交互。

ContentObserver:观察ContentProvider中的数据变化,并将变化通知给外界。

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

===========================

getActivity()空指针:这种情况一般发生在在异步任务里调用getActivity(),而Fragment已经onDetach(),此时就会有空指针,解决方案是在Fragment里使用

一个全局变量mActivity,在onAttach()方法里赋值,这样可能会引起内存泄漏,但是异步任务没有停止的情况下本身就已经可能内存泄漏,相比直接crash,这种方式

显得更妥当一些。

Fragment视图重叠:在类onCreate()的方法加载Fragment,并且没有判断saveInstanceState==null或if(findFragmentByTag(mFragmentTag) == null),

导致重复加载了同一个Fragment导致重叠。(PS:replace情况下,如果没有加入回退栈,则不判断也不会造成重叠,但建议还是统一判断下)

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

// 在页面重启时,Fragment会被保存恢复,而此时再加载Fragment会重复加载,导致重叠 ;

if(saveInstanceState == null){

// 或者 if(findFragmentByTag(mFragmentTag) == null)

// 正常情况下去 加载根Fragment

}

}

8、Android里的Intent传递的数据有大小限制吗,如何解决?

==================================

Intent传递数据大小的限制大概在1M左右,超过这个限制就会静默崩溃。处理方式如下:

进程内:EventBus,文件缓存、磁盘缓存。

进程间:通过ContentProvider进行款进程数据共享和传递。

9、描述一下Android的事件分发机制?

=====================

面试题八:事件分发机制

Android事件分发机制的本质:事件从哪个对象发出,经过哪些对象,最终由哪个对象处理了该事件。此处对象指的是Activity、Window与View。

Android事件的分发顺序:Activity(Window) -> ViewGroup -> View

Android事件的分发主要由三个方法来完成,如下所示:

// 父View调用dispatchTouchEvent()开始分发事件

public boolean dispatchTouchEvent(MotionEvent event){

boolean consume = false;

// 父View决定是否拦截事件

if(onInterceptTouchEvent(event)){

// 父View调用onTouchEvent(event)消费事件,如果该方法返回true,表示

// 该View消费了该事件,后续该事件序列的事件(Down、Move、Up)将不会再传递

// 给其他View。

consume = onTouchEvent(event);

}else{

// 调用子View的dispatchTouchEvent(event)方法继续分发事件

consume = child.dispatchTouchEvent(event);

}

return consume;

}

10、描述一下View的绘制原理?

=================

View的绘制流程主要分为三步:

onMeasure:测量视图的大小,从顶层父View到子View递归调用measure()方法,measure()调用onMeasure()方法,onMeasure()方法完成绘制工作。

onLayout:确定视图的位置,从顶层父View到子View递归调用layout()方法,父View将上一步measure()方法得到的子View的布局大小和布局参数,将子View放在合适的位置上。

onDraw:绘制最终的视图,首先ViewRoot创建一个Canvas对象,然后调用onDraw()方法进行绘制。onDraw()方法的绘制流程为:① 绘制视图背景。② 绘制画布的图层。 ③ 绘制View内容。④ 绘制子视图,如果有的话。⑤ 还原图层。⑥ 绘制滚动条。

11、了解APK的打包流程吗,描述一下?

====================

Android的包文件APK分为两个部分:代码和资源,所以打包方面也分为资源打包和代码打包两个方面,这篇文章就来分析资源和代码的编译打包原理。

具体说来:

a、通过AAPT工具进行资源文件(包括AndroidManifest.xml、布局文件、各种xml资源等)的打包,生成R.java文件。

b、通过AIDL工具处理AIDL文件,生成相应的Java文件。

c、通过Javac工具编译项目源码,生成Class文件。

d、通过DX工具将所有的Class文件转换成DEX文件,该过程主要完成Java字节码转换成Dalvik字节码,压缩常量池以及清除冗余信息等工作。

e、通过ApkBuilder工具将资源文件、DEX文件打包生成APK文件。

f、利用KeyStore对生成的APK文件进行签名。

g、如果是正式版的APK,还会利用ZipAlign工具进行对齐处理,对齐的过程就是将APK文件中所有的资源文件举例文件的起始距离都偏移4字节的整数倍,这样通过内存映射访问APK文件

的速度会更快。

12、了解APK的安装流程吗,描述一下?

====================

a、复制APK到/data/app目录下,解压并扫描安装包。

b、资源管理器解析APK里的资源文件。

c、解析AndroidManifest文件,并在/data/data/目录下创建对应的应用数据目录。

d、然后对dex文件进行优化,并保存在dalvik-cache目录下。

e、将AndroidManifest文件解析出的四大组件信息注册到PackageManagerService中。

f、安装完成后,发送广播。

13、当点击一个应用图标以后,都发生了什么,描述一下这个过程?

===============================

  • a、点击桌面应用图标,Launcher进程将启动Activity(MainActivity)的请求以Binder的方式发送给了AMS。

  • b、AMS接收到启动请求后,交付ActivityStarter处理Intent和Flag等信息,然后再交给ActivityStackSupervisior/ActivityStack处理Activity进栈相关流程。同时以Socket方式请求Zygote进程fork新进程。

  • c、Zygote接收到新进程创建请求后fork出新进程。

  • d、在新进程里创建ActivityThread对象,新创建的进程就是应用的主线程,在主线程里开启Looper消息循环,开始处理创建Activity。

  • e、ActivityThread利用ClassLoader去加载Activity、创建Activity实例,并回调Activity的onCreate()方法。这样便完成了Activity的启动。

15、BroadcastReceiver与LocalBroadcastReceiver有什么区别?

=================================================

BroadcastReceiver 是跨应用广播,利用Binder机制实现。

LocalBroadcastReceiver 是应用内广播,利用Handler实现,利用了IntentFilter的match功能,提供消息的发布与接收功能,

实现应用内通信,效率比较高。

16、Android Handler机制是做什么的,原理了解吗?

================================

主要涉及的角色如下所示:

Message:消息,分为硬件产生的消息(例如:按钮、触摸)和软件产生的消息。

MessageQueue:消息队列,主要用来向消息池添加消息和取走消息。

Looper:消息循环器,主要用来把消息分发给相应的处理者。

Handler:消息处理器,主要向消息队列发送各种消息以及处理各种消息。

整个消息的循环流程还是比较清晰的,具体说来:

Handler通过sendMessage()发送消息Message到消息队列MessageQueue。

Looper通过loop()不断提取触发条件的Message,并将Message交给对应的target handler来处理。

target handler调用自身的handleMessage()方法来处理Message。

17、Android Binder机制是做什么的,为什么选用Binder,原理了解吗?

===========================================

Linux进程通信的几种方式总结

Android Binder是用来做进程通信的,Android的各个应用以及系统服务都运行在独立的进程中,它们的通信都依赖于Binder。

为什么选用Binder,在讨论这个问题之前,我们知道Android也是基于Linux内核,Linux现有的进程通信手段有以下几种:

1、管道(pipe);2、消息队列;3、共享内存;4、套接字;5、信号量(semophore );6、信号(signal)

既然有现有的IPC方式,为什么重新设计一套Binder机制呢。主要是出于以上三个方面的考量:

高性能:从数据拷贝次数来看Binder只需要进行一次内存拷贝,而管道、消息队列、Socket都需要两次,共享内存不需要拷贝,

Binder的性能仅次于共享内存。

稳定性:上面说到共享内存的性能优于Binder,那为什么不适用共享内存呢,因为共享内存需要处理并发同步问题,控制负责,

容易出现死锁和资源竞争,稳定性较差。而Binder基于C/S架构,客户端与服务端彼此独立,稳定性较好。

安全性:我们知道Android为每个应用分配了UID,用来作为鉴别进程的重要标志,Android内部也依赖这个UID进行权限管理,

包括6.0以前的固定权限和6.0以后的动态权限,传统IPC只能由用户在数据包里填入UID/PID,这个标记完全

是在用户空间控制的,没有放在内核空间,因此有被恶意篡改的可能,因此Binder的安全性更高。

18、描述一下Activity的生命周期,这些生命周期是如何管理的?

==================================

源码分析:Activity生命周期调用顺序(一)

用startActivity的方式启动要给activity的流程是这样的:

a、startActivity内部调用startActivityForResult,以binder方式通知AMS;

b、AMS先保存信息,然后对当前系统栈顶的Activity执行onPause操作;

c、AMS会判断需要启动的Activity所属的应用进程是否已经启动,若没有则以socket方式通知Zygote进程fork新进程;

d、Zygote进程收到请求后,fork新进程;

e、在新进程里创建activitythread对象,在其main方法里开启looper消息循环,开始处理创建activity

f、Activitythread利用classloader加载activity,创建activity实例,并回调activity的oncreate方法,

这样就完成了activity的创建。

19、Activity的通信方式有哪些?

====================

startActivityForResult、LocalBroadcastReceiver、EventBus

20、Android应用里有几种Context对象?

==========================

Android——context理解

在应用程序中Context的具体实现子类就是:Activity,Service,Application。

那么Context数量=Activity数量+Service数量+1。

Broadcast Receiver,Content Provider并不是Context的子类,

他们所持有的Context都是其他地方传过去的,所以并不计入Context总数。

22、Android哪些情况会导致内存泄漏,如何分析内存泄漏?

===============================

常见的产生内存泄漏的情况如下所示:

持有静态的Context(Activity)引用。

持有静态的View引用,

内部类&匿名内部类实例无法释放(有延迟时间等等),而内部类又持有外部类的强引用,导致外部类无法释放,这种匿名内部类常见于监听器、Handler、Thread、TimerTask

资源使用完成后没有关闭,例如:BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap。

不正确的单例模式,比如单例持有Activity。

集合类内存泄漏,如果一个集合类是静态的(缓存HashMap),只有添加方法,没有对应的删除方法,会导致引用无法被释放,引发内存泄漏。

错误的覆写了finalize()方法,finalize()方法执行执行不确定,可能会导致引用无法被释放。

查找内存泄漏可以使用Android Profiler工具或者利用LeakCanary工具。

23、Android有哪几种进程,是如何管理的?

========================

前台进程、可见进程、服务进程、后台进程、空进程

24、SharePreference性能优化,可以做进程同步吗?

================================

在Android中, SharePreferences是一个轻量级的存储类,特别适合用于保存软件配置参数。使用SharedPreferences保存数据,其背后是用xml文件存放数据,文件存放在/data/data/ < package name > /shared_prefs目录下.

之所以说SharedPreference是一种轻量级的存储方式,是因为它在创建的时候会把整个文件全部加载进内存,如果SharedPreference文件比较大,会带来以下问题:

  • 第一次从sp中获取值的时候,有可能阻塞主线程,使界面卡顿、掉帧。

  • 解析sp的时候会产生大量的临时对象,导致频繁GC,引起界面卡顿。

  • 这些key和value会永远存在于内存之中,占用大量内存。

优化建议

不要存放大的key和value,会引起界面卡、频繁GC、占用内存等等。

毫不相关的配置项就不要放在在一起,文件越大读取越慢。

读取频繁的key和不易变动的key尽量不要放在一起,影响速度,如果整个文件很小,那么忽略吧,为了这点性能添加维护成本得不偿失。

不要乱edit和apply,尽量批量修改一次提交,多次apply会阻塞主线程。

尽量不要存放JSON和HTML,这种场景请直接使用JSON。

SharedPreference无法进行跨进程通信,MODE_MULTI_PROCESS只是保证了在API 11以前的系统上,如果sp已经被读取进内存,再次获取这个SharedPreference的时候,如果有这个flag,会重新读一遍文件,仅此而已。

25、如何做SQLite升级?

===============

数据库升级增加表和删除表都不涉及数据迁移,但是修改表涉及到对原有数据进行迁移。升级的方法如下所示:

将现有表命名为临时表。

创建新表。

将临时表的数据导入新表。

删除临时表。

如果是跨版本数据库升级,可以由两种方式,如下所示:

逐级升级,确定相邻版本与现在版本的差别,V1升级到V2,V2升级到V3,依次类推。

跨级升级,确定每个版本与现在数据库的差别,为每个case编写专门升级大代码。

26、进程保护如何做,如何唤醒其他进程?

====================

进程保活主要有两个思路:

提升进程的优先级,降低进程被杀死的概率。

拉活已经被杀死的进程。

如何提升优先级,如下所示:

监控手机锁屏事件,在屏幕锁屏时启动一个像素的Activity,在用户解锁时将Activity销毁掉,前台Activity可以将进程变成前台进程,优先级升级到最高。

如果拉活

利用广播拉活Activity。

27、理解序列化吗,Android为什么引入Parcelable?

=================================

所谓序列化就是将对象变成二进制流,便于存储和传输。

Serializable是java实现的一套序列化方式,可能会触发频繁的IO操作,效率比较低,适合将对象存储到磁盘上的情况。

Parcelable是Android提供一套序列化机制,它将序列化后的字节流写入到一个共性内存中,其他对象可以从这块共享内存中读出字节流,并反序列化成对象。因此效率比较高,适合在对象间或者进程间传递信息。

28、Android如何在不压缩的情况下加载高清大图?‘

============================

使用BitmapRegionDecoder进行布局加载。

29、Android里的内存缓存和磁盘缓存是怎么实现的?

============================

内存缓存基于LruCache实现,磁盘缓存基于DiskLruCache实现。这两个类都基于Lru算法和LinkedHashMap来实现。

LRU算法可以用一句话来描述,如下所示:

LRU是Least Recently Used的缩写,最近最久未使用算法,从它的名字就可以看出,它的核心原则是如果一个数据在最近一段时间没有使用到,那么它在将来被

访问到的可能性也很小,则这类数据项会被优先淘汰掉。

LruCache的原理是利用LinkedHashMap持有对象的强引用,按照Lru算法进行对象淘汰。具体说来假设我们从表尾访问数据,在表头删除数据,当访问的数据项在链表中存在时,则将该数据项移动到表尾,否则在表尾新建一个数据项。当链表容量超过一定阈值,则移除表头的数据。

30、为什么会选择LinkedHashMap呢?

========================

这跟LinkedHashMap的特性有关,LinkedHashMap的构造函数里有个布尔参数accessOrder,当它为true时,LinkedHashMap会以访问顺序为序排列元素,否则以插入顺序为序排序元素。

DiskLruCache与LruCache原理相似,只是多了一个journal文件来做磁盘文件的管理和迎神,如下所示:

libcore.io.DiskLruCache

1

1

1

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

总结

现在新技术层出不穷,如果每次出新的技术,我们都深入的研究的话,很容易分散精力。新的技术可能很久之后我们才会在工作中用得上,当学的新技术无法学以致用,很容易被我们遗忘,到最后真的需要使用的时候,又要从头来过(虽然上手会更快)。

我觉得身为技术人,针对新技术应该是持拥抱态度的,入了这一行你就应该知道这是一个活到老学到老的行业,所以面对新技术,不要抵触,拥抱变化就好了。

Flutter 明显是一种全新的技术,而对于这个新技术在发布之初,花一个月的时间学习它,成本确实过高。但是周末花一天时间体验一下它的开发流程,了解一下它的优缺点、能干什么或者不能干什么。这个时间,并不是我们不能接受的。

如果有时间,其实通读一遍 Flutter 的文档,是最全面的一次对 Flutter 的了解过程。但是如果我们只有 8 小时的时间,我希望能关注一些最值得关注的点。

(跨平台开发(Flutter)、java基础与原理,自定义view、NDK、架构设计、性能优化、完整商业项目开发等)

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img
们才会在工作中用得上,当学的新技术无法学以致用,很容易被我们遗忘,到最后真的需要使用的时候,又要从头来过(虽然上手会更快)。

我觉得身为技术人,针对新技术应该是持拥抱态度的,入了这一行你就应该知道这是一个活到老学到老的行业,所以面对新技术,不要抵触,拥抱变化就好了。

Flutter 明显是一种全新的技术,而对于这个新技术在发布之初,花一个月的时间学习它,成本确实过高。但是周末花一天时间体验一下它的开发流程,了解一下它的优缺点、能干什么或者不能干什么。这个时间,并不是我们不能接受的。

如果有时间,其实通读一遍 Flutter 的文档,是最全面的一次对 Flutter 的了解过程。但是如果我们只有 8 小时的时间,我希望能关注一些最值得关注的点。

(跨平台开发(Flutter)、java基础与原理,自定义view、NDK、架构设计、性能优化、完整商业项目开发等)

[外链图片转存中…(img-TyUTRDFJ-1712779866459)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-g1UKGM4C-1712779866459)]

  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值