Android面试题精选汇总 - Android

文章目录

    • 1、基础
      • 1. 四大组件是什么?
      • 2. Activity 的生命周期?
      • 3. Activity 之间的通信方式?
      • 4. Activity 各种情况下的生命周期?
      • 5. 横竖屏切换时 Activity 的生命周期
      • 6. 前台切换到后台,然后再回到前台时 Activity 的生命周期
      • 7. 弹出 Dialog 的时候按 Home 键时 Activity 的生命周期
      • 8. 两个 Activity 之间跳转时的生命周期
      • 9. 下拉状态栏时 Activity 的生命周期
      • 10. Activity 与 Fragment 之间生命周期比较?
      • 11. Activity 的四种 LaunchMode(启动模式)的区别?
      • 12. Activity 状态保存与恢复?
      • 13. Activity 和 Fragment 之间怎么通信, Fragment 和 Fragment 怎么通信?
      • 14. Service 的生命周期?
      • 15. Service 的启动方式?
      • 16. Service 与 IntentService 的区别?
      • 17. Service 和 Activity 之间的通信方式?
      • 18. 对 ContentProvider 的理解?
      • 19. ContentProvider、ContentResolver、ContentObserver 之间的关系?
      • 20. 对 BroadcastReceiver 的了解?
      • 21. 广播的分类?使用方式和场景?
      • 22. 动态广播和静态广播有什么区别?
      • 23. AlertDialog、popupWindow、Activity 之间的区别?
      • 24. Application 和 Activity 的 Context 之间的区别?
      • 25. Android 动画特性?
      • 26. 请列举 Android 中常见的布局(Layout)类型,并简述其用法,以及排版效率。【猎豹移动】
      • 27. 对 SurfaceView 的了解?
      • 28. Serializable 和 Parcelable 的区别?
      • 29. Android 中数据存储方式有哪些?
      • 30. 数据解析
      • 30. Android 各个版本 API 的区别?
      • 31. 屏幕适配的处理技巧都有哪些?
      • 32. 动态权限适配方案,权限组的概念?
      • 33. 通知适配
      • 34. 自适应图标适配
      • 35. 为什么不能在子线程更新 UI?
      • 36. ListView 图片加载错乱的原理和解决方案?
      • 37. 对 RecycleView 的了解?
      • 38. Recycleview 和 ListView 的区别? 为什么Listview没有废弃?
      • 39. Android Manifest 的作用与理解?
      • 40. 多线程在 Android 中的使用?
      • 41. 区别 Animation 和 Animator 的用法,概述实现原理?【猎豹移动】
      • 42. Webview
    • 2、进阶
      • 1. 画出 Android 的大体架构图
      • 2. 低版本 SDK 如何使用高版本 API?
      • 3. AsyncTask 如何使用?
      • 4. AsyncTask 机制、原理及不足?
      • 6. Handler 机制和底层实现?
      • 7. Handler、Thread、HandlerThread 区别?
      • 8. ThreadLocal 原理、实现及如何保证 Local 属性?
      • 9. 自定义 View 的流程?如何机型适配?
      • 10. 自定义 View 的时怎么获取 View 的大小?
      • 11. View 的绘制流程?
      • 12. 如何理解Activity,View,Window三者之间的关系?
      • 13. View 的事件传递分发机制?
      • 14. requestLayout(),onLayout(),onDraw(),drawChild() 区别与联系?
      • 15. invalidate() 和 postInvalidate() 的区别?
      • 16. 如何计算一个 View 的嵌套层级?
      • 17. 进程和 Application 的生命周期的关系?
      • 18. SparseArray 的实现原理?
      • 1. ContentProvider 是如何实现数据共享的?
      • 1. ContentProvider 的权限管理?
      • 1. Android 系统为什么会设计 ContentProvider?
      • 1. Android 线程有没有上限?
      • 1. 怎么去除重复代码?
      • 1. Android 中开启摄像头的主要流程?
      • 1. 对 Bitmap 对象的了解?
      • 1. 图片加载原理?
      • 1. 图片压缩原理?
      • 1. 图片框架实现原理?LRUCache 原理?
      • 1. EventBus 实现原理?
      • 1. ButterKnife 实现原理?
      • 1. Volley 实现原理?
      • 1. okhttp 实现原理?
      • 1. rxJava 实现原理?
      • 1. Retorfit 实现原理?
      • 1. Dagger2 实现原理?
      • 1. 服务器只提供数据接收接口,在多线程或多进程条件下,如何保证数据的有序到达?
      • 1. SQLite 数据库升级,数据迁移问题?
      • 1. 数据库框架对比和源码分析?
      • 1. CAS介绍,OAuth 授权机制?
      • 1. 谈谈你对安卓签名的理解
      • 1. App 是如何沙箱化,为什么要这么做?
    • 3、混合开发
      • 1. 混合开发的方式?各自优缺点和使用场景?
      • 1. Hybird
      • 1. React Native
      • 1. Weex
      • 1. Flutter
      • 1. Dart
      • 1. 快应用
    • 4、Framework
      • 1. 请介绍一下 NDK?
      • 1. 如何加载 ndk 库?如何在 jni 中注册 native 函数,有几种注册方式?【猎豹移动】
      • 1. 谈谈对进程共享和线程安全的认识?
      • 1. 谈谈对多进程开发的理解以及多进程应用场景?
      • 1. 什么是协程?
      • 1. 逻辑地址与物理地址,为什么使用逻辑地址?
      • 1. Android 为每个应用程序分配的内存大小是多少?
      • 1. 进程保活的方式?
      • 1. 系统启动流程是什么?
      • 1. 一个应用程序安装到手机上的过程发生了什么?
      • 1. App 启动流程,从点击桌面开始(Activity 启动流程)?
      • 1. 什么是 AIDL?解决了什么问题?如何使用?
      • 1. Binder 机制及工作原理?
      • 1. App 中唤醒其他进程的实现方式?
      • 1. Activity、Window、View 三者的关系与区别?
      • 1. ApplicationContext 和 ActivityContext 的区别?
      • 1. ActivityThread,ActivityManagerService,WindowManagerService 的工作原理?
      • 1. PackageManagerService 的工作原理?
      • 1. PowerManagerService 的工作原理?
      • 1. 权限管理系统(底层的权限是如何进行 grant 的)?
      • 1. 操作系统中进程和线程有什么区别?系统在什么情况下会在用户态和内核态中切换?【猎豹移动】
      • 1. 如果一个 App 里面有多个进程存在,请列举你所知道的全部 IPC 方法。
    • 5、性能优化
      • 1. 性能优化方式
      • 2. 如何对 Android 应用进行性能分析以及优化?
      • 3. ANR 产生的原因是什么?怎么定位?
      • 4. OOM 是什么?怎么解决?是否可以 try catch?
      • 5. Java 多线程引发的性能问题,怎么解决?
      • 6. 启动页白屏、黑屏、太慢怎么解决?
      • 1. App 启动崩溃异常怎么捕捉?
      • 1. 对于 Android App 闪退,可能有哪些原因?请针对每种情况简述分析过程。【猎豹移动】
      • 1. 如何保持应用的稳定性?
      • 1. RecyclerView 和 ListView 的性能对比?
      • 1. Bitmap 如何处理大图?如何预防 OOM?
      • 1. 如何缩小 Apk 的体积?
      • 1. 如何统计启动时长?
    • 6、新技术
      • 1. Glide 源码解析
      • 1. 对热修复和插件化的理解?
      • 1. 插件化原理分析
      • 1. 模块化实现(好处,原因)
      • 1. 项目组件化的理解
      • 1. 描述清点击 Android Studio 的 build 按钮后发生了什么?
      • 1. Kotlin
      • 1. 谈谈对 Kotlin 的理解
      • 1. 闭包和局部内部类的区别?
    • 7. 工具
      • 1. Git和SVN的区别
      • 2. Gradle

1、基础

1. 四大组件是什么?

Activity、Service、BroadcastReceiver、ContentProvider

2. Activity 的生命周期?

onCreate onStart onResume onPause onStop onDestroy onRestart

3. Activity 之间的通信方式?

  1. 使用 Intent/Bundle
  2. 类静态变量
  3. 全局变量
  4. 广播
  5. eventbus

4. Activity 各种情况下的生命周期?

正常情况:

  • 启动:oncreate > onStart > onResume
  • 打开新的Activity或切换到桌面:onPause > onStop ; 如果新Activity采用透明主题,当前Activity不会调用onStop
  • 回到原先Activity:onRestart > onStart > onResume
  • back退出: onPause > onStop > onDestory

异常情况:

  • 销毁:调用onSaveInstanceState保存状态,在onStop之前
  • 重建:调用onRestoreInstanceState恢复状态,在onStart之后

5. 横竖屏切换时 Activity 的生命周期

取决于android:configChanges="orientation|screenSize"设置与否

  • 设置:只回调onConfigurationChanged方法
  • 未设置:销毁 > 重建,并且会调用onSaveInstanceState和onRestoreInstanceState

6. 前台切换到后台,然后再回到前台时 Activity 的生命周期

  • 新Activity正常:onPause > onStop > onRestart > onStart > onResume
  • 新Activity透明:onPause > onResume

7. 弹出 Dialog 的时候按 Home 键时 Activity 的生命周期

Dialog对于Activity生命周期没有影响,当按下home键时,activity回调生命周期方法 onPause > onStop

8. 两个 Activity 之间跳转时的生命周期

A 跳到 B : A onPause > B onCrate > B onStart > B onResume > A onStop
B 回到 A : B onPause > A onRestart > A onStart > A onResume > B onStop > B onDestory

9. 下拉状态栏时 Activity 的生命周期

下拉状态栏不会影响Activity的生命周期

10. Activity 与 Fragment 之间生命周期比较?

正常流程:
onCreate > onStart【onAttatch > onCreate > onCreateView > onActivityCreated > onStart】 > onResume 【onResume】 > onPause 【onPause】 > onStop 【onStop】> onDestroy【onDestroy > onDestroyView > onDetach】

回到前台:
onRestart > onStart【onStart】 > onResume【onResume】

11. Activity 的四种 LaunchMode(启动模式)的区别?

  • Standard 默认模式

每启动一次Activity,就创建一个Activity实例

  • SingleTop 栈顶复用

任务栈顶有该Activity实例,回调onNewIntent(); 栈顶无实例,创建新实例

应用场景:登录页面、接收推送的资讯详情页

  • SingleTask 栈内复用

该Activity的taskAffity属性指定的任务栈,如果不存在,则创建该任务栈,创建Activity实例;任务栈存在,如果栈内有该Activity实例,回调onNewIntent(),并将任务栈中在其上面的Activity全部弹出栈; 栈内无实例,创建新Activity实例

应用场景:主页、浏览器打开网页的Activity(设置SingleTask,设置IntentFilter允许隐式启动)

  • SingleInstance 单一实例

SingleTask的加强版,如果存在该Activity实例,则回调onNewIntent();无实例,则创建新的任务栈和新的Activity实例,该实例是全局的,该任务栈中也将有且仅有这一个Activity实例,通过该Activity启动的其他Activity也将在其他单独的任务栈中创建

应用场景:来电提醒、闹钟提醒这种全局唯一的页面,项目中还未用到过

复用Activity,回调onNewIntent()的情况:

A为SingleTask,B为Standard,启动顺序:A > B > A ,生命周期切换如下
A : onCreate() > onStart() > onResume() > onPause()
B : onCreate() > onStart() > onResume()
A : onStop()
B : onPause()
A : onNewIntent() > onRestart() > onStart() > onResume()
B : onStop() > onDestroy()

12. Activity 状态保存与恢复?

异常销毁时会回调:

  • 销毁:调用onSaveInstanceState保存状态,在onStop之前
  • 重建:调用onRestoreInstanceState恢复状态,在onStart之后

13. Activity 和 Fragment 之间怎么通信, Fragment 和 Fragment 怎么通信?

Activity > Fragment:

  • findFragmentById 、findFragmentByTag获取Fragment,通过setArgument()

Fragment > Activity:

  • getActivity获取Activity,调用Activity的方法
  • startActivity开启Activity,通过Intent

Fragment > Fragment:

  • 上面两种方式结合,获取Activity再获取Fragment,传递值
  • 广播、EventBus

14. Service 的生命周期?

startService:
onCreate > onStartCommand > onDestory

bindService:
onCreate > onBind > onUnbind > onDestory

15. Service 的启动方式?

1.启动
通过startService()启动,一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响,任务完成后自行停止

2.绑定
通过调用bindService() 绑定启动,绑定服务的生命周期会跟调用者关联起来,调用者退出,服务也会跟着销毁

16. Service 与 IntentService 的区别?

Service
Service 是长期运行在后台的应用程序组件。

Service 不是一个单独的进程,它和应用程序在同一个进程中,Service 也不是一个线程,它和线程没有任何关系,所以它不能直接处理耗时操作。如果直接把耗时操作放在 Service 的 onStartCommand() 中,很容易引起 ANR .如果有耗时操作就必须开启一个单独的线程来处理。

IntentService
IntentService 是继承于 Service 并处理异步请求的一个类,在 IntentService 内有一个工作线程来处理耗时操作,启动 IntentService 的方式和启动传统 Service 一样,同时,当任务执行完后,IntentService 会自动停止,而不需要我们去手动控制。另外,可以启动 IntentService 多次,而每一个耗时操作会以工作队列的方式在IntentService 的 onHandleIntent 回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。

参考:Android开发之Service与IntentService的区别与使用场景

17. Service 和 Activity 之间的通信方式?

  • Binder
  • BroadcastReceiver、EventBus

参考:Service与Activity之间通信的2种方式

18. 对 ContentProvider 的理解?

ContentProvider是Android四大组件之一,管理对中央数据存储区的访问。它封装数据,为存储和访问数据提供统一的接口,并提供用于定义数据安全性的机制。 主要作用是向其他应用提供数据,并保护数据访问的安全性。

19. ContentProvider、ContentResolver、ContentObserver 之间的关系?

ContentProvider 内容提供者,用于对外提供数据
ContentResolver 内容解析者,用于获取内容提供者提供的数据
ContentObserver 内容监听器,可以监听数据的改变状态

20. 对 BroadcastReceiver 的了解?

BroadCastReceiver 是 Android 四大组件之一,主要用于接收系统或者 app 发送的广播事件,通过android系统的Binder机制实现

21. 广播的分类?使用方式和场景?

  1. 有序广播 sendOrderedBroadcast();
    按照被接收者的优先级顺序,在被接收者中依次传播。比如有三个广播接收者 A,B,C,优先级是 A >B > C。那这个消息先传给 A,再传给 B,最后传给 C。每个接收者有权终止广播,比如 B 终止广播,C 就无法接收到。此外 A接收到广播后可以对结果对象进行操作,当广播传给 B 时,B 可以从结果对象中取得 A 存入的数据

  2. 普通广播 sendBroadcast();
    完全异步,逻辑上可以被任何广播接收者接收到。优点是效率较高。缺点是一个接收者不能将处理结果传递给下一个接收者,并无法终止广播 intent 的传播。

  3. 系统广播

  4. 本地广播

22. 动态广播和静态广播有什么区别?

清单文件注册(静态注册),只要应用程序被部署到手机上,就立刻生效,不管进程是否处于运行状态;

代码注册(动态注册),代码运行了,广播接收者才生效,如果代码运行结束,广播接收者,就失效;对于动态广播,有注册就必然得有注销,否则会导致内存泄露,重复注册、重复注销也不允许

23. AlertDialog、popupWindow、Activity 之间的区别?

AlertDialog、popupWindow是View,Activity是Android系统中的四大组件之一,可以用于显示View。

区别:
(1)Popupwindow在显示之前一定要设置宽高,Dialog无此限制。

(2)Popupwindow默认不会响应物理键盘的back,除非显示设置了popup.setFocusable(true);而在点击back的时候,Dialog会消失。

(3)Popupwindow不会给页面其他的部分添加蒙层,而Dialog会。

(4)Popupwindow没有标题,Dialog默认有标题,可以通过dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);取消标题

(5)二者显示的时候都要设置Gravity。如果不设置,Dialog默认是Gravity.CENTER。

(6)二者都有默认的背景,都可以通过setBackgroundDrawable(new ColorDrawable(android.R.color.transparent));去掉

最关键的区别:
AlertDialog是非阻塞式对话框:AlertDialog弹出时,后台还可以做事情;
PopupWindow是阻塞式对话框:PopupWindow弹出时,程序会等待,在PopupWindow退出前,程序一直等待,只有当我们调用了dismiss方法的后,PopupWindow退出,程序才会向下执行。

参考:AlertDialog和PopupWindow的区别

24. Application 和 Activity 的 Context 之间的区别?

Application 和 Activity 都是 Context 的子类, Activity的Context维护的是Activity的生命周期,而Application的Context维护的事应用的生命周期。

Context数量 = Activity数量 + Service数量 + 1; 1就是Application数量

25. Android 动画特性?

**(1)Frame Animation(帧动画)**主要用于播放一帧帧准备好的图片,类似GIF图片,优点是使用简单方便、缺点是需要事先准备好每一帧图片;

**(2)Tween Animation(补间动画)**仅需定义开始与结束的关键帧,而变化的中间帧由系统补上,优点是不用准备每一帧,缺点是只改变了对象绘制,而没有改变View本身属性。因此如果改变了按钮的位置,还是需要点击原来按钮所在位置才有效。

**(3)Property Animation(属性动画)**是3.0后推出的动画,优点是使用简单、降低实现的复杂度、直接更改对象的属性、几乎可适用于任何对象而仅非View类,缺点是需要3.0以上的API支持,限制较大!但是目前国外有个开源库,可以提供低版本支持!

参考:Android三大动画使用总结、Android 有近10种动画,你都知道吗?

26. 请列举 Android 中常见的布局(Layout)类型,并简述其用法,以及排版效率。【猎豹移动】

第一种:帧布局(框架布局)FrameLayout,在这个布局中,所有的子元素统统放于这块区域的左上角,并且后面的子元素直接覆盖在前面的子元素之上,将前面的子元素部分和全部遮挡。

第二种:线性布局 LinearLayout,最常用的一种布局方式,所有子控件的对齐方式,取决于如何定义 orientation的属性:vertical 垂直方向 ,如果按照这种方向所有的子控件将按照垂直的方式分布在布局上,每行只允许有一个子元素,horizontal水平方向 ,这时子控件将会以水平的方向分布在布局中。

第三种:绝对布局 AbsoluteLayout,又可以叫做坐标布局,可以直接指定子元素的绝对位置,这种布局简单直接,直观性强,但是由于手机屏幕尺寸差别比较大,使用绝对定位的适应性会比较差。

第四种:相对布局 RelativeLayout,允许子元素指定它们相对于其父元素或兄弟元素的位置,这是实际布局中最常用的布局方式之一。它灵活性大很多,当然属性也多,操作难度也大,属性之间产生冲突的的可能性也大,使用相对布局时要多做些测试。

第五种:表格布局 TableLayout,表格布局TableLayout以行列的形式管理子元素,每一行是一个TableRow布局对象,当然也可以是普通的View对象,TableRow里每放一个元素就是一列,总列数由列数最多的那一行决定。

第六种:网格布局 GridLayout,在Android 4.0中,新引入的GridLayout网格布局,GridLayout布局使用虚细线将布局划分为行,列和单元格,也支持一个控件在行,列上都有交错排列。而GridLayout使用的其实是跟LinearLayout类似的API,只不过是修改了一下相关的标签而已,所以对于开发者来说,掌握GridLayout还是很容易的事情。

第七种:约束布局
参考:

  • 约束布局ConstraintLayout用法全解析
  • ConstraintLayout 约束布局

27. 对 SurfaceView 的了解?

我们知道View是通过刷新来重绘视图,系统通过发出VSSYNC信号来进行屏幕的重绘,刷新的时间间隔是16ms,如果我们可以在16ms以内将绘制工作完成,则没有任何问题,如果我们绘制过程逻辑很复杂,并且我们的界面更新还非常频繁,这时候就会造成界面的卡顿,影响用户体验,为此Android提供了SurfaceView来解决这一问题。

View和SurfaceView的区别:
1 . View适用于主动更新的情况,而SurfaceView则适用于被动更新的情况,比如频繁刷新界面。
2 . View在主线程中对页面进行刷新,而SurfaceView则开启一个子线程来对页面进行刷新。
3 . View在绘图时没有实现双缓冲机制,SurfaceView在底层机制中就实现了双缓冲机制。

双缓冲主要是为了解决反复局部刷屏带来的闪烁。把要画的东西先画到一个内存区域里,然后整体的一次性画出来。

参考:Android中的SurfaceView详解

28. Serializable 和 Parcelable 的区别?

Serializable使用IO读写存储在硬盘上。序列化过程使用了反射技术,并且期间产生临时对象。优点代码少。

Parcelable是直接在内存中读写,我们知道内存的读写速度肯定优于硬盘读写速度,所以Parcelable序列化方式性能上要优于Serializable方式很多。但是代码写起来相比Serializable方式麻烦一些。

参考:浅谈Android中Serializable和Parcelable使用区别

29. Android 中数据存储方式有哪些?

1.SQLite:

SQLite是一个轻量级的数据库,支持基本SQL语法,是常被采用的一种数据存储方式,最大支持2TB容量。Android为此数据库提供了一个名为SQLiteDatabase的类,封装了一些操作数据库的API。

Android上SQLite的使用
Android ORM 框架:GreenDao 使用详解

2.SharedPreference:
其本质就是一个xml文件,常用于存储较简单的参数设置。

commit和apply方法的区别:

  • commit和apply虽然都是原子性操作,但是原子的操作不同,commit是原子提交到数据库,所以从提交数据到存在Disk中都是同步过程,中间不可打断。
  • 而apply方法的原子操作是原子提交的内存中,而非数据库,所以在提交到内存中时不可打断,之后再异步提交数据到数据库中,因此也不会有相应的返回值。
  • 所有commit提交是同步过程,效率会比apply异步提交的速度慢,但是apply没有返回值,永远无法知道存储是否失败。
  • 在不关心提交结果是否成功的情况下,优先考虑apply方法。

SharedPreferences中的commit和apply方法

3.File:

即常说的文件(I/O)存储方法,常用于存储大数量的数据,但是缺点是更新数据将是一件困难的事情。

4.ContentProvider:

Android 系统中能实现所有应用程序共享的一种数据存储方式,由于数据通常在各应用间的是互相私密的,所以此存储方式较少使用,但是其又是必不可少的一种存储方式。 例如音频,视频,图片和通讯录,一般都可以采用此种方式进行存储。每个ContentProvider都会对外提供一个公共的URI,其它应用通过ContentResolver,使用这个URI进行数据操作

5.网络存储:

从网络读取数据和写入数据。 Android提供了通过网络来实现数据的存储和获取的方法。
我们可以调用WebService返回的数据或是解析HTTP协议实现网络数据交互。

开发过程中,根据设计目标、性能需求、空间需求等找到 合适的数据存储方式

30. 数据解析

一、xml解析

DOM、SAX、PULL

参考:XML数据的三种解析方式

二、json

手动解析、GSON、FastJson

GSON、FastJson的区别?

  1. fastjson性能更快一些,据说FastJson采用独创的算法,将parse的速度提升到极致,超过所有json库。
  2. 序列化时fastJson是按照set方法的名字来转换的,而gson则是按照属性的名字来转换的。
  3. 反序列化时,有默认的无参构造方法时,gson和fastJson都会调用它来创建对象,没有默认的无参构造方法时,fastJson会直接报错!而gson则会调用Unsafe.allocateInstance()这个native方法直接在内存上创建对象。

参考:JSON解析、Gson与FastJson比较

三、xml和json区别

  • 数据体积方面,JSON相对XML来讲,数据的体积小,传递的速度更快些
  • 数据交互方面,JSON与JavaScript的交互更加方便,更容易解析处理,更好地进行数据交互
  • 数据描述方面,JSON对数据的描述性比XML较差

30. Android 各个版本 API 的区别?

5.0特性

  1. ART虚拟机
  2. MD控件

6.0特性

  1. 动态权限

7.0特性

  1. 应用之间共享文件的权限收紧,需要使用FileProvide授予临时访问权限

8.0特性

  1. 自适应图标
  2. 通知增加channel属性

9.0特性

  1. 全面屏的全面支持
  2. 禁用非加密网络请求(http)

参考:Android 1.5到10.0 都有哪些新特性?、Android5.0,6.0,7.0,8.0新特性整理

31. 屏幕适配的处理技巧都有哪些?

  • 图片适配:多套图片资源、.9图片
  • 布局适配:使用RelativeLayout、ConstraintLayout,权重、wrap_content、限定符(尺寸限定符、最小宽度限定符、方向限定符),dp、sp

参考:Android 屏幕适配:最全面的解决方案、smallestWidth适配、
今日头条适配方案、Android 刘海屏适配方案

32. 动态权限适配方案,权限组的概念?

Android 6.0把权限分成正常权限和危险权限,AndroidManifest中声明的正常权限系统会自动授予,而危险权限则需要在使用的时候用户明确授予。

对于危险权限:
1.检查权限 ContextCompat.checkSelfPermission
2.申请权限 ActivityCompat.requestPermissions
3.处理权限请求响应 onRequestPermissionsResult

参考:Android动态权限申请

33. 通知适配

Android 8.0系统的通知栏适配

34. 自适应图标适配

Android 8.0系统的应用图标适配

35. 为什么不能在子线程更新 UI?

Android的UI访问是没有加锁的,多个线程可以同时访问更新操作同一个UI控件。也就是说访问UI的时候,android系统当中的控件都不是线程安全的,这将导致在多线程模式下,当多个线程共同访问更新操作同一个UI控件时容易发生不可控的错误,而这是致命的。所以Android中规定只能在UI线程中访问UI,这相当于从另一个角度给Android的UI访问加上锁,一个伪锁。提高移动端更新UI的效率和和安全性.

子线程更新UI的正确姿势:
1;使用Handler
2;使用Activity的runOnUiThread方法把更新UI的代码创建在Runnable中即可
3;使用AsyncTask
4;HandlerThread

36. ListView 图片加载错乱的原理和解决方案?

原因:
异步加载 + Listview的view复用

解决方案:
1.findViewByTag (由于ListView中的ImageView控件都是重用的,移出屏幕的控件很快会被进入屏幕的图片重新利用起来,那么getView()方法就会再次得到执行,而在getView()方法中会为这个ImageView控件设置新的Tag,这样老的Tag就会被覆盖掉,于是这时再调用findVIewWithTag()方法并传入老的Tag,就只能得到null了,而我们判断只有ImageView不等于null的时候才会设置图片,这样图片乱序的问题也就不存在了。)

2.Volley当中提供的控件NetworkImageView(原理就是如果这个控件已经被移出了屏幕且被重新利用了,那么就把之前的请求取消掉,仅此而已)

  1. 使用弱引用关联(本质是要让ImageView和BitmapWorkerTask之间建立一个双向关联,互相持有对方的引用,再通过适当的逻辑判断来解决图片乱序问题,然后为了防止出现内存泄漏的情况,双向关联要使用弱引用的方式建立)

参考:Android ListView异步加载图片乱序问题,原因分析及解决方案

37. 对 RecycleView 的了解?

Recyclerview是Android 5.0新增的一个列表控件。顾名思义,recycler view,只负责回收和复用视图,高度的解耦,可灵活定制,轻松实现Listview、GridView、瀑布流的效果。

优点:

  • item复用
    把ViewHolder的实现封装起来,规范了ViewHolder,把item的view写入ViewHolder中,可以通过复用ViewHolder来实现view的复用

  • 灵活、可定制化高、可拓展性高
    显示方式:通过LayoutManager控制
    item分割线:通过ItemDecoration控制
    item动画:通过ItemAnimator控制
    item点击事件:自定义

参考:

  • Android RecyclerView 使用完全解析 体验艺术般的控件
  • 快速掌握 Recyclerview、SwipeRefreshLayout、Cardview
  • RecyclerView 必知必会
  • RecyclerView 优秀文集

38. Recycleview 和 ListView 的区别? 为什么Listview没有废弃?

1、区别

  • Adapter不同:RecyclerView的继承Recyclerview.Adapter、Listview的继承BaseAdapter
  • ViewHolder不同:RecyclerView的必须重写、ListView不是必须的
  • 点击事件不同:Recyclerview需要自定义、ListView直接setOnItemClickListener
  • 缓存层级不同:Recyclerview 4级 、 ListView 2级
  • 缓存对象不同:RecyclerView缓存ViewHolder、ListView缓存View

2、ListView采用的是RecyclerBin的回收机制在一些轻量级的List显示时效率更高
参考:

  • ListView 与 RecyclerView 对比浅析–缓存机制

39. Android Manifest 的作用与理解?

每个安卓应用程序必须有一个AndroidManifest.xml文件,在app/manifests目录中。主要作用用于告诉系统一些应用的信息:

  • 指定应用包名,包的名称作为应用程序的唯一标识符
  • 声明四大组件
  • 权限
  • 版本

40. 多线程在 Android 中的使用?

  1. Handler
    Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
    handler在两个子线程间传递数据

  2. AsyncTask
    参考:Android AsyncTask 源码解析

  3. IntentService
    IntentService是一种特殊的Service,它继承了Service并是一个抽象类,它使用工作线程逐一处理所有启动请求。如果您不要求服务同时处理多个请求,这是最好的选择。 您只需实现 onHandleIntent() 方法即可,该方法会接收每个启动请求的 Intent,使您能够执行后台工作。

    IntentService 执行以下操作:

    • 创建默认的工作线程,用于在应用的主线程外执行传递给 onStartCommand() 的所有 Intent。
    • 创建工作队列,用于将 Intent 逐一传递给 onHandleIntent() 实现,这样您就永远不必担心多线程问题。
    • 在处理完所有启动请求后停止服务,因此您永远不必调用 stopSelf()。
    • 提供 onBind() 的默认实现(返回 null)。
      *提供 onStartCommand() 的默认实现,可将 Intent 依次发送到工作队列和 onHandleIntent() 实现。

    综上所述,您只需实现 onHandleIntent() 来完成客户端提供的工作即可。(不过,您还需要为服务提供小型构造函数。)

public class HelloIntentService extends IntentService {

  /**
   * A constructor is required, and must call the super IntentService(String)
   * constructor with a name for the worker thread.
   */
  public HelloIntentService() {
      super("HelloIntentService");
  }

  /**
   * The IntentService calls this method from the default worker thread with
   * the intent that started the service. When this method returns, IntentService
   * stops the service, as appropriate.
   */
  @Override
  protected void onHandleIntent(Intent intent) {
      // Normally we would do some work here, like download a file.
      // For our sample, we just sleep for 5 seconds.
      try {
          Thread.sleep(5000);
      } catch (InterruptedException e) {
          // Restore interrupt status.
          Thread.currentThread().interrupt();
      }
  }
}

41. 区别 Animation 和 Animator 的用法,概述实现原理?【猎豹移动】

(1)对于 Animation 动画:

他的实现机制是,在每次进行绘图的时候,通过对整块画布的矩阵进行变换,从而实现一种视图坐标的移动,但实际上其在 View 内部真实的坐标位置及其他相关属性始终恒定.

(2)对于 Animator 动画:

Animator 动画的实现机制说起来其实更加简单一点,因为他其实只是计算动画开启之后,结束之前,到某个时间点得时候,某个属性应该有的值,然后通过回调接口去设置具体值,其实 Animator 内部并没有针对某个 view 进行刷新,来实现动画的行为,动画的实现是在设置具体值的时候,方法内部自行调取的类似 invalidate 之类的方法实现的.也就是说,使用 Animator ,内部的属性发生了变化.

42. Webview

主要类:

  • WebSettings类(主要作用是:对WebView进行配置和管理)
  • WebViewClient类(主要作用是:处理各种通知 & 请求事件)
  • WebChromeClient类( 作用:辅助 WebView 处理 Javascript 的对话框,网站图标,网站标题等等。)

android调用Js:

  • 通过WebView的loadUrl()

  • 通过WebView的evaluateJavascript()

Js调用Android:

  • 通过WebView的addJavascriptInterface()进行对象映射

  • 通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url

  • 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息

基本优化:
(1)给WebView加一个加载进度条
(2)加快HTML网页加载完成的速度,等页面finish再加载图片
(3)自定义WebView页面加载出错界面
(4) 可以代码创建WebView,使用完后及时销毁,防止内存泄漏
(5) 漏洞:

1.任意代码执行漏洞:4.2后使用@JavascriptInterface,之前使用其他调用方式
2.密码明文存储漏洞:WebSettings.setSavePassword(false) 
3.域控制不严格漏洞:禁止file 协议

参考:

  1. WebView的基本使用以及Android和js的交互
  2. 全面总结WebView遇到的坑及优化
  3. WebView的内存泄漏、漏洞以及缓存机制原理和解决方案

2、进阶

1. 画出 Android 的大体架构图

  • Linux 内核

  • 硬件抽象层 (HAL)

  • Android Runtime

  • 原生 C/C++ 库

  • Java API 框架

  • 系统应用

Android面试题精选汇总 - Android_第1张图片

2. 低版本 SDK 如何使用高版本 API?

  • @SuppressLint , 忽略警告
  • @TargetApi , 到达指定版本才调用

参考:如何在低版本SDK调用高版本API?

3. AsyncTask 如何使用?

一个Android 已封装好的轻量级异步类
属于抽象类,即使用时需 实现子类
主要用来执行耗时任务,然后更新UI

  1. 继承AsyncTask
  2. 重写onPreExecute,做一些准备操作,如提示框显示
  3. 重写doInBackground,做耗时操作,可以通过publishProgress向重写onProgressUpdate传递值
  4. 重写onProgressUpdate,更新进度值
  5. 重写onPostExecute,更新UI
  6. 创建AsyncTask实例对象,调用excute(),开始任务执行
  • 必须在UI线程中调用
  • 同一个AsyncTask实例对象只能执行1次,若执行第2次将会抛出异常
  • 执行任务中,系统会自动调用AsyncTask的一系列方法:onPreExecute() 、doInBackground()、onProgressUpdate() 、onPostExecute()
  • 不能手动调用上述方法

参考:AsyncTask最详细使用教程

4. AsyncTask 机制、原理及不足?

原理:
AsyncTask的实现原理 = 2个线程池 + Handler

Android面试题精选汇总 - Android_第2张图片

缺陷:
AsyncTask在并发执行多个任务时发生异常。其实还是存在的,在3.0以前的系统中还是会以支持多线程并发的方式执行,支持并发数也是我们上面所计算的128,阻塞队列可以存放10个;也就是同时执行138个任务是没有问题的;而超过138会马上出现java.util.concurrent.RejectedExecutionException;而在在3.0以上包括3.0的系统中会为单线程执行

参考:

  • Android AsyncTask 源码解析
  • AsyncTask的原理 及其源码分析

6. Handler 机制和底层实现?

Handler 机制:

Handler是Android中的消息传递机制,因为在Android中只能在UI线程进行UI更新操作,所以在多线程的应用场景中,将工作线程中需更新UI的操作信息 传递到 UI主线程,从而实现工作线程对UI的更新处理,最终实现异步消息的处理。保证UI线程安全。

关键类:

  1. Looper : 轮询器
  2. MessageQueue : 消息队列
  3. Handler : 消息处理
  4. Message : 消息对象

对应关系:

  1. 1个Thread只能绑定1个Looper,但可以有多个Handler
  2. 1个Handler只能绑定1个1个Looper
  3. 1个Looper 可绑定多个Handler

Handler的工作流程:

  1. 异步通信准备

    • Looper
      • 通过Looper.prepare()调用Looper构造方法new Looper()创建Looper,只能调用一次,保证了1个Thread对应一个Looper
    • MessageQueue
      • Looper构造方法内会自动创建MessageQueue
    • Handler
      • 创建Handler,通过new Handler(),重写handleMessage()方法
      • new Handler(),构造方法中通过Looper.myLooper()和Looper关联,通过mLooper.mQueue和MessageQueue关联
  2. 消息发送

    • Handler.sendMessage()、Handler.post(),最终都会调用Handler.sendMessageAtTime()这个方法,其中通过MessageQueue.enqueueMessage()将消息加入到MessageQueue
  3. 消息循环

    • Looper.loop(),循环遍历MessageQueue,调用MessageQueue.next(),没有消息就阻塞,有消息就调用Handler.dispatchMessage(msg),交个Handler.handleMessage()处理,最后通过msg.recycle()释放消息占用资源
  4. 消息处理

    • 在handleMessage()方法中进行UI更新操作

总结完成,大家可能还会问,那么在Activity中,我们并没有显示的调用Looper.prepare()和Looper.loop()方法,为啥Handler可以成功创建呢,这是因为在Activity的启动代码中,已经在当前UI线程调用了Looper.prepare()和Looper.loop()方法。

参考:深入理解 Looper、Handler、Message三者关系

7. Handler、Thread、HandlerThread 区别?

Handler:在android中负责发送和处理消息,通过它可以实现工作线程与主线程之间的消息通讯。

Thread:Java进程中执行运算的最小单位。分为主线程和工作线程,一个进程中至少有一个线程,就是主线程

HandlerThread:本质是继承Thread类 & 封装Handler类 , 为异步消息通信提供便利

参考: 教你使用HandlerThread

8. ThreadLocal 原理、实现及如何保证 Local 属性?

ThreadLocal即线程变量,它为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

ThreadLocal的实现是以ThreadLocal对象为键。任意对象为值得存储结构。**这个结构被附带在线程上,**也就是说一个线程可以根据一个ThreadLocal对象查询到绑定在这个线程上的一个值。

参考:

  • ThreadLocal 概念、原理及使用方法
  • Android的消息机制之ThreadLocal的工作原理

9. 自定义 View 的流程?如何机型适配?

分类:

  • 继承View,创建新View

  • 继承ViewGroup,创建新Layout

  • 继承现有特定的View进行扩展,如继承Textview自定义字体

  • 继承现有特定的ViewGroup,进行自定义组合控件

适配:

  • 图片适配:多套图片资源、.9图片
  • 布局适配:使用RelativeLayout、ConstraintLayout,权重、wrap_content、限定符(尺寸限定符、最小宽度限定符、方向限定符),dp、sp
    参考:android机型适配终极篇

10. 自定义 View 的时怎么获取 View 的大小?

getMeasureWidth()/getMeasuredHeight()
在measure()过程结束后就可以获取到了
getMeasureXXX()方法中的值是通过setMeasuredDimension()方法来进行设置的

getHeight()/getWidth()
要在layout()过程结束后才能获取到
getXXX()方法中的值则是通过视图右边的坐标减去左边的坐标计算出来的。

11. View 的绘制流程?

View的绘制从ActivityThread类中Handler处理RESUME_ACTIVITY事件开始,在执行performResumeActivity之后,创建Window以及DecorView并调用WindowManager的addView方法添加到屏幕上,addView又调用ViewRootImpl的setView方法,最终执行performTraversals方法,依次执行performMeasure,performLayout,performDraw。也就是view绘制的三大过程。

measure过程测量view的视图大小,最终需要调用setMeasuredDimension方法设置测量的结果,如果是ViewGroup需要调用measureChildren或者measureChild方法进而计算自己的大小。

layout过程是摆放view的过程,View不需要实现,通常由ViewGroup实现,在实现onLayout时可以通过getMeasuredWidth等方法获取measure过程测量的结果进行摆放。

draw过程先是绘制背景,其次调用onDraw()方法绘制view的内容,再然后调用dispatchDraw()调用子view的draw方法,最后绘制滚动条。ViewGroup默认不会执行onDraw方法,如果复写了onDraw(Canvas)方法,需要调用 setWillNotDraw(false);清除不需要绘制的标记。

12. 如何理解Activity,View,Window三者之间的关系?

从UI加载流程来分析:

UI加载流程由Activity#setContentView()开始,最终调用的是PhoneWindow#setContentView(),在其中又会调用honeWindow#installDecor()创建DecorView,然后加载我们自定义布局资源,最后通过Window#addView()将布局添加到屏幕上,addView又调用ViewRootImpl的setView方法,最终执行performTraversals方法,依次执行performMeasure,performLayout,performDraw。也就是view绘制的三大过程。

由此,可看出Activity算是控制器,Window算是实际承载View的容器,而View就是显示视图

13. View 的事件传递分发机制?

事件分发其实就是MotionEvent事件分发过程,当一个MotionEvent产生以后,系统需要把这个事件传递给一个具体的View,这个过程就是事件分发。

传递顺序:
Activity 》 Window 》 ViewGroup 》 View

主要方法:
dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()

分发步骤:
事件总是先传递给Activity,Activity再传递给Window,Window传递给顶级View,然后按照事件分发机制分发事件。

传递到Viewgroup时,它的dispatchTouchEvent()会被调用,在其中如果它的onInterceptTouchEvent()返回true就表示它要拦截这个事件,接着事件就会交给这个ViewGroup处理,它的onTouchEvent()就会被调用。

如果它的onInterceptTouchEvent()返回false就表示它不拦截这个事件,这个事件就会继续传递给它的子View

接着子View的dispatchTouchEvent()会被调用,如此反复直到事件被处理。

当一个View需要处理事件时,如果它设置了onTouchLister,那么其中的onTouch()方法会被调用。如果onTouch()方法返回true,则View的onTouchEvent()不会被调用;如果返回false,则View的onTouchEvent()会被调用。 (onTouchLister > onTouchEvent > onClickListener)

如果这个View的onTouchEvent()返回false,那么它的父容器的onTouchEvent()将会被调用,以此类推,如果所有元素都不处理这个事件,最终会回传给Activity,Activity的onTouchEvent()会被调用。

事件传递是由外向内的,子元素也可以通过requestDisallowInterceptTouchEvent()方法干预分发过程,但是ACTION_DOWN事件除外。

事件冲突的解决:

  1. 内部拦截法
    父容器不做任何拦截,所有的事件都交个子元素,如果子元素需要就直接消耗掉,否则返回给父容器处理,需要配合requestDisallowInterceptTouchEvent()方法使用

  2. 外部拦截法
    重写父容器的onInterceptTouchEvent()方法,在其中做出相应的拦截

参考:Android事件分发机制详解

14. requestLayout(),onLayout(),onDraw(),drawChild() 区别与联系?

调用requestLayout()方法的时机是:当前View发生了一些改变,这个改变使得现有的View失效,所以调用requestLayout()方法对View树进行重新布局,过程包括了measure()和layout()过程,但不会调用draw()过程,即不会发生重新绘制视图过程。

调用onLayout()的时机是:View需要给自己设置大小和位置了或者ViewGroup需要给子View和ViewGroup自身时调用。

自定义一个view时,重写onDraw()。画自己

自定义一个ViewGroupdispatchDraw()会调用drawChild()。画孩子

参考:requestLayout(),onLayout(),onDraw(),drawChild() 区别与联系?

15. invalidate() 和 postInvalidate() 的区别?

view.invalidate(),会触发onDraw()和computeScroll()。前提是该view被附加在当前窗口上

view.postInvalidate(); //是在非UI线程上调用的

参考:invalidate() 和 postInvalidate() 的区别

16. 如何计算一个 View 的嵌套层级?

递归调用getParent()

参考:计算一个ViewGroup的嵌套层级

17. 进程和 Application 的生命周期的关系?

当application在Linux平台开启时,系统会给这个application创建一个进程(process)来运行同时分配内存资源给该application,当程序结束运行时,该进程结束系统回收内存资源

18. SparseArray 的实现原理?

SparseArray有两个优点:

1.避免了自动装箱(auto-boxing),
2.数据结构不会依赖于外部对象映射。

我们知道HashMap 采用一种所谓的“Hash 算法”来决定每个元素的存储位置,存放的都是数组元素的引用,通过每个对象的hash值来映射对象。而SparseArray则是用数组数据结构来保存映射,然后通过折半查找来找到对象。但其实一般来说,SparseArray执行效率比HashMap要慢一点,因为查找需要折半查找,而添加删除则需要在数组中执行,而HashMap都是通过外部映射。但相对来说影响不大,最主要是SparseArray不需要开辟内存空间来额外存储外部映射,从而节省内存。

参考:Android为什么推荐使用SparseArray来替代HashMap?

1. ContentProvider 是如何实现数据共享的?

1. ContentProvider 的权限管理?

1. Android 系统为什么会设计 ContentProvider?

1. Android 线程有没有上限?

1. 怎么去除重复代码?

1. Android 中开启摄像头的主要流程?

1. 对 Bitmap 对象的了解?

玩转Android Bitmap
Android 之 Bitmap

1. 图片加载原理?

1. 图片压缩原理?

1. 图片框架实现原理?LRUCache 原理?

1. EventBus 实现原理?

1. ButterKnife 实现原理?

1. Volley 实现原理?

参考:Volley 源码解析

1. okhttp 实现原理?

参考:okhttp源码解析

1. rxJava 实现原理?

1. Retorfit 实现原理?

1. Dagger2 实现原理?

1. 服务器只提供数据接收接口,在多线程或多进程条件下,如何保证数据的有序到达?

1. SQLite 数据库升级,数据迁移问题?

1. 数据库框架对比和源码分析?

1. CAS介绍,OAuth 授权机制?

1. 谈谈你对安卓签名的理解

1. App 是如何沙箱化,为什么要这么做?

3、混合开发

1. 混合开发的方式?各自优缺点和使用场景?

1. Hybird

1. React Native

1. Weex

1. Flutter

1. Dart

1. 快应用

4、Framework

1. 请介绍一下 NDK?

1. 如何加载 ndk 库?如何在 jni 中注册 native 函数,有几种注册方式?【猎豹移动】

1. 谈谈对进程共享和线程安全的认识?

1. 谈谈对多进程开发的理解以及多进程应用场景?

1. 什么是协程?

1. 逻辑地址与物理地址,为什么使用逻辑地址?

1. Android 为每个应用程序分配的内存大小是多少?

1. 进程保活的方式?

1. 系统启动流程是什么?

1. 一个应用程序安装到手机上的过程发生了什么?

1. App 启动流程,从点击桌面开始(Activity 启动流程)?

1. 什么是 AIDL?解决了什么问题?如何使用?

1. Binder 机制及工作原理?

1. App 中唤醒其他进程的实现方式?

1. Activity、Window、View 三者的关系与区别?

1. ApplicationContext 和 ActivityContext 的区别?

1. ActivityThread,ActivityManagerService,WindowManagerService 的工作原理?

1. PackageManagerService 的工作原理?

1. PowerManagerService 的工作原理?

1. 权限管理系统(底层的权限是如何进行 grant 的)?

1. 操作系统中进程和线程有什么区别?系统在什么情况下会在用户态和内核态中切换?【猎豹移动】

1. 如果一个 App 里面有多个进程存在,请列举你所知道的全部 IPC 方法。

5、性能优化

1. 性能优化方式

布局优化

核心思想就是减少布局的层级,层级减少了,绘制时间就减少了,性能自然提高

  1. 删除减少无用的层级
  2. 选择性使用ViewGroup,LinearLayout和RelativeLayout选择LinearLayout,因为RelativeLayout比较复杂,但是如果一层LinearLayout完成不了布局,就选择使用RelativeLayout,不然的话就增加了层级,性能同样是变低
  3. 使用《include》标签,和《merge》标签,include重复利用布局文件,merger一般和include同时使用,主要是用来减少层级,比如LinearLayout垂直布局中使用《include》,插入的这个布局中也是线性垂直布局,这是没必要的层级,这时就可以使用《merge》减少层级
  4. 使用《viewstub》,它继承自view,且宽高都是0,不参与布局的绘制,满足按需加载的需求,比如我们平常都会有个网络错误的布局,一般是不需要加载的,当想加载时,可以通过findviewByid().setvisible(true)实现,也可通过findviewByid().inflate()实现

绘制优化

避免在ondraw()中执行大量的操作,Google建议的是每帧的绘制不超过16ms,总之尽量减少onDraw()中绘制的复杂度,循环次数

内存泄露优化

  1. 注意静态变量引起的内存泄露,比如一个静态的上下文,会导致Activity无法释放,建议如果需要生命周期较长的上下文,可以使用Applicationcontext代替
  2. 注意属性动画中循环动画引起的内存泄露,要在onDestroy()中使用animator.cancle()
  3. 注意没有及时关闭Cursor一起的内存泄露,及时手动关闭cursor.close()
  4. Handler导致的Activity泄漏,如果Handler中有延迟的任务或者是等待执行的任务队列过长,都有可能因为Handler继续执行而导致Activity发生泄漏,在UI退出之前,执行remove Handler消息队列中的消息与runnable对象
  5. 注意监听器的注销

响应速度优化

将耗时操作:数据库查询,网络请求,复杂的逻辑计算通过handler,Asynctask,runonuiThread异步操作,保证UI界面的流畅性;避免ANR的出现,一般Activity是5秒,广播是10秒

Listview和Bitmap优化

  1. listview就是通过viewholder缓存引用,converview复用,图片异步加载等
  2. Bitmap就是对bitmap进行采样压缩,及时回收

电量优化

  1. 对定位要求不太高的场景尽量使用网络定位,而不是GPS定位。
  2. 尽可能的减少网络请求次数和减小网络请求时间间隔。

APK瘦身优化

  1. 代码混淆。使用IDE 自带的 proGuard 代码混淆器工具 ,它包括压缩、优化、混淆等功能。
  2. 资源优化。比如使用 Android Lint 删除冗余资源,资源文件最少化等
  3. 图片优化。比如利用 PNG优化工具 对图片做压缩处理。
  4. 可以使用微信开源资源文件混淆工具——AndResGuard 。一般可以压缩apk的1M左右大
  5. 避免重复或无用功能的第三方库。例如,百度地图接入基础地图即可、讯飞语音无需接入离线、图片库Glide\Picasso等

2. 如何对 Android 应用进行性能分析以及优化?

  • UI卡顿
    • 使用HierarchyViewer分析UI性能
    • 使用GPU过度绘制分析UI性能
  • 内存泄漏
    • LeakCanary

参考:Android应用开发性能优化完全分析

3. ANR 产生的原因是什么?怎么定位?

在 Android 上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框。

用户可以选择让程序继续运行,但是,他们在使用你的应用程序时,并不希望每次都要处理这个对话框。因此,在程序里对响应性能的设计很重要,这样,系统不会显示ANR 给用户。

不同的组件发生 ANR 的时间不一样,Activity是 5 秒,BroadCastReceiver 是 10 秒,Service是20s

解决方案:
将所有耗时操作,比如访问网络,Socket 通信,查询大量 SQL 语句,复杂逻辑计算等都放在子线程中去,然后通过 handler、runonUITread、AsyncTask 等方式更新 UI。无论如何都要确保用户界面操作的流畅度。

定位:
分析ANR,除了检查代码的生命周期函数是否有耗时操作,还可以分析traces日志(data/anr/traces.txt),分析角度主要包括:
1.栈信息,一般可以知道在哪段代码附近发生了ANR,可能不是直接原因,但一般在问题点附近。
2.CPU用量,看负载比例和平均负载,判断是不是有别的App占用了过多的CPU。
3.IO Wait,看IOWait的占比是否很高,判断是否在等待IO。

参考:深入理解ANR

4. OOM 是什么?怎么解决?是否可以 try catch?

Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M,有的机器为24M。我们平常看到的OutOfMemory的错误,通常是堆内存溢出。

虽然JAVA有垃圾回收机制,但也存在内存泄露。如果我们一个程序中,已经不再使用某个对象,但是因为仍然有引用指向它,垃圾回收器就无法回收它,当然 该对象占用的内存就无法被使用,这就造成了内存泄露。内存泄漏严重了就会导致内存溢出OOM

造成内存泄漏的原因:

  1. 数据库的cursor没有关闭。
  2. 调用registerReceiver()后未调用unregisterReceiver().
  3. 未关闭InputStream/OutputStream。
  4. Bitmap使用后未调用recycle()。
    • 及时recycle()
    • ARGB 8888 转换为RGB 565,
    • 采样率压缩
  5. Context泄漏。
    • static修饰,参考第7条
    • 内部类持有外部类引用
      • 将线程的内部类,改为静态内部类。并且注意第二条。
      • 在线程内部采用弱引用保存Context引用。
  6. static关键字等。
    • 应该尽量避免static成员变量引用资源耗费过多的实例,比如Context。
    • Context尽量使用Application Context,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题。
    • 使用WeakReference代替强引用。比如可以使用WeakReference mContextRef;

是否可以 try catch?
一般不适合这么处理,try catch是用来捕获检查性异常的

Java中管理内存除了显式地catch OOM之外还有更多有效的方法:比如SoftReference, WeakReference, 硬盘缓存等。

在JVM用光内存之前,会多次触发GC,这些GC会降低程序运行的效率。
如果OOM的原因不是try语句中的对象(比如内存泄漏),那么在catch语句中会继续抛出OOM

参考:Android OOM出现常见原因及解决办法

5. Java 多线程引发的性能问题,怎么解决?

线程池

参考:Java多线程引发的性能问题以及调优策略

6. 启动页白屏、黑屏、太慢怎么解决?

参考:你的 APP 为何启动那么慢?

1. App 启动崩溃异常怎么捕捉?

1. 对于 Android App 闪退,可能有哪些原因?请针对每种情况简述分析过程。【猎豹移动】

1. 如何保持应用的稳定性?

1. RecyclerView 和 ListView 的性能对比?

1. Bitmap 如何处理大图?如何预防 OOM?

1. 如何缩小 Apk 的体积?

1. 如何统计启动时长?

6、新技术

1. Glide 源码解析

1. 对热修复和插件化的理解?

1. 插件化原理分析

1. 模块化实现(好处,原因)

1. 项目组件化的理解

1. 描述清点击 Android Studio 的 build 按钮后发生了什么?

1. Kotlin

1. 谈谈对 Kotlin 的理解

1. 闭包和局部内部类的区别?

7. 工具

1. Git和SVN的区别

1.SVN优缺点
优点:
1、 管理方便,逻辑明确,符合一般人思维习惯。
2、 易于管理,集中式服务器更能保证安全性。
3、 代码一致性非常高。
4、 适合开发人数不多的项目开发。
缺点:
1、 服务器压力太大,数据库容量暴增。
2、 如果不能连接到服务器上,基本上不可以工作,看上面第二步,如果服务器不能连接上,就不能提交,还原,对比等等。
3、 不适合开源开发(开发人数非常非常多,但是Google app engine就是用svn的)。但是一般集中式管理的有非常明确的权限管理机制(例如分支访问限制),可以实现分层管理,从而很好的解决开发人数众多的问题。

2.Git优缺点
优点:
1、适合分布式开发,强调个体。
2、公共服务器压力和数据量都不会太大。
3、速度快、灵活。
4、任意两个开发者之间可以很容易的解决冲突。
5、离线工作。
缺点:
1、学习周期相对而言比较长。
2、不符合常规思维。
3、代码保密性差,一旦开发者把整个库克隆下来就可以完全公开所有代码和版本信息。

2. Gradle

Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化建构工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置。在Android Studio中,我们可以使用Gradle来完成APK的编译及打包工作

使用Gradle的原因:

(1)、使用领域专用语言(Domain Specific Language)来描述和处理构建逻辑。
(2)、基于Groovy。DSL可以混合各种声明元素,用代码操控这些DSL元素达到逻辑自定义。
(3)、支持已有的Maven或者Ivy仓库基础建设。
(4)、非常灵活,允许使用best practices,并不强制让你遵照它的原则来。
(5)、其它插件时可以暴露自己的DSL和API来让Gradle构建文件使用。
(6)、允许IDE集成,是很好的API工具。

在Android Studio中,你可以在Gradle中配置以下内容:

(1)、配置插件及插件的属性
(2)、配置远程仓库,像jcenter和maven
(3)、配置所依赖的第三方库,jar包等
(4)、配置多渠道打包的信息
(5)、配置应用的签名信息,编译版本信息等等

你可能感兴趣的:(【面试】)