金三銀四,衝擊大廠,你值得擁有的一份2019初中級移動端社招面試總結+解答html
你當前所處:Android篇:2019初中級Android開發社招面試解答(下)android
Android篇:2019初中級Android開發社招面試解答(上)git
Android篇:2019初中級Android開發社招面試解答(中)github
注:由於實際開發與參考答案會有所不一樣,再者怕誤導你們,因此這些面試題答案仍是本身去理解!面試官會針對簡歷中提到的知識點由淺入深提問,因此不要背答案,多理解。面試
- 參考回答:
- 要測試Android應用程序,一般會建立如下類型自動單元測試
- 本地測試:只在本地機器JVM上運行,以最小化執行時間,這種單元測試不依賴於Android框架,或者即便有依賴,也很方便使用模擬框架來模擬依賴,以達到隔離Android依賴的目的,模擬框架如Google推薦的Mockito;
- Android官網-創建本地單元測試
- 檢測測試:真機或模擬器上運行的單元測試,因爲須要跑到設備上,比較慢,這些測試能夠訪問儀器(Android系統)信息,好比被測應用程序的上下文,通常地,依賴不太方便經過模擬框架模擬時採用這種方式;
- Android官網-創建儀表單元測試
- 注意:單元測試不適合測試複雜的UI交互事件
- 推薦文章:Android 單元測試只看這一篇就夠了
- App的穩定主要決定於總體的系統架構設計,同時也不可忽略代碼編程的細節規範,正所謂「千里之堤,潰於蟻穴」,一旦考慮不周,看似可有可無的代碼片斷可能會帶來總體軟件系統的崩潰,因此上線以前除了本身本地化測試以外還須要進行Monkey壓力測試
- 少部分面試官可能會延伸,如Gradle自動化測試、機型適配測試等
- 參考回答:
- 首先要了解Java四種引用類型的場景和使用(強引用、軟引用、弱引用、虛引用)
- 舉個場景例子:SoftReference對象是用來保存軟引用的,但它同時也是一個Java對象,因此當軟引用對象被回收以後,雖然這個SoftReference對象的get方法返回null,但SoftReference對象自己並非null,而此時這個SoftReference對象已經再也不具備存在的價值,須要一個適當的清除機制,避免大量SoftReference對象帶來的內存泄露
- 所以,Java提供ReferenceQueue來處理引用對象的回收狀況。當SoftReference所引用的對象被GC後,JVM會先將softReference對象添加到ReferenceQueue這個隊列中。當咱們調用ReferenceQueue的poll()方法,若是這個隊列中不是空隊列,那麼將返回並移除前面添加的那個Reference對象。
![]()
- 推薦文章:Java中的四種引用類型:強引用、軟引用、弱引用和虛引用
- 參考回答:
- 一個完整APK包含如下目錄(將APK文件拖到Android Studio):
- META-INF/:包含CERT.SF和CERT.RSA簽名文件以及MANIFEST.MF 清單文件。
- assets/:包含應用可使用AssetManager對象檢索的應用資源。
- res/:包含未編譯到的資源 resources.arsc。
- lib/:包含特定於處理器軟件層的編譯代碼。該目錄包含了每種平臺的子目錄,像armeabi,armeabi-v7a, arm64-v8a,x86,x86_64,和mips。
- resources.arsc:包含已編譯的資源。該文件包含res/values/ 文件夾全部配置中的XML內容。打包工具提取此XML內容,將其編譯爲二進制格式,並將內容歸檔。此內容包括語言字符串和樣式,以及直接包含在**resources.arsc*8文件中的內容路徑 ,例如佈局文件和圖像。
- classes.dex:包含以Dalvik / ART虛擬機可理解的DEX文件格式編譯的類。
- AndroidManifest.xml:包含核心Android清單文件。該文件列出應用程序的名稱,版本,訪問權限和引用的庫文件。該文件使用Android的二進制XML格式。
![]()
- lib、class.dex和res佔用了超過90%的空間,因此這三塊是優化Apk大小的重點(實際狀況不惟一)
- 減小res,壓縮圖文文件
- 圖片文件壓縮是針對jpg和png格式的圖片。咱們一般會放置多套不一樣分辨率的圖片以適配不一樣的屏幕,這裏能夠進行適當的刪減。在實際使用中,只保留一到兩套就足夠了(保留一套的話建議保留xxhdpi,兩套的話就加上hdpi),而後再對剩餘的圖片進行壓縮(jpg採用優圖壓縮,png嘗試採用pngquant壓縮)
- 減小dex文件大小
- 添加資源混淆
![]()
- shrinkResources爲true表示移除未引用資源,和代碼壓縮協同工做。
- minifyEnabled爲true表示經過ProGuard啓用代碼壓縮,配合proguardFiles的配置對代碼進行混淆並移除未使用的代碼。
- 代碼混淆在壓縮apk的同時,也提高了安全性。
- 推薦文章:Android混淆最佳實踐
- 減小lib文件大小
- 因爲引用了不少第三方庫,lib文件夾佔用的空間一般都很大,特別是有so庫的狀況下。不少so庫會同時引入armeabi、armeabi-v7a和x86這幾種類型,這裏能夠只保留armeabi或armeabi-v7a的其中一個就能夠了,實際上微信等主流app都是這麼作的。
- 只需在build.gradle直接配置便可,NDK配置同理
![]()
- 推薦文章:
- 參考回答:
- 首先要了解設置多渠道的緣由。在安裝包中添加不一樣的標識,配合自動化埋點,應用在請求網絡的時候攜帶渠道信息,方便後臺作運營統計,好比說統計咱們的應用在不一樣應用市場的下載量等信息
- 這裏以友盟統計爲例
- 首先在manifest.xml文件中設置動態渠道變量:
![]()
- 接着在app目錄下的build.gradle中配置productFlavors,也就是配置打包的渠道:
![]()
- 最後在編輯器下方的Teminal輸出命令行
- 執行./gradlew assembleRelease ,將會打出全部渠道的release包;
- 執行./gradlew assembleVIVO,將會打出VIVO渠道的release和debug版的包;
- 執行./gradlew assembleVIVORelease將生成VIVO的release包。
- 推薦文章:
- 參考回答:
- 插件化是指將 APK 分爲宿主和插件的部分。把須要實現的模塊或功能當作一個獨立的提取出來,在 APP 運行時,咱們能夠動態的載入或者替換插件部分,減小宿主的規模
- 宿主: 就是當前運行的APP。
- 插件: 相對於插件化技術來講,就是要加載運行的apk類文件。
- 而熱修復則是從修復bug的角度出發,強調的是在不須要二次安裝應用的前提下修復已知的bug。能
![]()
- 類加載機制
- Android中經常使用的兩種類加載器,DexClassLoader和PathClassLoader,它們都繼承於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對象。
- 推薦文章:
- 參考回答:
- 引入組件化的緣由:項目隨着需求的增長規模變得愈來愈大,規模的增大致使了各類業務錯中複雜的交織在一塊兒, 每一個業務模塊之間,代碼沒有約束,帶來了代碼邊界的模糊,代碼衝突時有發生, 更改一個小問題可能引發一些新的問題, 牽一髮而動全身,增長一個新需求,須要熟悉相關的代碼邏輯,增長開發時間
- 避免重複造輪子,能夠節省開發和維護的成本。
- 能夠經過組件和模塊爲業務基準合理地安排人力,提升開發效率。
- 不一樣的項目能夠共用一個組件或模塊,確保總體技術方案的統一性。
- 爲將來插件化共用同一套底層模型作準備。
- 組件化開發流程就是把一個功能完整的App或模塊拆分紅多個子模塊(Module),每一個子模塊能夠獨立編譯運行,也能夠任意組合成另外一個新的 App或模塊,每一個模塊即不相互依賴但又能夠相互交互,可是最終發佈的時候是將這些組件合併統一成一個apk,遇到某些特殊狀況甚至能夠升級或者降級
- 舉個簡單的模型例子
![]()
App是主application,ModuleA和ModuleB是兩個業務模塊(相對獨立,互不影響),Library是基礎模塊,包含全部模塊須要的依賴庫,以及一些工具類:如網絡訪問、時間工具等 ![]()
- 注意:提供給各業務模塊的基礎組件,須要根據具體狀況拆分紅 aar 或者 library,像登陸,基礎網絡層這樣較爲穩定的組件,通常直接打包成 aar,減小編譯耗時。而像自定義 View 組件,因爲隨着版本迭代會有較多變化,就直接以源碼形式抽離成 Library
- 推薦文章:
- 參考回答:
- 跨組件通訊場景:
- 第一種是組件之間的頁面跳轉 (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註解的形式製造出跳轉規則,並人爲地攔截跳轉和設置跳轉條件。
- 常見的組件化方案以下
![]()
- 參考回答:
- 由於在組件化中,各個業務模塊之間是各自獨立的, 並不會存在相互依賴的關係, 因此一個業務模塊是訪問不了其餘業務模塊的代碼的, 若是想從 A 業務模塊的 A 頁面跳轉到 B 業務模塊的 B 頁面, 光靠模塊自身是不能實現的,這就須要一種跨組件通訊方案—— 路由(Router)
- 路由主要有如下兩種場景:
- 第一種是組件之間的頁面跳轉 (Activity 到 Activity, Fragment 到 Fragment, Activity 到 Fragment, Fragment 到 Activity) 以及跳轉時的數據傳遞 (基礎數據類型和可序列化的自定義類類型)
- 第二種是組件之間的自定義類和自定義方法的調用(組件向外提供服務)
- 其原理在於將分佈在不一樣組件module中的某些類按照必定規則生成映射表(數據結構一般是Map,Key爲一個字符串,Value爲類或對象),而後在須要用到的時候從映射表中根據字符串從映射表中取出類或對象,本質上是類的查找
- 埋點則是在應用中特定的流程收集一些信息,用來跟蹤應用使用的情況
- 代碼埋點:在某個事件發生時調用SDK裏面相應的接口發送埋點數據,百度統計、友盟、TalkingData、Sensors Analytics等第三方數據統計服務商大都採用這種方案
- 全埋點:全埋點指的是將Web頁面/App內產生的全部的、知足某個條件的行爲,所有上報到後臺服務器
- 可視化埋點:經過可視化工具(例如Mixpanel)配置採集節點,在Android端自動解析配置並上報埋點數據,從而實現所謂的自動埋點
- 無埋點:它並非真正的不須要埋點,而是Android端自動採集所有事件並上報埋點數據,在後端數據計算時過濾出有用數據
- 推薦文章:
- 參考回答:
- Hook是一種用於改變API執行結果的技術,可以將系統的API函數執行重定向(應用的觸發事件和後臺邏輯處理是根據事件流程一步步地向下執行。而Hook的意思,就是在事件傳送到終點前截獲並監控事件的傳輸,像個鉤子鉤上事件同樣,而且可以在鉤上事件時,處理一些本身特定的事件,例如逆向破解App)
![]()
- Android 中的 Hook 機制,大體有兩個方式:
- 要 root 權限,直接 Hook 系統,能夠幹掉全部的 App。
- 無 root 權限,可是隻能 Hook 自身app,對系統其它 App 無能爲力。
- 插樁是以靜態的方式修改第三方的代碼,也就是從編譯階段,對源代碼(中間代碼)進行編譯,然後從新打包,是靜態的篡改; 而Hook則不須要再編譯階段修改第三方的源碼或中間代碼,是在運行時經過反射的方式修改調用,是一種動態的篡改
- 推薦文章:
- 參考回答:
- Android的簽名機制包含有消息摘要、數字簽名和數字證書
- 消息摘要:在消息數據上,執行一個單向的 Hash 函數,生成一個固定長度的Hash值
- 數字簽名:一種以電子形式存儲消息簽名的方法,一個完整的數字簽名方案應該由兩部分組成:簽名算法和驗證算法
- 數字證書:一個經證書受權(Certificate Authentication)中心數字簽名的包含公鑰擁有者信息以及公鑰的文件
- 推薦文章:
- 參考回答:
- 在v1版本的簽名中,簽名以文件的形式存在於apk包中,這個版本的apk包就是一個標準的zip包,V2和V1的差異是V2是對整個zip包進行簽名,並且在zip包中增長了一個apk signature block,裏面保存簽名信息。
![]()
- v2版本簽名塊(APK Signing Block)自己又主要分紅三部分:
- SignerData(簽名者數據):主要包括簽名者的證書,整個APK完整性校驗hash,以及一些必要信息
- Signature(簽名):開發者對SignerData部分數據的簽名數據
- PublicKey(公鑰):用於驗籤的公鑰數據
- v3版本簽名塊也分紅一樣的三部分,與v2不一樣的是在SignerData部分,v3新增了attr塊,其中是由更小的level塊組成。每一個level塊中能夠存儲一個證書信息。前一個level塊證書驗證下一個level證書,以此類推。最後一個level塊的證書,要符合SignerData中自己的證書,即用來簽名整個APK的公鑰所屬於的證書
![]()
- 推薦文章:
- 參考回答:
- Android5.0新特性
- MaterialDesign設計風格
- 支持64位ART虛擬機(5.0推出的ART虛擬機,在5.0以前都是Dalvik。他們的區別是:Dalvik,每次運行,字節碼都須要經過即時編譯器轉換成機器碼(JIT)。 ART,第一次安裝應用的時候,字節碼就會預先編譯成機器碼(AOT))
- 通知詳情能夠用戶本身設計
- Android6.0新特性
- 動態權限管理
- 支持快速充電的切換
- 支持文件夾拖拽應用
- 相機新增專業模式
- Android7.0新特性
- 多窗口支持
- V2簽名
- 加強的Java8語言模式
- 夜間模式
- Android8.0(O)新特性
- 優化通知:通知渠道 (Notification Channel) 通知標誌 休眠 通知超時 通知設置 通知清除
- 畫中畫模式:清單中Activity設置android:supportsPictureInPicture
- 後臺限制
- 自動填充框架
- 系統優化
- 等等優化不少
- Android9.0(P)新特性
- 室內WIFI定位
- 「劉海」屏幕支持
- 安全加強
- 等等優化不少
- Android10.0(Q)新特性
- 夜間模式:包括手機上的全部應用均可覺得其設置暗黑模式。
- 桌面模式:提供相似於PC的體驗,可是遠遠不能代替PC。
- 屏幕錄製:經過長按「電源」菜單中的"屏幕快照"來開啓。
- 推薦文章:Android Developers 官方文檔
- 參考回答:
- 做用:經過寬測量值widthMeasureSpec和高測量值heightMeasureSpec決定View的大小
- 組成:一個32位int值,高2位表明SpecMode(測量模式),低30位表明SpecSize( 某種測量模式下的規格大小)。
- 三種模式:
- UNSPECIFIED:父容器不對View有任何限制,要多大有多大。經常使用於系統內部。
- EXACTLY(精確模式):父視圖爲子視圖指定一個確切的尺寸SpecSize。對應LyaoutParams中的match_parent或具體數值。
- AT_MOST(最大模式):父容器爲子視圖指定一個最大尺寸SpecSize,View的大小不能大於這個值。對應LayoutParams中的wrap_content。
- 決定因素:值由子View的佈局參數LayoutParams和父容器的MeasureSpec值共同決定。具體規則見下圖:
![]()
- 參考回答:
- Android中經常使用佈局分爲傳統佈局和新型佈局
- 傳統佈局(編寫XML代碼、代碼生成):
- 框架佈局(FrameLayout):
- 線性佈局(LinearLayout):
- 絕對佈局(AbsoluteLayout):
- 相對佈局(RelativeLayout):
- 表格佈局(TableLayout):
- 新型佈局(可視化拖拽控件、編寫XML代碼、代碼生成):
- 約束佈局(ConstrainLayout):
![]()
- 注:圖片出自Carson_Ho的Android:經常使用佈局介紹&屬性設置大全
- 對於嵌套多層View而言,其排版效率:LinearLayout = FrameLayout >> RelativeLayout
- 參考回答:
- 動畫的種類:前者只有透明度,旋轉,平移,伸縮4種屬性,而對於後者,只要是該控件的屬性,且有setter該屬性的方法就均可以對該屬性執行一種動態變化的效果。
- 可操做的對象:前者只能對UI組件執行動畫,但屬性動畫幾乎能夠對任何對象執行動畫(無論它是否顯示在屏幕上)。
- 動畫播放順序:在Animator中,AnimatorSet正是經過playTogether()、playSequentially()、animSet.play().with()、before()、after()這些方法來控制多個動畫協同工做,從而作到對動畫播放順序的精確控制
![]()
- 參考回答:
- 圖片加載庫:Fresco、Glide、Picasso等
- Glide的設計微妙在於:
- Glide的生命週期綁定:能夠控制圖片的加載狀態與當前頁面的生命週期同步,使整個加載過程隨着頁面的狀態而啓動/恢復,中止,銷燬
- Glide的緩存設計:經過(三級緩存,Lru算法,Bitmap複用)對Resource進行緩存設計
- Glide的完整加載過程:採用Engine引擎類暴露了一系列方法供Request操做
- 推薦文章:
- 參考回答:
![]()
- 參考回答:
- 網絡加載庫:OkHttp、Retrofit、xUtils、Volley等
- 推薦文章:
- 參考回答:
- 內部更新:
- 經過接口獲取線上版本號,versionCode
- 比較線上的versionCode 和本地的versionCode,彈出更新窗口
- 下載APK文件(文件下載)
- 安裝APK
- 灰度更新:
- 找單一渠道投放特別版本。
- 作升級平臺的改造,容許針對部分用戶推送升級通知甚至版本強制升級。
- 開放單獨的下載入口。
- 是兩個版本的代碼都打到app包裏,而後在app端植入測試框架,用來控制顯示哪一個版本。測試框架負責與服務器端api通訊,由服務器端控制app上A/B版本的分佈,能夠實現指定的一組用戶看到A版本,其它用戶看到B版本。服務端會有相應的報表來顯示A/B版本的數量和效果對比。最後能夠由服務端的後臺來控制,所有用戶在線切換到A或者B版本~
- 不管哪一種方法都須要作好版本管理工做,分配特別的版本號以示區別。 固然,既然是作灰度,數據監控(常規數據、新特性數據、主要業務數據)仍是要作到位,該打的數據樁要打。 還有,灰度版最好有收回的能力,通常就是強制升級下一個正式版。
- 強制更新:
- 通常的處理就是進入應用就彈窗通知用戶有版本更新,彈窗能夠沒有取消按鈕並不能取消。這樣用戶就只能選擇更新或者關閉應用了,固然也能夠添加取消按鈕,可是若是用戶選擇取消則直接退出應用。
- 增量更新:
- 二進制差分工具bsdiff是相應的補丁合成工具,根據兩個不一樣版本的二進制文件,生成補丁文件.patch文件。經過bspatch使舊的apk文件與不定文件合成新的apk。 注意經過apk文件的md5值進行區分版本。
- 參考回答:
- Kotlin是一種具備類型推斷的跨平臺,靜態類型的通用編程語言。 Kotlin旨在與Java徹底互操做,其標準庫的JVM版本依賴於Java類庫,但類型推斷容許其語法更簡潔。
- Flutter是由Google建立的開源移動應用程序開發框架。它用於開發Android和iOS的應用程序,以及爲Google Fuchsia建立應用程序的主要方法
- 關於kotlin的重要性,相信你們在平常開發能夠體會到,應用到實際開發中,須要避免語法糖(例如單列模式、空值判斷、高階函數等)
- 至於Flutter,目前Google官方文檔還不完善,市面上採用此語言編寫的項目較少,如須要具體深刻,請參考閒魚和官方文檔