美文网首页
Android常见面试题

Android常见面试题

作者: John_Phil | 来源:发表于2021-07-04 14:26 被阅读0次
    1. ThreadLocal的理解
      可以保证线程的安全。在多个线程共享相同的数据的时候,会为每个线程创建单独的副本,在单独的副本上进行数据的操作,不会对其它线程的数据产生影响,保证了线程安全。

    2. HashMap HashSet HashTable的区别?
      都是集合,底层都是Hash算法实现的。HashMap是Hashtable的替代品,这两个都是双列集合,而HashSet是单列集合。HashMap线程不安全、效率高、可以存储null键和null值;Hashtable线程安全,效率低,不可以存储null键和null值。

    3. 如何让HashMap可以线程安全?
      HashMap 在并发执行 put 操作时会引起死循环,导致 CPU 利用率接近100%。因为多线程会导致 HashMap 的 Node 链表形成环形数据结构,一旦形成环形数据结构,Node 的 next 节点永远不为空,就会在获取 Node 时产生死循环。
      使用下面三种替换方式:
      Hashtable
      ConcurrentHashMap
      Synchronized Map

    4. Android对HashMap做了优化后推出的新的容器类是什么?
      SparseArray
      它要比 HashMap 节省内存,某些情况下比HashMap性能更好,按照官方问答的解释,主要是因为SparseArray不需要对key和value进行auto-boxing(将原始类型封装为对象类型,比如把int类型封装成Integer类型),结构比HashMap简单(SparseArray内部主要使用两个一维数组来保存数据,一个用来存key,一个用来存value)不需要额外的额外的数据结构(主要是针对HashMap中的HashMapEntry而言的)。

    5. Java多线程之间如何通信
      等待唤醒机制

    6. 线程池的实现机制
      向线程池提交任务,会依次启动核心线程,如果提交的任务数超过了核心线程数,会将任务保存到阻塞队列中,如果阻塞队列也满了,且继续提交任务,则会创建新线程执行任务,直到任务数达到最大线程数。此时如果再提交任务的话会抛出异常或者直接丢弃任务。通过Executor.execute()无法得到返回值,通过ExecutorService.submit()可以得到返回值。

    7. RxJava中map和flatmap操作符的区别及底层实现
      Map返回的是结果集,flatmap返回的是包含结果集的Observable。Map只能一对一,flatmap可以一对多、多对多。
      RxJava是通过观察者模式实现的。

    8. 对消息机制中Looper的理解
      Looper在消息机制中扮演的角色是创造无限循环从Messagequeue中取得消息然后分发。

    9. 单例模式有哪些实现方式
      饿汉模式(线程安全,调用效率高,但是不能延时加载)
      懒汉模式(线程安全,调用效率不高,但是能延时加载)
      双重检测锁模式(由于JVM底层模型原因,偶尔会出问题,不建议使用)
      静态内部类式(线程安全,调用效率高,可以延时加载)
      枚举类(线程安全,调用效率高,不能延时加载,可以天然的防止反射和反序列化调用)

    10. 通过静态内部类实现单例模式有哪些优点
      线程安全,调用效率高,可以延时加载

    11. synchronized volatile关键字有什么区别?以及还有哪些同样功能的关键字
      (1) volatile是变量修饰符,而synchronized则作用于一段代码或者方法。
      (2) volatile只是在线程内存和main memory(主内存)间同步某个变量的值;而synchronized通过锁定和解锁某个监视器同步所有变量的值。显然synchronized要比volatile消耗更多资源。
      const、final、lock

    12. 界面卡顿的原因有哪些?
      UI线程(main)有耗时操作
      视图渲染时间过长,导致卡顿

    13. 造成OOM/ANR 的原因?
      OOM: (1)不恰当地使用static关键字 (2)内部类对Activity的引用 (3)大量Bitmap的使用会导致程序包运行时的内存消耗变大 (4)游标Cursor对象用完应该及时关闭 (5)加载对象过大 (6)相应资源过多,来不及释放。
      ANR: (1)在5秒内没有响应输入的事件(IO操作耗时、数据库操作复杂耗时、主线程非主线程产生死锁等待、网络加载/图片操作耗时、硬件操作耗时) (2)BroadcastReceiver在10秒内没有执行完毕(Service binder数量达到上限、Service忙导致超时无响应)

    14. Activity与Fragment生命周期有何联系
      在创建的过程中,是Activity带领着Fragment,在销毁的过程中,是Fragment带领着Activity。

    1. Glide三级缓存
      内存缓存,磁盘缓存、网络缓存(由于网络缓存严格来说不算是缓存的一种,故也称为二级缓存)。缓存的资源分为两种:原图(SOURCE)、处理图(RESULT)(默认)。
      内存缓存:默认开启的,可以通过调用skipMemoryCache(true)来设置跳过内存缓存,缓存最大空间:每个进程可用的最大内存*0.4。(低配手机0.33)
      磁盘缓存:分为四种:ALL(缓存原图)、NONE(什么都不缓存)、SOURCE(只缓存原图)、RESULT(之后处理图),通过diskCacheStrategy(DiskCacheStrategy.ALL)来设置,缓存大小250M。

    2. MVC、MVP、MVVM的原理
      (1) MVC,Model View Controller,是软件架构中最常见的一种框架,简单来说就是通过controller的控制去操作model层的数据,并且返回给view层展示。当用户发出事件的时候,view层会发送指令到controller层,接着controller去通知model层更新数据,model层更新完数据以后直接显示在view层上,这就是MVC的工作原理。

    (2) MVP是MVC的演化。MVP的model层相对于MVC是一样的,而activity和fragment不再是controller层,而是纯粹的view层,所有关于用户事件的转发全部交由presenter层处理。presenter层充当了桥梁的作用,用于操作view层发出的事件传递到presenter层中,presenter层去操作model层,并且将数据返回给view层。

    (3) MVVM和MVP的区别貌似不大,只不过是presenter层换成了viewmodel层,还有一点就是view层和viewmodel层是相互绑定的关系,这意味着当你更新viewmodel层的数据的时候,view层会相应的变动ui。

    1. 数据库的操作类型有哪些,如何导入外部数据库?
      (1) 增删改查
      (2) 将外部数据库放在项目的res/raw目录下。因为安卓系统下数据库要放在data/data/packagename/databases的目录下,然后要做的就是将外部数据库导入到该目录下,操作方法是通过FileInputStream读取外部数据库,再用FileOutputStrean把读取到的东西写入到该目录下。

    2. 是否使用过 IntentService,作用是什么, AIDL 解决了什么问题?
      (1) IntentService继承自Service。由于Service运行在主线程,无法进行耗时操作。所以你需要在Service中开启一个子线程,并且在子线程中运行。为了简化这一操作,Android中提供了IntentService来进行这一处理。通过查看IntentService的源码可以看到,在onCreate中,我们开启了一个HandlerThread线程,之后获取HandlerThread线程中的Looper,并通过这个Looper创建了一个Handler。然后在onStart方法中通过这个Handler将intent与startId作为Message的参数进行发送到消息队列中,然后交由Handler中的handleMessage中进行处理。由于在onStart方法是在主线程内运行的,而Handler是通过工作者线程HandlerThread中的Looper创建的。所以也就是在主线程中发送消息,在工作者接收到消息后便可以进行一些耗时的操作。
      (2) 进程间通信

    3. 是否使用过本地广播,和全局广播有什么差别?
      本地广播的数据在本应用范围内传播,不用担心隐私数据泄露的问题。不用担心别的应用伪造广播,造成安全隐患。相比在系统内发送全局广播,它更高效。

    4. Activity、 Window、 View 三者的差别, fragment 的特点?
      (1) Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图) LayoutInflater像剪刀,Xml配置像窗花图纸。
      (2) a. Fragment可以作为Activity界面的一部分组成出现;
      b. 可以在一个Activity中同时出现多个Fragment,并且一个Fragment也可以在多个Activity中使用;
      c. 在Activity运行过程中,可以添加、移除或者替换Fragment;
      d. Fragment可以响应自己的输入事件,并且有自己的生命周期,它们的生命周期会受宿主Activity的生命周期影响。

    5. Handler、 Thread 和 HandlerThread 的差别
      从Android中Thread(java.lang.Thread -> java.lang.Object)描述可以看出,Android的Thread没有对Java的Thread做任何封装,但是Android提供了一个继承自Thread的类HandlerThread(android.os.HandlerThread -> java.lang.Thread),这个类对Java的Thread做了很多便利Android系统的封装。
      android.os.Handler可以通过Looper对象实例化,并运行于另外的线程中,Android提供了让Handler运行于其它线程的线程实现,也是就HandlerThread。HandlerThread对象start后可以获得其Looper对象,并且使用这个Looper对象实例Handler。

    6. 低版本 SDK 实现高版本 api
      自己实现或使用注解@TargetApi annotation

    7. launch mode 应用场景
      (1) standard:标准的启动模式。

    (2) singleTop:单一顶部模式
    如果Activity已经被开启,并且处于任务栈的栈顶,就不会创建新的Activity,而是复用这个已经开启的Activity。
    为了防止出现一些奇怪的用户体验,推荐使用单一顶部模式,整个任务栈可以有多个实例存在.
    应用场景:短信发送界面.

    (3)singletask:单一任务栈
    在整个任务栈里面只允许有一个当前Activity的实例存在
    如果要开启的Activity在任务栈中已经存在,直接复用这个已经存在的Activity,并且把这个Activity上面的所有的其他Activity给清空
    应用场景:如果一个Activity非常消耗内存和cpu资源,建议把这个Activity做成singletask的模式。浏览器的browserActivity

    (4)singleinstance:单一实例.
    整个手机操作系统只有一个实例存在,并且是运行在自己单独的任务栈里面.
    应用场景:通话界面的Activity

    1. touch 事件传递流程
      事件处理包括三种情况,分别为:传递—-dispatchTouchEvent()函数、拦截——onInterceptTouchEvent()函数、消费—-onTouchEvent()函数和OnTouchListener。
      Android事件传递流程:
      (1) 事件都是从Activity.dispatchTouchEvent()开始传递
      (2) 事件由父View传递给子View,ViewGroup可以通过onInterceptTouchEvent()方法对事件拦截,停止其向子view传递
      (3) 如果事件从上往下传递过程中一直没有被停止,且最底层子View没有消费事件,事件会反向往上传递,这时父View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到Activity的onTouchEvent()函数。
      (4) 如果View没有对ACTION_DOWN进行消费,之后的其他事件不会传递过来,也就是说ACTION_DOWN必须返回true,之后的事件才会传递进来
      (5) OnTouchListener优先于onTouchEvent()对事件进行消费

    25.Android性能优化
    一、代码优化
    1.使用AndroidLint分析结果进行相应优化
    2.不使用枚举及IOC框架,反射性能低
    3.常量加static
    4.静态方法
    5.减少不必要的对象、成员变量
    6.尽量使用线程池
    7.适当使用软引用和弱引用
    8.尽量使用静态内部类,避免潜在的内存泄露
    9.图片缓存,采用内存缓存LRUCache和硬盘缓存DiskLRUCache
    10.Bitmap优化,采用适当分辨率大小并及时回收
    二、布局优化
    避免OverDraw过渡绘制
    优化布局层级
    避免嵌套过多无用布局
    当我们在画布局的时候,如果能实现相同的功能,优先考虑相对布局,然后在考虑别的布局,不要用绝对布局。
    使用标签把复杂的界面需要抽取出来
    使用标签,因为它在优化UI结构时起到很重要的作用。目的是通过删减多余或者额外的层级,从而优化整个Android Layout的结构。核心功能就是减少冗余的层次从而达到优化UI的目的!
    ViewStub 是一个隐藏的,不占用内存空间的视图对象,它可以在运行时延迟加载布局资源文件。
    三、ListView和GridView优化
    1.采用ViewHolder复用convertView
    2.避免在getView中执行耗时操作
    3.列表在滑动状态时不加载图片
    4.开启硬件加速

    26.Android内存泄漏
    内存泄漏简单地说就是申请了一块内存空间,使用完毕后没有释放掉。它的一般表现方式是程序运行时间越长,占用内存越多,最终用尽全部内存,整个系统崩溃。由程序申请的一块内存,且没有任何一个指针指向它,那么这块内存就泄露了。可能的原因有:
    1.注册没取消造成内存泄露,如:广播
    2.静态变量持有Activity的引用
    3.单例模式持有Activity的引用
    4.查询数据库后没有关闭游标cursor
    5.构造Adapter时,没有使用 convertView 重用
    6.Bitmap对象不在使用时调用recycle()释放内存
    7.对象被生命周期长的对象引用,如activity被静态集合引用导致activity不能释放
    8.使用Handler造成的内存泄露

    27.程序设计类:
    1.请设计一个点餐系统,实现从网络运用okhttp或原生web请求获得远程服务器信息。本地利用SQLite存储点餐信息,可以在在线或离线情况下可以实现获得历史点餐信息。请写出设计思路,以及运用的技术。
    2.请利用安卓技术设计一个网络app应用管理软件,本地利用SQLite存储应用列表信息存储,可以在在线或离线情况下可以实现获得历史app应用软件信息。可以对本地app应用软件进行权限管理,删除更新等。请写出设计思路,以及运用的技术。

    转载:https://blog.csdn.net/mythmayor/article/details/79959898

    相关文章

      网友评论

          本文标题:Android常见面试题

          本文链接:https://www.haomeiwen.com/subject/pdgmultx.html