答應我,我踩過的坑你別再踩了好嘛,那些年社招的坑坑窪窪

回想起前年左右,本身去社招的時候,一連串下來問了好多如今都是歷歷在目。回想起之前才以爲 紙上得來終覺淺,絕知此事要躬行

全部的面試題答案並非百分百的標準,要靠你本身的感悟和有本身的想法,才能獨樹一幟脫穎而出的。全部僅供參考

全部的都在這個PDF中有所彙總,983頁花了幾十個小時整理出來的。仍是比較全面的有Android,Java小知識,到性能優化.線程.View.OpenCV.NDK.大廠面試,算法等等,你們能夠聯繫我看看對自身有沒有用android

(更多完整項目下載。未完待續。源碼。圖文知識後續上傳github。)
能夠點擊關於我聯繫我獲取完整PDF
( VX:mm14525201314)

1丶如何進行單元測試,如何保證 App 穩定 ?

要測試 Android 應用程序,一般會建立如下類型自動單元測試
  • 本地測試: 只在本地機器 JVM 上運行,以最小化執行時間,這種單元測試不依賴於 Android 框架,或者即便有依賴,也很方便使用模擬框架來模擬依賴,以達到隔離 Android 依賴的目的,模擬框架如Google 推薦的 Mockito;
  • 檢測測試: 真機或模擬器上運行的單元測試,因爲須要跑到設備上,比較慢,這些測試能夠訪問儀器(Android 系統)信息,好比被測應用程序的上下文,通常地,依賴不太方便經過模擬框架模擬時採用這種方式;

注意: 單元測試不適合測試複雜的 UI 交互事件git

  • App 的穩定主要決定於總體的系統架構設計,同時也不可忽略代碼編程的細節規範,正所謂「千里之堤,潰於蟻穴」,一旦考慮不周,看似可有可無的代碼片斷可能會帶來總體軟件系統的崩潰,因此上線以前除了本身 本地化測試以外還須要進行 y Monkey 壓力測試
  • 少部分面試官可能會延伸,如 Gradle 自動化測試、機型適配測試等

2 、 Android 中如何查看一個對象的回收狀況 ?

首先要了解 Java 四種引用類型的場景和使用(強引用、軟引用、弱引用、虛引用)github

  • 舉個場景例子: SoftReference 對象是用來保存軟引用的,但它同時也是一個 Java 對象,因此當軟引用對象被回收以後,雖然這個 SoftReference 對象的 get 方法返回null,但 SoftReference 對象自己並非 null,而此時這個 SoftReference 對象已經再也不具備存在的價值,須要一個適當的清除機制,避免大量SoftReference 對象帶來的內存泄露
  • 所以,Java 提供 ReferenceQueue 來處理引用對象的回收狀況。當 SoftReference 所引用的對象被 GC 後,JVM 會先將 softReference 對象添加到ReferenceQueue 這個隊列中。當咱們調用 ReferenceQueue 的 的 poll() 方法,若是這個隊列中不是空隊列,那麼將返回並移除前面添加的那個Reference 對象
public static void main(String[] args) throws InterruptedException {
          
          //假設當前JVM內存只有8m
         Person person = new Person( "/K=" );
         ReferenceQueue Person> queue = new ReferenceQueue>( );
         Sof tReference Person> softReference = new SoftReference<Person>(person, queue );

         реrѕоn = null;// 去掉強引用, new Person ( "/K=" );的這個對象只有軟引用了

         Person anotherPerson = new Person( "/L=" )//沒有足夠的空間同事保留兩個Person對象,因此觸發GC機制
         Thread.sleep(1000);

         Sys tem. err . println( "軟引用的對象 ------" > softReference.get( ));

         Reference softPollRef = queue . poll( );
         if (softPollRef != null) f
              System.err.println( " SoftReference對象中保存的軟引用對象已經被GC,準備清理SoftReference對象");
                //清理softReference
         }
}

3丶壓縮APK大小

一個完整 APK 包含如下目錄(將 APK 文件拖到 Android Studio):
  • META-INF/: 包含 CERT.SFCERT.RSA 簽名文件以及 MANIFEST.MF 清單文件。
  • assets/: 包含應用可使用 AssetManager 對象檢索的應用資源。
  • res/: 包含未編譯到的資源 resources.arsc
  • lib/: 包含特定於處理器軟件層的編譯代碼。該目錄包含了每種平臺的子目錄,像 armeabi armeabi-v7aarm64-v8ax86x86_64 ,和mips
  • resources.arsc 包含已編譯的資源。該文件包含res/values/ 文件夾全部配置中的 XML 內容。打包工具提取此 XML 內容,將其編譯爲二進制格式,並將內容歸檔。此內容包括語言字符串和樣式,以及直接包含在resources.arsc8 文件中的內容路徑 ,例如佈局文件和圖像。
  • classes.dex:包含以 Dalvik / ART 虛擬機可理解的X DEX 文件格式編譯的類。
  • AndroidManifest.xml 包含核心 Android 清單文件。該文件列出應用程序的名稱,版本,訪問權限和引用的庫文件.該文件使用 Android 的二進制XML 格式。

  • libclass.dex 和 res 佔用了超過 90%的空間,因此這三塊是優化 Apk 大小的重點(實際狀況不惟一)
減小 res ,壓縮圖文文件

圖片文件壓縮是針對 jpgpng 格式的圖片。咱們一般會放置多套不一樣分辨率的圖片以適配不一樣的屏幕,這裏能夠進行適當的刪減。在實際使用中,只保留一到兩套就足夠了(保留一套的話建議保留xxhdpi,兩套的話就加上 hdpi),而後再對剩餘的圖片進行壓縮(jpg 採用優圖壓縮,png 嘗試採用pngquant 壓縮)面試

減小 dex
  • 添加資源混淆
buildTypes {
      release  {
            shrinkResources true
            minifyEnabled  true
            proguardFiles  getDefaultProguardFile("proguard-android. txt"),’proguard-rules.pro’
      }
}
  • shrinkResources 爲 true 表示移除未引用資源,和代碼壓縮協同工做。
  • minifyEnabled 爲 true 表示經過 ProGuard 啓用代碼壓縮,配合 proguardFiles 的配置對代碼進行混淆並移除未使用的代碼。
  • 代碼混淆在壓縮 apk 的同時,也提高了安全性。
減小 lib
  • 因爲引用了不少第三方庫,lib 文件夾佔用的空間一般都很大,特別是有 so 庫的狀況下。不少 so 庫會同時引入 armeabiarmeabi-v7ax86 這幾種類型,這裏能夠只保留 armeabiarmeabi-v7a 的其中一個就能夠了,實際上微信等主流 app 都是這麼作的。
  • 只需在 build.gradle 直接配置便可,NDK 配置同理
defaultConfig {
      ndk  {
             abiFilters 'armeabi'
      }
}

4丶插件化原理分析

插件化是指將 APK 分爲 宿主插件的部分。把須要實現的模塊或功能當作一個獨立的提取出來,在 APP 運行時,咱們能夠動態的 載入或者 替換插件部分,減小 宿主的規模算法

  • 宿主: 就是當前運行的 APP。
  • 插件: 相對於插件化技術來講,就是要加載運行的apk 類文件

熱修復則是從修復 bug 的角度出發,強調的是在不須要二次安裝應用的前提下修復已知的 bug。編程

類加載機制:

Android 中經常使用的兩種類加載器, DexClassLoaderPathClassLoader,它們都繼承於BaseDexClassLoader,二者 區別在於PathClassLoader 只能加載 內部存儲目錄dex/jar/apk 文件。DexClassLoader 支持加載 指定目錄(不限於內部)的 dex/jar/apk 文件緩存

插件通訊:

經過給插件 apk 生成相應的 DexClassLoader 即可以訪問其中的類,可分爲單 DexClassLoader 和多DexClassLoader 兩種結構。安全

  • 若使用多 ClassLoader 機制,主工程引用插件中類須要先經過插件的 ClassLoader 加載該類再經過 反

射調用其方法。插件化框架通常會經過統一的入口去管理對各個插件中類的訪問,而且作必定的限制。性能優化

  • 若使用單 ClassLoader 機制,主工程則能夠 直接經過類名去訪問插件中的類。該方式有個弊端,若兩個不一樣的插件工程引用了一個庫的不一樣版本,則程序可能會出錯。
資源加載:

原理在於經過反射將插件 apk 的路徑加入AssetManager 中並建立 Resource 對象加載資源,有兩種處理方式:微信

  • 合併式: addAssetPath 時加入全部插件和主工程的路徑;因爲 AssetManager 中加入了全部插件和主工程的路徑,所以生成的Resource 能夠同時訪問插件和主工程的資源。可是因爲主工程和各個插件都是獨立編譯的,生成的資源 id 會存在相同的狀況,在訪問時會產生資源衝突。
  • 獨立式: 各個插件只添加本身 apk 路徑,各個插件的資源是互相隔離的,不過若是想要實現資源的共享,必須拿到對應的 Resource對象。

5 、組件化原理

引入組件化的緣由: 項目隨着需求的增長規模變得愈來愈大,規模的增大致使了各類業務錯中複雜的交織在一塊兒,每一個業務模塊之間,代碼沒有約束,帶來了代碼邊界的模糊,代碼衝突時有發生, 更改一個小問題可能引發一些新的問題, 牽一髮而動全身,增長一個新需求,須要熟悉相關的代碼邏輯,增長開發時間

  • 避免重複造輪子,能夠節省開發和維護的成本。
  • 能夠經過組件和模塊爲業務基準合理地安排人力,提升開發效率。
  • 不一樣的項目能夠共用一個組件或模塊,確保總體技術方案的統一性。
  • 爲將來插件化共用同一套底層模型作準備。

組件化開發流程就是把一個功能完整的 App 或模塊拆分紅多個子模塊( Module ),每一個子模塊能夠 獨立編譯運行,也能夠任意組合成另外一個新的 App 或模塊,每一個模塊即不相互依賴但又能夠相互交互,可是最終發佈的時候是將這些組件合併統一成一個 apk,遇到某些特殊狀況甚至能夠升級或者

六、跨組件通訊

跨組件通訊場景:
  • 第一種是組件之間的頁面跳轉 (Activity 到Activity, Fragment 到 Fragment, Activity 到Fragment, Fragment 到 Activity) 以及跳轉時的數據傳遞 (基礎數據類型和可序列化的自定義類型)
  • 第二種是組件之間的自定義類和自定義方法的調用(組件向外提供服務)
跨組件通訊方案分析:
  • 第一種 組件之間的頁面跳轉實現簡單,跳轉時想傳遞不一樣類型的數據提供有相應的 API 便可。
  • 第二種組件之間的自定義類和 自定義方法的調用要稍微複雜點,須要 ARouter 配合架構中的 公共服務(CommonService) 實現:

    • 提供服務的業務模塊: 在公共服務(CommonService) 中聲明 Service接口 (含有須要被調用的自定義方法), 而後在本身的模塊中實現這個 Service 接口, 再經過 ARouter API 暴露實現類。
    • 使用服務的業務模塊: 經過 ARouter 的 API 拿到這個Service 接口(多態持有, 實際持有實現類), 便可調用 Service 接口中聲明的自定義方法, 這樣就能夠達到模塊之間的交互。
  • 此外,可使用 AndroidEventBus 其獨有的Tag, 能夠在開發時更容易定位發送事件和接受事件的代碼, 若是以組件名來做爲 Tag 的前綴進行分組, 也能夠更好的統一管理和查看每一個組件的事件, 固然也不建議你們過多使用 EventBus
如何管理過多的路由表?
  • RouterHub 存在於基礎庫, 能夠被看做是全部組件都須要遵照的通信協議, 裏面不只能夠放路由地址常量, 還能夠放跨組件傳遞數據時命名的各類 Key 值,再配以適當註釋, 任何組件開發人員不須要事先溝通只要依賴了這個協議, 就知道了各自該怎樣協同工做, 既提升了效率又下降了出錯風險, 約定的東西天然要比口頭上說強。
  • Tips: 若是您以爲把每一個路由地址都寫在基礎庫的RouterHub 中, 太麻煩了, 也能夠在每一個組件內部創建一個私有 RouterHub, 將不須要跨組件的路由地址放入私有 RouterHub 中管理, 只將須要跨組件的路由地址放入基礎庫的公有 RouterHub 中管理, 若是您不須要集中管理全部路由地址的話, 這也是比較推薦的一種方式。
ARouter 路由原理:

ARouter 維護了一個路由表 Warehouse,其中保存着所有的模塊跳轉關係,ARouter 路由跳轉實際上仍是調用了 startActivity 的跳轉,使用了原生的Framework 機制,只是經過 apt 註解的形式製造出跳轉規則,並人爲地攔截跳轉和設置跳轉條件

7 、 Hook 以及插樁技術

Hook 是一種用於 改變 API執行結果的技術,可以將系統的API 函數執行 重定向(應用的 觸發事件後臺邏輯處理是根據事件流程一步步地向下執行。而 Hook 的意思,就是在事件傳送到終點前截獲並監控事件的傳輸,像個鉤子鉤上事件同樣,而且可以在鉤上事件時,處理一些本身特定的事件,例如逆向破解 App)

Android 中的 Hook 機制,大體有兩個方式:
  • 要 root 權限,直接 Hook 系統,能夠幹掉全部的App。
  • 無 root 權限,可是隻能 Hook 自身 app,對系統其它 App 無能爲力。

插樁是以靜態的方式修改第三方的代碼,也就是從編譯階段,對源代碼(中間代碼)進行編譯,然後從新打包,是靜態的篡改; 而 Hook則不須要再編譯階段修改第三方的源碼或中間代碼,是在運行時經過反射的方式修改調用,是一種 動態的篡改

8 、說下 Measurepec 這個類

做用: 經過寬測量值 widthMeasureSpec 和高測量值heightMeasureSpec 決定 View 的大小

組成: 一個 32 位 int 值,高 2 位表明 SpecMode(測量模式),低 30 位表明 SpecSize( 某種測量模式下的規格大小)。

三種模式:

  • UNSPECIFIED: 父容器不對 View 有任何限制,要多大有多大。經常使用於系統內部。
  • EXACTLY(精確模式): 父視圖爲子視圖指定一個確切的尺寸 SpecSize。對應 LyaoutParams 中的match_parent 或具體數值。
  • AT_MOST(最大模式): 父容器爲子視圖指定一個最大尺寸 SpecSize,View 的大小不能大於這個值。對應LayoutParams 中的 wrap_content。

9丶圖片加載庫Glide

圖片加載庫:Fresco 丶Glide 、o Picasso 等

Glide 的設計:
  • Glide 的生命週期綁定: 能夠控制圖片的加載狀態與當前頁面的生命週期同步,使整個加載過程隨着頁面的狀態而啓動/恢復,中止,銷燬
  • Glide 的緩存設計: 經過(三級緩存,Lru 算法,Bitmap 複用)對 Resource 進行緩存設計
  • Glide 的完整加載過程: 採用 Engine 引擎類暴露了一系列方法供 Request 操做

10 、區別 Animation 和 和 Animator

  • 動畫的種類: 前者只有 透明度, 旋轉, 平移, 伸縮 4 種屬性,而對於後者,只要是該控件的屬性,且有 setter 該屬性的方法就均可以對該屬性執行一種 動態變化的效果。
  • 可操做的對象: 前者只能對 I UI 組件執行動畫,但屬性動畫幾乎能夠對任何對象執行動畫(無論它是否顯示在屏幕上)。
  • 動畫播放順序: 在 Animator 中,AnimatorSet 正是經過

playTogether()playSequentially()animSet.play().with()before()after()這些方法來控制多個動畫協同工做,從而作到對動畫播放順序的精確控制

// animation主要用於tween動畫
   //根據資源獲得動畫
   Animation roitateAnimation = AnimationUtils.loadAnimation(this,R.anim.rotata_anim);
  //播放動畫完成以後,保留動畫最後的狀態
   rotateAnimation.setFillAfter(true);
 //播放動畫
  btnRotate.startAnimation(rotateAnimation);

// animator主要用於屬性動畫
   objectAnimator animator = objectanimator.ofFloat(textview,"alpha,1f,0f,1f);
   animator.setDuration(5000);
   animator,start();

   AnimatorSet animatorSet = new AnimatorSet();
    //移動
        objectAnimator ty = object Animator.ofFloat(btn,"translationY",0,300);
          ty.setDuration(1000);
   //旋轉
       objectAnimator ty = objectAnimator.ofFloat(btn, "rotationY", 0,1080);
   //透明度
       objectAnimator alpha = objectAnimator.ofFloat(btn, "alpha", 1,0,0.5f,1);
   //縮放
       objectAnimator sx = objectAnimator.ofFloat(btn, "scaleX",1,0.5f);
   //一塊兒播放
        // animatorSet.playTogether(items);
        animatorSet.play(ry),with(sx).after(ty).before(alpha);
        animatorSet.start();

請查看完整的PDF版
(更多完整項目下載。未完待續。源碼。圖文知識後續上傳github。)
能夠點擊關於我聯繫我獲取完整PDF
(VX:mm14525201314)

相關文章
相關標籤/搜索