2020年终总结:这是一份面向Android工程师的面试大纲

缘起
有不少Android 开发人员准备面试,殊不知道如何准备?因而纷纷上网发帖求助。css

甚至不少人网上随便找找面试题什么的,其结果就是[字节惨挂在三面],挥泪整理面筋。等诸多文章火了,究其缘由就是这些文章戳中了大部分面试者的痛点,面试被刷了。html

想到还有不少android程序员没有找到Android面试大纲。不知道如何准备Android面试。java

因而,我就想干脆我本身作这个事吧,就算没人看,也当我本身的年终总结了。linux

如何准备android面试

纯技术方面的准备,若是是的话,我就提供一些拙见,大部分算是一些开发知识死角或者tips吧,权当抛砖引玉了:)
今天就总结下2020年搜集整理的面试题,难度不大,大佬能够直接路过,固然发发善心点个赞也是能够的❤️。android

Activity面试题


一、Activity是什么git

Activity是四大组件之一,它提供一个界面让用户点击和各类滑动操做,这就是Activity程序员

二、Activity四种状态web

  • runing
  • paused
  • stopped
  • killed

三、Activity生命周期面试

  • onCreate()
  • onStart()
  • onResume()
  • onPause()
  • onStop()
  • onDestroy()
  • onRestart()
    Android工程师之Android面试大纲PDF

四、Activity切换横屏时生命周期shell

  • onSaveInstanceState()
  • onPause()
  • onStop()
  • onDestroy()
  • onCreate()
  • onStart()
  • onRestoreInstanceState()
  • onResume()

五、进程的优先级

oom_adj是linux内核分配给每一个系统进程的一个值,表明进程的优先级,进程回收机制就是根据这个优先级来决定是否进行回收。进程的oom_adj越大,表示此进程优先级越低,越容易被杀回收;越小,表示进程优先级越高,越不容易被杀回收。普通app进程的oom_adj>=0,系统进程的oom_adj才可能小于0。进程优先级从小到大以下

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

六、Activity任务栈

  • 先进后出

七、Activity启动模式

  • standard
  • singletop
  • singletask
  • singleinstance

八、scheme跳转协议

android中的scheme是一种页面内跳转协议,经过定义本身的scheme协议,能够跳转到app中的各个页面

  • 服务器能够定制化告诉app跳转哪一个页面
  • App能够经过跳转到另外一个App页面
  • 能够经过H5页面跳转页面

九、Context、Activity、Application之间有什么区别

Activity和Application都是Context的子类。Context从字面上理解就是上下文的意思,在实际应用中它也确实是起到了管理上下文环境中各个参数和变量的总用,方便咱们能够简单的访问到各类资源。虽然Activity和Application都是Context的子类,可是他们维护的生命周期不同。前者维护一个Acitivity的生命周期,因此其对应的Context也只能访问该activity内的各类资源。后者则是维护一个Application的生命周期

十、Activity启动过程

  1. 在安装应用的时候,系统会启动PackaManagerService管理服务,这个管理服务会对AndroidManifest进行解析,从而获得应用程序中的相关信息,好比service,activity,Broadcast等等,而后得到相关组件的信息
  2. 当用户点击应用图标时,就会调用startActivitySately(),而这个方法内部则是调用startActivty()startActivity()最终仍是会调用startActivityForResult()。因为startActivityForResult()是有返回结果的,系统直接返回-1,表示不须要返回结果
  3. startActivityForResult()经过Instrumentation类中的execStartActivity()来启动activity,Instrumentation这个类主要做用是监控程序和系统之间的交互。在这个execStartActivity()中会获取ActivityManagerService的代理对象,经过这个代理对象进行启动activity
  4. 在ActivityManagerService的代理对象中,经过Binder通讯,调用到ApplicationThread.scheduleLaunchActivity()进行启动activity,在这个方法中建立一个ActivityClientRecord对象,用来记录启动Activity组件的信息,而后经过handler将ActivityClientRecord发送出去
  5. 在handler收到消息后,调用ActivityThread.handleLaunchActivity()启动Activity

十一、简述Activity,View,Window三者关系

  1. Activity本质是上下文,View本质是视图,Window本质是窗口
  2. Activity构造的时候会初始化一个Window,其具体实现是PhoneWindow
  3. PhoneWindow中有一个ViewRoot(View或ViewGroup),是最初始的根视图
  4. ViewRoot经过addView()将View添加到根视图上,其实是将View交给了PhoneWindow处理
  5. View的事件监听是由WindowManagerService来接受消息,而且回调Activity函数

Fragment面试题


一、Fragment为何被称为第五大组件

Fragment比Activity更节省内存,其切换模式也更加温馨,使用频率不低于四大组件,且有本身的生命周期,并且必须依附于Activity

二、Activity建立Fragment的方式

  • 静态建立
  • 动态建立

三、FragmentPageAdapter和FragmentPageStateAdapter的区别

  • FragmentPageAdapter在每次切换页面的的时候,是将Fragment进行分离,适合页面较少的Fragment使用以保存一些内存,对系统内存不会多大影响
  • FragmentPageStateAdapter在每次切换页面的时候,是将Fragment进行回收,适合页面较多的Fragment使用,这样就不会消耗更多的内存

四、Fragment生命周期

  • onAttach()
  • onCreate()
  • onCreateView()
  • onActivityCreated()
  • onStart()
  • onResume()
  • onPause()
  • onStop()
  • onDestroyView()
  • onDestroy()
  • onDetach()

五、Fragment的通讯

  • Fragment调用Activity中的方法:getActivity
  • Activity调用Fragment中的方法:接口回调
  • Fragment调用Fragment中的方法:FragmentManager.findFragmentById

六、Fragment的replace、add、remove方法

  • replace:替代Fragment的栈顶页面
  • add:添加Fragment到栈顶页面
  • remove:移除Fragment栈顶页面

Service面试题


一、Service是什么

Service是四大组件之一,它能够在后台执行长时间运行操做而没有用户界面的应用组件

二、Service和Thread的区别

  • Service是安卓中系统的组件,它运行在独立进程的主线程中,不能够执行耗时操做。Thread是程序执行的最小单元,分配CPU的基本单位,能够开启子线程执行耗时操做
  • Service在不一样Activity中能够获取自身实例,能够方便的对Service进行操做。Thread在不一样的Activity中难以获取自身实例,若是Activity被销毁,Thread实例就很难再获取获得

三、Service启动方式

  • startService
  • bindService

四、Service生命周期

  1. startService
  • onCreate()
  • onStartCommand()
  • onDestroy()
  1. bindService
  • onCreate()
  • onBind()
  • onUnbind()
  • onDestroy()

Broadcast Receiver面试题


一、Broadcast Receiver是什么

Broadcast是四大组件之一,是一种普遍运用在应用程序之间传输信息的机制,经过发送Intent来传送咱们的数据

二、Broadcast Receiver的使用场景

  • 同一App具备多个进程的不一样组件之间的消息通讯
  • 不一样App之间的组件之间的消息通讯

三、Broadcast Receiver的种类

  • 普通广播
  • 有序广播
  • 本地广播
  • Sticky广播

四、Broadcast Receiver的实现

  • 静态注册:注册后一直运行,尽管Activity、进程、App被杀死仍是能够接收到广播
  • 动态注册:跟随Activity的生命周期

五、Broadcast Receiver实现机制

  • 自定义广播类继承BroadcastReceiver,复写onReceiver()
  • 经过Binder机制向AMS进行注册广播
  • 广播发送者经过Binder机制向AMS发送广播
  • AMS查找符合相应条件的广播发送到BroadcastReceiver相应的循环队列中
  • 消息队列执行拿到广播,回调BroadcastReceiver的onReceiver()

六、LocalBroadcastManager特色

  • 本地广播只能在自身App内传播,没必要担忧泄漏隐私数据
  • 本地广播不容许其余App对你的App发送该广播,没必要担忧安全漏洞被利用
  • 本地广播比全局广播更高效
  • 以上三点都是源于其内部是用Handler实现的

WebView面试题


一、WebView安全漏洞

  • API16以前存在远程代码执行安全漏洞,该漏洞源于程序没有正确限制使用WebView.addJavascriptInterface方法,远程攻击者可经过使用Java反射机制利用该漏洞执行任意Java对象的方法

二、WebView销毁步骤

  • WebView在其余容器上时(如:LinearLayout),当销毁Activity时,须要在onDestroy()中先移除容器上的WebView,而后再将WebView.destroy(),这样就不会致使内存泄漏

三、WebView的jsbridge

  • 客户端和服务端之间能够经过Javascript来互相调用各自的方法

四、WebViewClient的onPageFinished

  • WebViewClient的onPageFinished在每次完成页面的时候调用,可是遇到未加载完成的页面跳转其余页面时,就会一直调用,使用WebChromeClient.onProgressChanged能够替代

五、WebView后台耗电

  • 在WebView加载页面的时候,会自动开启线程去加载,若是不很好的关闭这些线程,就会致使电量消耗加大,能够采用暴力的方法,直接在onDestroy方法中System.exit(0)结束当前正在运行中的java虚拟机

六、WebView硬件加速

Android3.0引入硬件加速,默认会开启,WebView在硬件加速的状况下滑动更加平滑,性能更加好,可是会出现白块或者页面闪烁的反作用,建议WebView暂时关闭硬件加速

七、WebView内存泄漏

因为WebView是依附于Activity的,Activity的生命周期和WebView启动的线程的生命周期是不一致的,这会致使WebView一直持有对这个Activity的引用而没法释放,解决方案以下

  • 独立进程,简单暴力,不过可能涉及到进程间通讯(推荐)
  • 动态添加WebView,对传入WebView中使用的Context使用弱引用

Binder面试题


一、Linux内核的基本知识

  • 进程隔离/虚拟地址空间:进程间是不能够共享数据的,至关于被隔离,每一个进程被分配到不一样的虚拟地址中
  • 系统调用:Linux内核对应用有访问权限,用户只能在应用层经过系统调用,调用内核的某些程序
  • binder驱动:它负责各个用户的进程,经过binder通讯内核来进行交互的模块

二、为何使用Binder

  • 性能上,相比传统的Socket更加高效
  • 安全性高,支持协议双方互相校验

三、Binder通讯原理

  1. Service端经过Binder驱动在ServiceManager的查找表中注册Object对象的add方法
  2. Client端经过Binder驱动在ServiceManager的查找表中找到Object对象的add方法,并返回proxy对象的add方法,add方法是个空实现,proxy对象也不是真正的Object对象,是经过Binder驱动封装好的代理类的add方法
  3. 当Client端调用add方法时,Client端会调用proxy对象的add方法,经过Binder驱动去请求ServiceManager来找到Service端真正对象,而后调用Service端的add方法

四、AIDL

  1. 客户端经过aidl文件的Stub.asInterface()方法,拿到Proxy代理类
  2. 经过调用Proxy代理类的方法,将参数进行封包后,调用底层的transact()方法
  3. transact()方法会回调onTransact()方法,进行参数的解封
  4. 在onTransact()方法中调用服务端对应的方法,并将结果返回

五、BpBinder和BBinder

BpBinder(客户端)对象和BBinder(服务端)对象,它们都从IBinder类中派生而来,BpBinder(客户端)对象是BBinder(服务端)对象的代理对象,关系图以下

  • client端:BpBinder.transact()来发送事务请求
  • server端:BBinder.onTransact()会接收到相应事务

Handler面试题


一、Handler是什么

Handler经过发送和处理Message和Runnable对象来关联相对应线程的MessageQueue

二、Handler使用方法

  • post(runnable)
  • sendMessage(message)

三、Handler工做原理

四、Handler引发的内存泄漏

  • 缘由:非静态内部类持有外部类的匿名引用,致使Activity没法释放
  • 解决:

    • Handler内部持有外部Activity的弱引用
    • Handler改成静态内部类
    • Handler.removeCallback()

AsyncTask面试题


一、AsyncTask是什么

它本质上就是一个封装了线程池和Handler的异步框架

二、AsyncTask使用方法

  • 三个参数

    • Params:表示后台任务执行时的参数类型,该参数会传给AysncTask的doInBackground()方法
    • Progress:表示后台任务的执行进度的参数类型,该参数会做为onProgressUpdate()方法的参数
    • Result:表示后台任务的返回结果的参数类型,该参数会做为onPostExecute()方法的参数
  • 五个方法

    • onPreExecute():异步任务开启以前回调,在主线程中执行
    • doInBackground():执行异步任务,在线程池中执行
    • onProgressUpdate():当doInBackground中调用publishProgress时回调,在主线程中执行
    • onPostExecute():在异步任务执行以后回调,在主线程中执行
    • onCancelled():在异步任务被取消时回调

三、AsyncTask工做原理

四、AsyncTask引发的内存泄漏

  • 缘由:非静态内部类持有外部类的匿名引用,致使Activity没法释放
  • 解决:

    • AsyncTask内部持有外部Activity的弱引用
    • AsyncTask改成静态内部类
    • AsyncTask.cancel()

五、AsyncTask生命周期

在Activity销毁以前,取消AsyncTask的运行,以此来保证程序的稳定

六、AsyncTask结果丢失

因为屏幕旋转、Activity在内存紧张时被回收等状况下,Activity会被从新建立,此时,旧的AsyncTask持有旧的Activity引用,这个时候会致使AsyncTask的onPostExecute()对UI更新无效

七、AsyncTask并行or串行

  • AsyncTask在Android 2.3以前默认采用并行执行任务,AsyncTask在Android 2.3以后默认采用串行执行任务
  • 若是须要在Android 2.3以后采用并行执行任务,能够调用AsyncTask的executeOnExecutor()

HandlerThread面试题


一、HandlerThread产生背景

当系统有多个耗时任务须要执行时,每一个任务都会开启一个新线程去执行耗时任务,这样会致使系统屡次建立和销毁线程,从而影响性能。为了解决这一问题,Google提供了HandlerThread,HandlerThread是在线程中建立一个Looper循环器,让Looper轮询消息队列,当有耗时任务进入队列时,则不须要开启新线程,在原有的线程中执行耗时任务便可,不然线程阻塞

二、HanlderThread的特色、

  • HandlerThread本质上是一个线程,继承自Thread
  • HandlerThread有本身的Looper对象,能够进行Looper循环,能够建立Handler
  • HandlerThread能够在Handler的handlerMessage中执行异步方法
  • HandlerThread优势是异步不会堵塞,减小对性能的消耗
  • HandlerThread缺点是不能同时继续进行多任务处理,须要等待进行处理,处理效率较低
  • HandlerThread与线程池不一样,HandlerThread是一个串行队列,背后只有一个线程

IntentService面试题


一、IntentService是什么

IntentService是继承自Service并处理异步请求的一个类,其内部采用HandlerThread和Handler实现的,在IntentService内有一个工做线程来处理耗时操做,其优先级比普通Service高。当任务完成后,IntentService会自动中止,而不须要手动调用stopSelf()。另外,能够屡次启动IntentService,每一个耗时操做都会以工做队列的方式在IntentService中onHandlerIntent()回调方法中执行,而且每次只会执行一个工做线程

二、IntentService使用方法

  • 建立Service继承自IntentService
  • 覆写构造方法和onHandlerIntent()方法
  • 在onHandlerIntent()中执行耗时操做

视图工做机制面试题


事件分发机制面试题


Android项目构建面试题


一、Android构建流程

[图片上传失败…(image-ccd96b-1606878198554)]

二、jenkins持续集成构建

三、git经常使用命令

  • git init:仓库的初始化
  • git status:查看当前仓库的状态
  • git diff:查看仓库与上次修改的内容
  • git add:将文件放进暂存区
  • git commit:提交代码
  • git clone:克隆代码
  • git bransh:查看当前分支
  • git checkout:切换当前分支

四、git工做流

  • fork/clone(主流)

    • fork:将别人的仓库代码fork到本身的仓库上
    • clone:克隆下本身仓库的代码
    • update、commit:修改代码并提交到本身的仓库
    • push:提交到本身的仓库
    • pull request:请求添加到别人的仓库
  • clone

五、proguard是什么

ProGuard工具是用于压缩、优化和混淆咱们的代码,其主做用是移除或混淆代码中无用类、字段、方法和属性

六、proguard技术功能

  • 压缩
  • 优化
  • 混淆
  • 预检测

七、proguard工做原理

将无用的字段或方法存入到EntryPoint中,将非EntryPoint的字段和方法进行替换

八、为何要混淆

因为Java是一门跨平台的解释性语言,其源代码被编译成class字节码来适应其余平台,而class文件包含了Java源代码信息,很容易被反编译

九、annotationProcessor与compileOnly的区别

annotationProcessor与compileOnly都是只编译并不打入apk中

  • annotationProcessor:编译时生成代码,编译完就不须要了
  • compileOnly:有重复的库时,能够剃除重复库,只保留一个库

ANR面试题


一、什么是ANR

Application Not Responding,页面无响应的对话框

二、发生ANR的条件

应用程序的响应性是由ActivityManager和WindowManager系统服务监视的,当ANR发生条件知足时,就会弹出ANR的对话框

  • Activity超过5秒无响应
  • BroadcastReceiver超过10秒无响应
  • Service超过20秒无响应

三、形成ANR的主要缘由

主线程被IO操做阻塞

  • Activity的全部生命周期回调都是执行在主线程的
  • Service默认执行在主线程中
  • BoardcastReceiver的回调onReceive()执行在主线程中
  • AsyncTask的回调除了doInBackground,其余都是在主线程中
  • 没有使用子线程Looper的Handler的handlerMessage,post(Runnable)都是执行在主线程中

四、如何解决ANR

  • 使用AsyncTask处理耗时IO操做
  • 使用Thread或HandlerThread提升优先级
  • 使用Handler处理工做线程的耗时操做
  • Activity的onCreate和onResume回调尽可能避免耗时操做

OOM面试题


一、什么是OOM

OOM指Out of memory(内存溢出),当前占用内存加上咱们申请的内存资源超过了Dalvik虚拟机的最大内存限制就会抛出Out of memory异常

二、OOM相关概念

  • 内存溢出:指程序在申请内存时,没有足够的空间供其使用
  • 内存泄漏:指程序分配出去的内存再也不使用,没法进行回收
  • 内存抖动:指程序短期内大量建立对象,而后回收的现象

三、解决OOM

Bitmap相关

  • 图片压缩
  • 加载缩略图
  • 在滚动时不加载图片
  • 回收Bitmap
  • 使用inBitmap属性
  • 捕获异常

其余相关

  • listview重用convertView、使用lru
  • 避免onDraw方法执行对象的建立
  • 谨慎使用多进程

Bitmap面试题


一、recycle

  • 在安卓3.0之前Bitmap是存放在堆中的,咱们只要回收堆内存便可
  • 在安卓3.0之后Bitmap是存放在内存中的,咱们须要回收native层和Java层的内存
  • 官方建议咱们3.0之后使用recycle方法进行回收,该方法也能够不主动调用,由于垃圾回收器会自动收集不可用的Bitmap对象进行回收
  • recycle方法会判断Bitmap在不可用的状况下,将发送指令到垃圾回收器,让其回收native层和Java层的内存,则Bitmap进入dead状态
  • recycle方法是不可逆的,若是再次调用getPixels()等方法,则获取不到想要的结果

二、LruCache原理

LruCache是个泛型类,内部采用LinkedHashMap来实现缓存机制,它提供get方法和put方法来获取缓存和添加缓存,其最重要的方法trimToSize是用来移除最少使用的缓存和使用最久的缓存,并添加最新的缓存到队列中

三、计算采样率

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {
        if (width > height) {
            inSampleSize = Math.round((float)height / (float)reqHeight);
        } else {
            inSampleSize = Math.round((float)width / (float)reqWidth);
        }
    }
    return inSampleSize;
}

四、采样率压缩(缩略图)

public static Bitmap thumbnail(String path,int maxWidth, int maxHeight) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    Bitmap bitmap = BitmapFactory.decodeFile(path, options);
    options.inJustDecodeBounds = false;
    int sampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
    options.inSampleSize = sampleSize;
    options.inPreferredConfig = Bitmap.Config.RGB_565;
    options.inPurgeable = true;
    options.inInputShareable = true;
    if (bitmap != null && !bitmap.isRecycled()) {
        bitmap.recycle();
    }
    bitmap = BitmapFactory.decodeFile(path, options);
    return bitmap;
}

五、质量压缩

public static String save(Bitmap bitmap,Bitmap.CompressFormat format, int quality, File destFile) {
    try {
        FileOutputStream out = new FileOutputStream(destFile);
        if (bitmap.compress(format, quality, out)) {
            out.flush();
            out.close();
        }
        if (bitmap != null && !bitmap.isRecycled()) {
            bitmap.recycle();
        }
        return destFile.getAbsolutePath();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

六、尺寸压缩

public static void reSize(Bitmap bmp,File file,int ratio){
    Bitmap result = Bitmap.createBitmap(bmp.getWidth()/ratio, bmp.getHeight()/ratio,Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(result);
    RectF rect = new RectF(0, 0, bmp.getWidth()/ratio, bmp.getHeight()/ratio);
    canvas.drawBitmap(bmp, null, rect , null);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    result.compress(Bitmap.CompressFormat.JPEG, 100, baos);
    try {
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(baos.toByteArray());
        fos.flush();
        fos.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

七、保存到SD卡

public static String save(Bitmap bitmap,Bitmap.CompressFormat format, int quality, Context context) {
    if (!Environment.getExternalStorageState()
            .equals(Environment.MEDIA_MOUNTED)) {
        return null;
    }
    File dir = new File(Environment.getExternalStorageDirectory()
            + "/" + context.getPackageName() + "/save/");
    if (!dir.exists()) {
        dir.mkdirs();
    }
    File destFile = new File(dir, UUID.randomUUID().toString());
    return save(bitmap, format, quality, destFile);
}

八、三级缓存

  • 网络缓存
  • 本地缓存
  • 内存缓存

九、NDK压缩

Android进阶——图片优化之质量压缩、尺寸压缩、采样率压缩、LibJpeg压缩

十、webp压缩

Android Webp 彻底解析 快来缩小apk的大小吧-鸿洋的博客

UI卡顿面试题


一、UI卡顿原理

View的绘制帧数保持60fps是最佳,这要求每帧的绘制时间不超过16ms(1000/60),若是安卓不能在16ms内完成界面的渲染,那么就会出现卡顿现象

二、UI卡顿的缘由分析

  • 在UI线程中作轻微的耗时操做,致使UI线程卡顿
  • 布局Layout过于复杂,没法在16ms内完成渲染
  • 同一时间动画执行的次数过多,致使CPU和GPU负载太重
  • overDraw,致使像素在同一帧的时间内被绘制屡次,使CPU和GPU负载太重
  • View频繁的触发measure、layout,致使measure、layout累计耗时过多和整个View频繁的从新渲染
  • 频繁的触发GC操做致使线程暂停,会使得安卓系统在16ms内没法完成绘制
  • 冗余资源及逻辑等致使加载和执行缓慢
  • ANR

三、UI卡顿的优化

  • 布局优化

    • 使用include、ViewStub、merge
    • 不要出现过于嵌套和冗余的布局
    • 使用自定义View取代复杂的View
  • ListView优化

    • 复用convertView
    • 滑动不加载
  • 背景和图片优化

    • 缩略图
    • 图片压缩
  • 避免ANR

    • 不要在UI线程中作耗时操做

内存泄漏面试题


一、Java内存泄漏引发的主要缘由

长生命周期的对象持有短生命周期对象的引用就极可能发生内存泄漏

二、Java内存分配策略

  • 静态存储区:又称方法区,主要存储全局变量和静态变量,在整个程序运行期间都存在
  • 栈区:方法体的局部变量会在栈区建立空间,并在方法执行结束后会自动释放变量的空间和内存
  • 堆区:保存动态产生的数据,如:new出来的对象和数组,在不使用的时候由Java回收器自动回收

三、Android解决内存泄漏的例子

  • 单例形成的内存泄漏:在单例中,使用context.getApplicationContext()做为单例的context
  • 匿名内部类形成的内存泄漏:因为非静态内部类持有匿名外部类的引用,必须将内部类设置为static
  • Handler形成的内存泄漏:使用static的Handler内部类,同时在实现内部类中持有Context的弱引用
  • 避免使用static变量:因为static变量会跟Activity生命周期一致,当Activity退出后台被后台回收时,static变量是不安全,因此也要管理好static变量的生命周期
  • 资源未关闭形成的内存泄漏:好比Socket、Broadcast、Cursor、Bitmap、ListView等,使用完后要关闭
  • AsyncTask形成的内存泄漏:因为非静态内部类持有匿名内部类的引用而形成内存泄漏,能够经过AsyncTask内部持有外部Activity的弱引用同时改成静态内部类或在onDestroy()中执行AsyncTask.cancel()进行修复

内存管理面试题


一、Android内存管理机制

  • 分配机制
  • 管理机制

二、内存管理机制的特色

  • 更少的占用内存
  • 在合适的时候,合理的释放系统资源
  • 在系统内存紧张的时候,能释放掉大部分不重要的资源
  • 能合理的在特殊生命周期中,保存或还原重要数据

三、内存优化方法

  • Service完成任务后应中止它,或用IntentService(由于能够自动中止服务)代替Service
  • 在UI不可见的时候,释放其UI资源
  • 在系统内存紧张的时候,尽量多的释放非重要资源
  • 避免滥用Bitmap致使内存浪费
  • 避免使用依赖注入框架
  • 使用针对内存优化过的数据容器
  • 使用ZIP对齐的APK
  • 使用多进程

冷启动和热启动面试题


一、什么是冷启动和热启动

  • 冷启动:在启动应用前,系统中没有该应用的任何进程信息
  • 热启动:在启动应用时,在已有的进程上启动应用(用户使用返回键退出应用,而后立刻又从新启动应用)

二、冷启动和热启动的区别

  • 冷启动:建立Application后再建立和初始化MainActivity
  • 热启动:建立和初始化MainActivity便可

三、冷启动时间的计算

这个时间值从应用启动(建立进程)开始计算,到完成视图的第一次绘制为止

四、冷启动流程

  • Zygote进程中fork建立出一个新的进程
  • 建立和初始化Application类、建立MainActivity
  • inflate布局、当onCreate/onStart/onResume方法都走完
  • contentView的measure/layout/draw显示在界面上

总结:点击App->IPC->Process.start->ActivityThread->Application生命周期->Activity生命周期->ViewRootImpl测量布局绘制显示在界面上

五、冷启动优化

  • 减小第一个界面onCreate()方法的工做量
  • 不要让Application参与业务的操做
  • 不要在Application进行耗时操做
  • 不要以静态变量的方式在Application中保存数据
  • 减小布局的复杂性和深度
  • 不要在mainThread中加载资源
  • 经过懒加载方式初始化第三方SDK

六、adb命令获取启动时间

adb shell am start -W packagename/MainActivity
  • ThisTime:最后一个Activity启动耗时
  • TotalTime:全部Activity启动耗时
  • WaitTime:AMS启动Activity的总耗时

其余优化面试题


一、Android不用静态变量存储数据

  • 静态变量等数据因为进程已经被杀死而被初始化
  • 使用其余数据传输方式:文件/sp/contentProvider

二、SharePreference安全问题

  • 不能跨进程同步
  • 文件不宜过大

三、内存对象序列化

  • Serializeble:是java的序列化方式,Serializeble在序列化的时候会产生大量的临时对象,从而引发频繁的GC
  • Parcelable:是Android的序列化方式,且性能比Serializeble高,Parcelable不能使用在要将数据存储在硬盘上的状况

四、避免在UI线程中作繁重的操做

架构模式面试题


插件化面试题


一、插件化解决的问题

  • 动态加载APK(反射、类加载器)
  • 资源加载(反射、AssetManager、独立资源、分段资源)
  • 代码加载(反射获取生命周期)

二、类加载器(Java中字节码添加到虚拟机中)

  • DexClassLoader:可以加载未安装的jar/apk/dex,主要用于动态加载和代码热更新
  • PathClassLoader:加载/data/app目录下的apk文件,只要用来加载系统中已经安装过的apk

热更新面试题


一、热更新主要流程

  • 线上检查到Crash
  • 拉出Bugfix分支修复Crash问题
  • jenkins构建和补丁生成
  • app经过推送或主动拉取补丁文件
  • 将Bugfix代码合到master上

二、热更新主流框架

  • Dexposed
  • AndFix
  • Nuwa

三、热更新的原理

  • 在ClassLoader建立一个dexElements数组
  • 将修复好的dex文件存放在dexElements数组的最前面
  • ClassLoader会遍历dexElements数组,找到最前面的dex文件优先加载

进程保活面试题


一、进程的优先级

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

二、Android进程回收策略

  • Low memory Killer(定时执行):经过一些比较复杂的评分机制,对进程进行打分,而后将分数高的进程断定为bad进程,杀死并释放内存
  • OOM_ODJ:判别进程的优先级

三、Android保活方案

  • 利用系统广播拉活
  • 利用系统Service机制拉活
  • 利用Native进程拉活
  • 利用JobScheduler机制拉活
  • 利用帐号同步机制拉活

Lint面试题


一、什么是Android Lint

Android Lint是一个静态代码分析工具,它可以对你的Android项目中潜在的Bug、可优化的代码、安全性、性能、可用性、可访问性、国际化等进行检查

二、Lint工做流程

[图片上传失败…(image-d5f5ab-1606878198551)]

三、配置Lint

  • 建立Lint.xml到根目录下,自定义Lint安全等级等
  • 在Java文件中可使用@suppressLint(“NewApi”)来忽视Lint的报错
  • 在xml文件中可使用tool:ignore(“UnusedResources”)来忽视Lint的报错
  • 自定义Lint检查,能够建立类,继承Detector和实现JavaPsiScanner

Kotlin面试题


一、什么是Kotlin

  • Kotlin是一种基于JVM的编程语言
  • 对Java的一种拓展,比Java更简洁
  • Kotlin支持函数式编程
  • Kotlin类和Java类能够相互调用

二、Kotlin环境搭建

  • 直接在Plugin中下载Kotlin插件便可
  • 系统会自动配置到Kotlin环境

虚拟机面试题


一、Dalvik与JIT

Dalvik是Android虚拟机,JIT则是Dalvik采用的技术策略

在编译打包APK文件时,会通过如下流程Java->Class->Dalvik字节码(dex)->每次执行代码都要编译成机器码->交给底层处理,这样处理起来效率低下,经过引入JIT(即时编译技术),当App运行时,每当遇到一个新类,JIT编译器就会对这个类进行即时编译,通过编译后的代码,会被优化成至关精简的原生型指令码,这样在下次执行到相同逻辑的时候,速度就会更快。但因为每次启动App都须要即时编译,致使运行时耗电量大

二、ART与AOT

ART是Android虚拟机,AOT则是ART采用的技术策略

在ART环境中,应用在第一次安装的时候,字节码就会预先编译成机器码,使其成为真正的本地应用,这一技术称为AOT。以后打开App的时候,不须要额外的翻译工做,直接使用本地机器码运行,所以运行速度提升。但因为会预先编译,安装时间不免会延长,并且会消耗更多的存储空间,但消耗掉空间的增幅一般不会超过应用代码包大小的20%

三、发展史

  • 2.2 ~ 4.4:Dalvik虚拟机使用JIT技术
  • 4.4 ~ 5.0:Dalvik虚拟机和ART虚拟机共存
  • 5.0 ~ x.0:ART虚拟机使用AOT技术替代Dalvik虚拟机

四、JVM与Dalvik不一样

  • 类加载系统区别比较大
  • JVM是基于栈,Dalvik是基于寄存器
  • JVM执行的是java字节码文件,Dalvik执行的是dex字节码文件
  • Dalvik能够同时存在多个,即便一个退出了也不会影响其余程序

五、Dalvik与ART不一样

  • Dalvik使用JIT(Just In Time 运行时编译)来将字节码转换成机器码,效率低
  • ART采用AOT(Ahead Of Time 运行前编译或安装时编译)预编译技术,应用运行速度更快
  • ART会占用更多的应用安装时间和存储空间

注解面试题


一、什么是Annotation

Java提供的一种元程序中的元素关联任何信息和任何元数据(metadata)的途径和方法

二、什么是metadata

  1. 元数据以标签的形式存在于Java代码中
  2. 元数据描述的信息是类型安全的
  3. 元数据须要编译器以外的工具额外的处理用来生成其余的程序部件
  4. 元数据能够只存在于Java源代码级别,也能够存在于编译以后的Class文件内部

三、注解分类

  1. 系统内置标准注解

    • @Override:表示重写
    • @Deprecated:表示已过期
    • @SuppressWarnnings:表示抑制警告
  2. 元注解

    • @Target:表示注解的修饰范围
    • @Retention:表示注解的代码生存期
    • @Documented:表示注解为程序员的API
    • @Inherited:表示注解能够继承
  3. @Target

    • ElementType.CONSTRUCTOR:构造器声明
    • ElementType.FIELD:成员变量、对象、属性(包括enum实例)
    • ElementType.LOCAL_VARIABLE:局部变量声明
    • ElementType.METHOD:方法声明
    • ElementType.PACKAGE:包声明
    • ElementType.PARAMETER:参数声明
    • ElementType.TYPE:类、接口(包括注解类型)或enum声明
  4. @Retention

    • RetentionPolicy.SOURCE:在源文件中有效,当Java文件编译成class文件的时候,注解被遗弃
    • RetentionPolicy.CLASS:在class文件中有效,当jvm加载class文件时候被遗弃
    • RetentionPolicy.RUNTIME:在运行时有效,当jvm加载class文件以后,仍然存在
  5. 生命周期

    • RUNTIME > CLASS > SOURCE
    • .java文件 --> .class文件 --> 内存中的字节码

四、注解声明

注解支持填写数组,同时支持多种范围

@Target({ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ModuleWrapper {}

五、Android Support Annotation

  • Nullness注解(@NonNull、@Nullable):表示指定的空类型或非空类型
  • ResourceType注解(@StringRes、@IntegerRes、@ColorRes等):表示指定的变量类型
  • Threading注解(@WorkerThread、@UIThread、@MainThread等):表示指定的线程类型
  • Range注解(@IntRange、@FloatRange等):表示容许传值的范围
  • OverridingMethods注解(@CallSuper等):表示调用父类的方法

六、注解的用途

  • 约束类
  • 约束变量
  • 约束入参
  • 约束返回值

网络面试题

1.网页中输入url,到渲染整个界面的整个过程,以及中间用了什么协议?

1)过程分析:主要分为三步

  • DNS解析。用户输入url后,须要经过DNS解析找到域名对应的ip地址,有了ip地址才能找到服务器端。首先会查找浏览器缓存,是否有对应的dns记录。再继续按照操做系统缓存—路由缓存—isp的dns服务器—根服务器的顺序进行DNS解析,直到找到对应的ip地址。
  • 客户端(浏览器)和服务器交互。浏览器根据解析到的ip地址和端口号发起HTTP请求,请求到达传输层,这里也就是TCP层,开始三次握手创建链接。服务器收到请求后,发送相应报文给客户端(浏览器),客户端收到相应报文并进行解析,获得html页面数据,包括html,js,css等。
  • 客户端(浏览器)解析html数据,构建DOM树,再构造呈现树(render树),最终绘制到浏览器页面上。

2)其中涉及到TCP/IP协议簇,包括DNS,TCP,IP,HTTP协议等等。

2.具体介绍下TCP/IP

TCP/IP通常指的是TCP/IP协议簇,主要包括了多个不一样网络间实现信息传输涉及到的各类协议
主要包括如下几层:

  • 应用层:主要提供数据和服务。好比HTTP,FTP,DNS等
  • 传输层:负责数据的组装,分块。好比TCP,UDP等
  • 网络层:负责告诉通讯的目的地,好比IP等
  • 数据链路层:负责链接网络的硬件部分,好比以太网,WIFI等

3.TCP的三次握手和四次挥手,为何不是两次握手?为何挥手多一次呢?

客户端简称A,服务器端简称B
1)TCP创建链接须要三次握手

  • A向B表示想跟B进行链接(A发送syn包,A进入SYN_SENT状态)
  • B收到消息,表示我也准备好和你链接了(B收到syn包,须要确认syn包,而且本身也发送一个syn包,即发送了syn+ack包,B进入SYN_RECV状态)
  • A收到消息,并告诉B表示我收到你也准备链接的信号了(A收到syn+ack包,向服务器发送确认包ack,AB进入established状态)开始链接。

2)TCP断开链接须要四次挥手

  • A向B表示想跟B断开链接(A发送fin,进入FIN_WAIT_1状态)
  • B收到消息,可是B消息没发送完,只能告诉A我收到你的断开链接消息(B收到fin,发送ack,进入CLOSE_WAIT状态)
  • 过一会,B数据发送完毕,告诉A,我能够跟你断开了(B发送fin,进入LAST_ACK状态)
  • A收到消息,告诉B,能够他断开(A收到fin,发送ack,B进入closed状态)

3)为何挥手多一次
其实正常的断开和链接都是须要四次

  • A发消息给B
  • B反馈给A表示正确收到消息
  • B发送消息给A
  • A反馈给B表示正确收到消息。

可是链接中,第二步和第三步是能够合并的,由于链接以前A和B是无联系的,因此没有其余状况须要处理。而断开的话,由于以前两端是正常链接状态,因此第二步的时候不能保证B以前的消息已经发送完毕,因此不能立刻告诉A要断开的消息。这就是链接为何能够少一步的缘由。

4)为何链接须要三次,而不是两次。
正常来讲,我给你发消息,你告诉我能收到,不就表明咱们以前通讯是正常的吗?

  • 简单回答就是,TCP是双向通讯协议,若是两次握手,不能保证B发给A的消息正确到达。

TCP 协议为了实现可靠传输, 通讯双方须要判断本身已经发送的数据包是否都被接收方收到, 若是没收到, 就须要重发。

TCP是怎么保证可靠传输的?

  • 序列号和确认号。好比链接的一方发送一段80byte数据,会带上一个序列号,好比101。接收方收到数据,回复确认号181(180+1),这样下一次发送消息就会从181开始发送了。

因此握手过程当中,好比A发送syn信号给B,初始序列号为120,那么B收到消息,回复ack消息,序列号为120+1。同时B发送syn信号给A,初始序列号为256,若是收不到A的回复消息,就会重发,不然丢失这个序列号,就没法正常完成后面的通讯了。

这就是三次握手的缘由。

4.TCP和UDP的区别?

TCP提供的是面向链接,可靠的字节流服务。即客户和服务器交换数据前,必须如今双方之间创建一个TCP链接(三次握手),以后才能传输数据。而且提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另外一端。

UDP 是一个简单的面向数据报的运输层协议。它不提供可靠性,只是把应用程序传给IP层的数据报发送出去,可是不能保证它们能到达目的地。因为UDP在传输数据报前不用再客户和服务器之间创建一个链接,且没有超时重发等机制,因此传输速度很快。

因此总结下来就是:

  • TCP 是面向链接的,UDP 是面向无链接的
  • TCP数据报头包括序列号,确认号,等等。相比之下UDP程序结构较简单。
  • TCP 是面向字节流的,UDP 是基于数据报的
  • TCP 保证数据正确性,UDP 可能丢包
  • TCP 保证数据顺序,UDP 不保证

能够看到TCP适用于稳定的应用场景,他会保证数据的正确性和顺序,因此通常的浏览网页,接口访问都使用的是TCP传输,因此才会有三次握手保证链接的稳定性。
而UDP是一种结构简单的协议,不会考虑丢包啊,创建链接等。优势在于数据传输很快,因此适用于直播,游戏等场景。

5.HTTP的几种请求方法具体介绍

常见的有四种:

  • GET 获取资源,没有body,幂等性
  • POST 增长或者修改资源,有body
  • PUT 修改资源,有body,幂等性
  • DELETE 删除资源,幂等性

6.HTTP请求和响应报文的格式,以及经常使用状态码

1)请求报文:

//请求行(包括method、path、HTTP版本)
   GET /s HTTP/1.1
   //Headers
   Host: www.baidu.com
   Content-Type: text/plain
   //Body
   搜索****

2)响应报文

//状态行 (包括HTTP版本、状态码,状态信息)
   HTTP/1.1 200 OK
   //Headers
   Content-Type: application/json; charset=utf-8
   //Body
   [{"info":"xixi"}]

3)经常使用状态码

主要分为五种类型:

  • 1开头, 表明临时性消息,好比100(继续发送)
  • 2开头, 表明请求成功,好比200(OK)
  • 3开头, 表明重定向,好比304(内容无改变)
  • 4开头, 表明客户端的一些错误,好比403(禁止访问)
  • 5开头, 表明服务器的一些错误,好比500
    出于篇幅的考量,本文不可能对Android面试大纲全部面试模块做出说明。即使如此,沿着本文提供的思路,参考相关章节内容,分析相关知识点和源码,你会很快、很容易地拿到一线互联网企业的offer。
    Android工程师之Android面试大纲PDF
文档领取方式:点赞+关注,而后私信关键词 【1】便可得到免费领取方式!
相关文章
相关标签/搜索