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】便可得到免費領取方式!
相關文章
相關標籤/搜索