手机版
网站地图
美文美图
最新动态
你好,欢迎访问
好美文阅读网
个性皮肤
搜索
网站首页
美文
文章
散文
日记
诗歌
小说
故事
句子
作文
签名
祝福语
情书
范文
读后感
文学百科
美文摘抄
节日文章
名家散文
网名大全
座右铭
口号大全
面试技巧
说说大全
阅读答案
诗词默写
流言蜚语
节日祝福
好句子
经典台词
谚语大全
亲情故事
友情故事
表白情书
工作报告
活动总结
心得体会
专题汇总
美文网首页
Android 面试题集 包含答案
Android 面试题集 包含答案
作者:
ZhouWG
| 来源:发表于
2018-04-26 17:20 被阅读0次
1、Activity如何与Service通信?
可以通过bindService的方式,先在Activity里实现一个ServiceConnection接口,并将该接口传递给bindService()方法,在ServiceConnection接口的onServiceConnected()方法里执行相关操作。
2、Service的生命周期与启动方法有什么区别?
startService():开启Service,调用者退出后Service仍然存在。
bindService():开启Service,调用者退出后Service也随即退出。
3、Service生命周期:
用startService()启动服务:onCreate() -> onStartCommand() -> onDestory
用bindService()绑定服务:onCreate() -> onBind() -> onUnBind() -> onDestory
同时使用startService()启动服务与bindService()绑定服务:onCreate() -> onStartCommnad() -> onBind() -> onUnBind() -> onDestory
4、广播分为哪几种,应用场景是什么?
普通广播:调用sendBroadcast()发送,最常用的广播。
有序广播:调用sendOrderedBroadcast(),发出去的广播会被广播接受者按照顺序接收,广播接收者按照Priority属性值从大-小排序,Priority属性相同者,动态注册的广播优先,广播接收者还可以选择对广播进行截断和修改。
5、广播的两种注册方式有什么区别?
静态注册:常驻系统,不受组件生命周期影响,即便应用退出,广播还是可以被接收,耗电、占内存。
动态注册:非常驻,跟随组件的生命变化,组件结束,广播结束。在组件结束前,需要先移除广播,否则容易造成内存泄漏。
6、广播发送和接收的原理了解吗?
1继承BroadcastReceiver,重写onReceive()方法。
2通过Binder机制向ActivityManagerService注册广播。
3通过Binder机制向ActivityMangerService发送广播。
4ActivityManagerService查找符合相应条件的广播(IntentFilter/Permission)的BroadcastReceiver,将广播发送到BroadcastReceiver所在的消息队列中。
5BroadcastReceiver所在消息队列拿到此广播后,回调它的onReceive()方法。
7、ContentProvider、ContentResolver与ContentObserver之间的关系是什么?
ContentProvider:管理数据,提供数据的增删改查操作,数据源可以是数据库、文件、XML、网络等,ContentProvider为这些数据的访问提供了统一的接口,可以用来做进程间数据共享。
ContentResolver:ContentResolver可以不同URI操作不同的ContentProvider中的数据,外部进程可以通过ContentResolver与ContentProvider进行交互。ContentObserver:观察ContentProvider中的数据变化,并将变化通知给外界。
8、遇到过哪些关于Fragment的问题,如何处理的?
getActivity()空指针:这种情况一般发生在在异步任务里调用getActivity(),而Fragment已经onDetach(),此时就会有空指针,解决方案是在Fragment里使用一个全局变量mActivity,在onAttach()方法里赋值,这样可能会引起内存泄漏,但是异步任务没有停止的情况下本身就已经可能内存泄漏,相比直接crash,这种方式显得更妥当一些。
Fragment视图重叠:在类onCreate()的方法加载Fragment,并且没有判断saveInstanceState==null或if(findFragmentByTag(mFragmentTag) == null),导致重复加载了同一个Fragment导致重叠。(PS:replace情况下,如果没有加入回退栈,则不判断也不会造成重叠,但建议还是统一判断下)
9、Android里的Intent传递的数据有大小限制吗,如何解决?
Intent传递数据大小的限制大概在1M左右,超过这个限制就会静默崩溃。处理方式如下:
进程内:EventBus,文件缓存、磁盘缓存。
10、描述一下Android的事件分发机制?
1Android事件分发机制的本质:事件从哪个对象发出,经过哪些对象,最终由哪个对象处理了该事件。此处对象指的是Activity、Window与View。
2Android事件的分发顺序:Activity(Window) -> ViewGroup -> View
11、描述一下View的绘制原理?
View的绘制流程主要分为三步:
1onMeasure:测量视图的大小,从顶层父View到子View递归调用measure()方法,measure()调用onMeasure()方法,onMeasure()方法完成绘制工作。
2onLayout:确定视图的位置,从顶层父View到子View递归调用layout()方法,父View将上一步measure()方法得到的子View的布局大小和布局参数,将子View放在合适的位置上。
3onDraw:绘制最终的视图,首先ViewRoot创建一个Canvas对象,然后调用onDraw()方法进行绘制。onDraw()方法的绘制流程为:① 绘制视图背景。② 绘制画布的图层。 ③ 绘制View内容。④ 绘制子视图,如果有的话。⑤ 还原图层。⑥ 绘制滚动条。
12、requestLayout()、invalidate()与postInvalidate()有什么区别?
requestLayout():该方法会递归调用父窗口的requestLayout()方法,直到触发ViewRootImpl的performTraversals()方法,此时mLayoutRequestede为true,会触发onMesaure()与onLayout()方法,不一定会触发onDraw()方法。
invalidate():该方法递归调用父View的invalidateChildInParent()方法,直到调用ViewRootImpl的invalidateChildInParent()方法,最终触发ViewRootImpl的performTraversals()方法,此时mLayoutRequestede为false,不会触发onMesaure()与onLayout()方法,当时会触发onDraw()方法。
postInvalidate():该方法功能和invalidate()一样,只是它可以在非UI线程中调用。
一般说来需要重新布局就调用requestLayout()方法,需要重新绘制就调用invalidate()方法。
13、了解APK的打包流程吗,描述一下?
Android的包文件APK分为两个部分:代码和资源,所以打包方面也分为资源打包和代码打包两个方面,这篇文章就来分析资源和代码的编译打包原理
APK整体的的打包流程如下图所示:
具体说来:
(1)通过AAPT工具进行资源文件(包括AndroidManifest.xml、布局文件、各种xml资源等)的打包,生成R.java文件。
(2)通过AIDL工具处理AIDL文件,生成相应的Java文件。
(3)通过Javac工具编译项目源码,生成Class文件。
(4)通过DX工具将所有的Class文件转换成DEX文件,该过程主要完成Java字节码转换成Dalvik字节码,压缩常量池以及清除冗余信息等工作。
(5)通过ApkBuilder工具将资源文件、DEX文件打包生成APK文件。
(6)利用KeyStore对生成的APK文件进行签名。
(7)如果是正式版的APK,还会利用ZipAlign工具进行对齐处理,对齐的过程就是将APK文件中所有的资源文件举例文件的起始距离都偏移4字节的整数倍,这样通过内存映射访问APK文件的速度会更快。
14、了解APK的安装流程吗,描述一下?
复制APK到/data/app目录下,解压并扫描安装包。
(1)资源管理器解析APK里的资源文件。
(2) 解析AndroidManifest文件,并在/data/data/目录下创建对应的应用数据目录。
(3) 然后对dex文件进行优化,并保存在dalvik-cache目录下。
(4) 将AndroidManifest文件解析出的四大组件信息注册到PackageManagerService中。
(5) 安装完成后,发送广播。
14、当点击一个应用图标以后,都发生了什么,描述一下这个过程?
点击应用图标后会去启动应用的LauncherActivity,如果LancerActivity所在的进程没有创建,还会创建新进程,整体的流程就是一个Activity的启动流程。
15、BroadcastReceiver与LocalBroadcastReceiver有什么区别?
BroadcastReceiver 是跨应用广播,利用Binder机制实现。
LocalBroadcastReceiver 是应用内广播,利用Handler实现,利用了IntentFilter的match功能,提供消息的发布与接收功能,实现应用内通信,效率比较高。
16、Android Handler机制是做什么的,原理了解吗?
主要涉及的角色如下所示:
Message:消息,分为硬件产生的消息(例如:按钮、触摸)和软件产生的消息。
MessageQueue:消息队列,主要用来向消息池添加消息和取走消息。
Looper:消息循环器,主要用来把消息分发给相应的处理者。
Handler:消息处理器,主要向消息队列发送各种消息以及处理各种消息。
整个消息的循环流程还是比较清晰的,具体说来:
(1)Handler通过sendMessage()发送消息Message到消息队列MessageQueue。
(2)Looper通过loop()不断提取触发条件的Message,并将Message交给对应的target handler来处理。
(3)target handler调用自身的handleMessage()方法来处理Message。
事实上,在整个消息循环的流程中,并不只有Java层参与,很多重要的工作都是在C++层来完成的。我们来看下这些类的调用关系。
17、Android Binder机制是做什么的,为什么选用Binder,原理了解吗?
Android Binder是用来做进程通信的,Android的各个应用以及系统服务都运行在独立的进程中,它们的通信都依赖于Binder。
为什么选用Binder,在讨论这个问题之前,我们知道Android也是基于Linux内核,Linux现有的进程通信手段有以下几种:
管道:在创建时分配一个page大小的内存,缓存区大小比较有限;
消息队列:信息复制两次,额外的CPU消耗;不合适频繁或信息量大的通信;
共享内存:无须复制,共享缓冲区直接付附加到进程虚拟地址空间,速度快;但进程间的同步问题操作系统无法实现,必须各进程利用同步工具解决;
套接字:作为更通用的接口,传输效率低,主要用于不通机器或跨网络的通信;
信号量:常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
6. 信号: 不适用于信息交换,更适用于进程中断控制,比如非法内存访问,杀死某个进程等;
既然有现有的IPC方式,为什么重新设计一套Binder机制呢。主要是出于以上三个方面的考量:
高性能:从数据拷贝次数来看Binder只需要进行一次内存拷贝,而管道、消息队列、Socket都需要两次,共享内存不需要拷贝,Binder的性能仅次于共享内存。
稳定性:上面说到共享内存的性能优于Binder,那为什么不适用共享内存呢,因为共享内存需要处理并发同步问题,控制负责,容易出现死锁和资源竞争,稳定性较差。而Binder基于C/S架构,客户端与服务端彼此独立,稳定性较好。
安全性:我们知道Android为每个应用分配了UID,用来作为鉴别进程的重要标志,Android内部也依赖这个UID进行权限管理,包括6.0以前的固定权限和6.0以后的动态权限,传统IPC只能由用户在数据包里填入UID/PID,这个标记完全是在用户空间控制的,没有放在内核空间,因此有被恶意篡改的可能,因此Binder的安全性更高。
18、描述一下Activity的生命周期,这些生命周期是如何管理的?
19、Activity的通信方式有哪些?
(1)startActivityForResult
(2)EventBus
(3)LocalBroadcastReceiver
20、Android应用里有几种Context对象?
实际的功能,Activity、Service与Application都直接或者间接的继承ContextWrapper。
21、描述一下进程和Application的生命周期?
22、Android哪些情况会导致内存泄漏,如何分析内存泄漏?
(1)持有静态的Context(Activity)引用。
(2)持有静态的View引用,
(3)内部类&匿名内部类实例无法释放(有延迟时间等等),而内部类又持有外部类的强引用,导致外部类无法释放,这种匿名内部类常见于监听器、Handler、Thread、TimerTask
(4)资源使用完成后没有关闭,例如:BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap。
(5)不正确的单例模式,比如单例持有Activity。
(6)集合类内存泄漏,如果一个集合类是静态的(缓存HashMap),只有添加方法,没有对应的删除方法,会导致引用无法被释放,引发内存泄漏。
(7)错误的覆写了finalize()方法,finalize()方法执行不确定,可能会导致引用无法被释放。
查找内存泄漏可以使用Android Profiler工具或者利用LeakCanary工具。
23、Android有哪几种进程,是如何管理的?
Android的进程主要分为以下几种:
(1)前台进程
用户当前操作所必需的进程。如果一个进程满足以下任一条件,即视为前台进程:
托管用户正在交互的 Activity(已调用 Activity 的 onResume() 方法)
托管某个 Service,后者绑定到用户正在交互的 Activity
托管正在“前台”运行的 Service(服务已调用 startForeground())
托管正执行一个生命周期回调的 Service(onCreate()、onStart() 或 onDestroy())
托管正执行其 onReceive() 方法的 BroadcastReceiver
通常,在任意给定时间前台进程都为数不多。只有在内存不足以支持它们同时继续运行这一万不得已的情况下,系统才会终止它们。 此时,设备往往已达到内存分页状态,因此需要终止一些前台进程来确保用户界面正常响应。
(2)可见进程
没有任何前台组件、但仍会影响用户在屏幕上所见内容的进程。 如果一个进程满足以下任一条件,即视为可见进程:
托管不在前台、但仍对用户可见的 Activity(已调用其 onPause() 方法)。例如,如果前台 Activity 启动了一个对话框,允许在其后显示上一 Activity,则有可能会发生这种情况。
托管绑定到可见(或前台)Activity 的 Service。
可见进程被视为是极其重要的进程,除非为了维持所有前台进程同时运行而必须终止,否则系统不会终止这些进程。
(3)服务进程
正在运行已使用 startService() 方法启动的服务且不属于上述两个更高类别进程的进程。尽管服务进程与用户所见内容没有直接关联,但是它们通常在执行一些用户关心的操作(例如,在后台播放音乐或从网络下载数据)。因此,除非内存不足以维持所有前台进程和可见进程同时运行,否则系统会让服务进程保持运行状态。
(4)后台进程
包含目前对用户不可见的 Activity 的进程(已调用 Activity 的 onStop() 方法)。这些进程对用户体验没有直接影响,系统可能随时终止它们,以回收内存供前台进程、可见进程或服务进程使用。 通常会有很多后台进程在运行,因此它们会保存在 LRU (最近最少使用)列表中,以确保包含用户最近查看的 Activity 的进程最后一个被终止。如果某个 Activity 正确实现了生命周期方法,并保存了其当前状态,则终止其进程不会对用户体验产生明显影响,因为当用户导航回该 Activity 时,Activity 会恢复其所有可见状态。
(5)空进程
不含任何活动应用组件的进程。保留这种进程的的唯一目的是用作缓存,以缩短下次在其中运行组件所需的启动时间。 为使总体系统资源在进程缓存和底层内核缓存之间保持平衡,系统往往会终止这些进程。
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升级?
数据库升级增加表和删除表都不涉及数据迁移,但是修改表涉及到对原有数据进行迁移。升级的方法如下所示:
(1)将现有表命名为临时表。
(2)创建新表。
(3)将临时表的数据导入新表。
(4)删除临时表。
如果是跨版本数据库升级,可以由两种方式,如下所示:
(1)逐级升级,确定相邻版本与现在版本的差别,V1升级到V2,V2升级到V3,依次类推。
(2)跨级升级,确定每个版本与现在数据库的差别,为每个case编写专门升级大代码。
26、进程保护如何做,如何唤醒其他进程?
进程保活主要有两个思路:
(1)提升进程的优先级,降低进程被杀死的概率。
(2)拉活已经被杀死的进程。
如何提升优先级,如下所示:
监控手机锁屏事件,在屏幕锁屏时启动一个像素的Activity,在用户解锁时将Activity销毁掉,前台Activity可以将进程变成前台进程,优先级升级到最高。
如果拉活
利用广播拉活Activity。
27、理解序列化吗,Android为什么引入Parcelable?
所谓序列化就是将对象变成二进制流,便于存储和传输。
Serializable是java实现的一套序列化方式,可能会触发频繁的IO操作,效率比较低,适合将对象存储到磁盘上的情况。
Parcelable是Android提供一套序列化机制,它将序列化后的字节流写入到一个共性内存中,其他对象可以从这块共享内存中读出字节流,并反序列化成对象。因此效率比较高,适合在对象间或者进程间传递信息。
28、如何计算一个Bitmap占用内存的大小,怎么保证加载Bitmap不产生内存溢出?
Bitamp 占用内存大小 = 宽度像素 x (inTargetDensity / inDensity) x 高度像素 x (inTargetDensity / inDensity)x 一个像素所占的内存.
在Bitmap里有两个获取内存占用大小的方法。
getByteCount():API12 加入,代表存储 Bitmap 的像素需要的最少内存。
getAllocationByteCount():API19 加入,代表在内存中为 Bitmap 分配的内存大小,代替了 getByteCount() 方法。
在不复用 Bitmap 时,getByteCount() 和 getAllocationByteCount 返回的结果是一样的。在通过复用 Bitmap 来解码图片时,那么 getByteCount() 表示新解码图片占用内存的大小,getAllocationByteCount() 表示被复用 Bitmap真实占用的内存大小(即 mBuffer 的长度)。
为了保证在加载Bitmap的时候不产生内存溢出,可以受用BitmapFactory进行图片压缩,主要有以下几个参数:
BitmapFactory.Options.inPreferredConfig:将ARGB_8888改为RGB_565,改变编码方式,节约内存。
BitmapFactory.Options.inSampleSize:缩放比例,可以参考Luban那个库,根据图片宽高计算出合适的缩放比例。
BitmapFactory.Options.inPurgeable:让系统可以内存不足时回收内存。
Android如何在不压缩的情况下加载高清大图?
使用BitmapRegionDecoder进行布局加载。
29、Android里的内存缓存和磁盘缓存是怎么实现的?
内存缓存基于LruCache实现,磁盘缓存基于DiskLruCache实现。这两个类都基于Lru算法和LinkedHashMap来实现。
LRU算法可以用一句话来描述,如下所示:
LRU是Least Recently Used的缩写,最近最久未使用算法,从它的名字就可以看出,它的核心原则是如果一个数据在最近一段时间没有使用到,那么它在将来被访问到的可能性也很小,则这类数据项会被优先淘汰掉。
LruCache的原理是利用LinkedHashMap持有对象的强引用,按照Lru算法进行对象淘汰。具体说来假设我们从表尾访问数据,在表头删除数据,当访问的数据项在链表中存在时,则将该数据项移动到表尾,否则在表尾新建一个数据项。当链表容量超过一定阈值,则移除表头的数据。
为什么会选择LinkedHashMap呢?
这跟LinkedHashMap的特性有关,LinkedHashMap的构造函数里有个布尔参数accessOrder,当它为true时,LinkedHashMap会以访问顺序为序排列元素,否则以插入顺序为序排序元素。
30、PathClassLoader与DexClassLoader有什么区别?
PathClassLoader:只能加载已经安装到Android系统的APK文件,即/data/app目录,Android默认的类加载器。
DexClassLoader:可以加载任意目录下的dex、jar、apk、zip文件。
31、WebView优化了解吗,如何提高WebView的加载速度?
为什么WebView加载会慢呢?
这是因为在客户端中,加载H5页面之前,需要先初始化WebView,在WebView完全初始化完成之前,后续的界面加载过程都是被阻塞的。
优化手段围绕着以下两个点进行:
预加载WebView。
加载WebView的同时,请求H5页面数据。
因此常见的方法是:
全局WebView。
客户端代理页面请求。WebView初始化完成后向客户端请求数据。
asset存放离线包。
除此之外还有一些其他的优化手段:
脚本执行慢,可以让脚本最后运行,不阻塞页面解析。
DNS与链接慢,可以让客户端复用使用的域名与链接。
React框架代码执行慢,可以将这部分代码拆分出来,提前进行解析。
32、Java和JS的相互调用怎么实现,有做过什么优化吗?
jockeyjs:https://github.com/tcoulter/jockeyjs
对协议进行统一的封装和处理。
33、JNI了解吗,Java与C++如何相互调用?
Java调用C++
在Java中声明Native方法(即需要调用的本地方法)
编译上述 Java源文件javac(得到 .class文件)
通过 javah 命令导出JNI的头文件(.h文件)
使用 Java需要交互的本地代码 实现在 Java中声明的Native方法
编译.so库文件
通过Java命令执行 Java程序,最终实现Java调用本地代码
C++调用Java
从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象。
获取类的默认构造方法ID。
查找实例方法的ID。
创建该类的实例。
调用对象的实例方法。
JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessMethod_callJavaInstaceMethod (JNIEnv *env, jclass cls) {
jclass clazz = NULL;
jobject jobj = NULL;
jmethodID mid_construct = NULL;
jmethodID mid_instance = NULL;
jstring str_arg = NULL;
// 1、从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象
clazz = (*env)->FindClass(env, "com/study/jnilearn/ClassMethod");
if (clazz == NULL) {
printf("找不到'com.study.jnilearn.ClassMethod'这个类");
return;
}
// 2、获取类的默认构造方法ID
mid_construct = (*env)->GetMethodID(env,clazz, "","()V");
if (mid_construct == NULL) {
printf("找不到默认的构造方法");
return;
}
// 3、查找实例方法的ID
mid_instance = (*env)->GetMethodID(env, clazz, "callInstanceMethod", "(Ljava/lang/String;I)V");
if (mid_instance == NULL) {
return;
}
// 4、创建该类的实例
jobj = (*env)->NewObject(env,clazz,mid_construct);
if (jobj == NULL) {
printf("在com.study.jnilearn.ClassMethod类中找不到callInstanceMethod方法"); return;
}
// 5、调用对象的实例方法
str_arg = (*env)->NewStringUTF(env,"我是实例方法");
(*env)->CallVoidMethod(env,jobj,mid_instance,str_arg,200);
// 删除局部引用
(*env)->DeleteLocalRef(env,clazz);
(*env)->DeleteLocalRef(env,jobj);
(*env)->DeleteLocalRef(env,str_arg);
}
相关文章
网友评论
本文标题:
Android 面试题集 包含答案
本文链接:
https://www.haomeiwen.com/subject/eohylftx.html
延伸阅读
那年盛夏诗歌
环境监察队工作总结范文
优秀教师学习心得范文
华胥引的读后感300字
《Its red》教学反思范文
农资购销的合同范本
竞选中队委优秀演讲稿
辞金蹈海的成语解释
《世纪宝鼎》公开课教案设计
因为爱你,所以牵挂
今生今世红尘醉——美到
一个90后的内心独白
致已逝去的高中年华
深度阅读
您也可以注册成为美文阅读网的作者,发表您的原创作品、分享您的心情!
情人节
母亲节
重阳节
清明节
端午节
植树节
元宵节
妇女节
愚人节
圣诞节
父亲节
教师节
儿童节
劳动节
青年节
建军节
万圣节
平安夜
光棍节
中秋节
国庆节
感恩节
腊八节
更多话题
栏目导航
摄影
故事
互联网
读书
旅行
热点阅读
#新中式宠妈艺术#妈妈,谢谢你给我的那份安全感!
ARC梳理
2018-04-25-(GTF文件各列含义 )
玄学之路
我的母亲
花期
代码回滚:简述git reset --hard xxx 、git
睁大你的眼第二季 两把刀 四十一章 教授出山
你是否诚实?
怨归
网友评论