<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ### Android進階延伸點 #### 1、如何進行單元測試,如何保證App穩定 ? > * 參考回答: > * 要測試Android應用程序,通常會創建以下類型自動單元測試 > * **本地測試**:只在本地機器JVM上運行,以最小化執行時間,這種單元測試不依賴于Android框架,或者即使有依賴,也很方便使用模擬框架來模擬依賴,以達到隔離Android依賴的目的,模擬框架如Google推薦的Mockito; > * [**Android官網-建立本地單元測試**](https://developer.android.com/training/testing/unit-testing/local-unit-tests.html) > * **檢測測試**:真機或模擬器上運行的單元測試,由于需要跑到設備上,比較慢,這些測試可以訪問儀器(Android系統)信息,比如被測應用程序的上下文,一般地,依賴不太方便通過模擬框架模擬時采用這種方式; > * [**Android官網-建立儀表單元測試**](https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests.html) > * 注意:單元測試不適合測試復雜的UI交互事件 > * 推薦文章:[Android 單元測試只看這一篇就夠了](https://juejin.im/post/5b57e3fbf265da0f47352618) > * App的穩定主要決定于整體的系統架構設計,同時也不可忽略代碼編程的細節規范,正所謂“千里之堤,潰于蟻穴”,一旦考慮不周,看似無關緊要的代碼片段可能會帶來整體軟件系統的崩潰,所以上線之前除了自己**本地化測試**之外還需要進行**Monkey壓力測試** > * 少部分面試官可能會延伸,如Gradle自動化測試、機型適配測試等 #### 2、Android中如何查看一個對象的回收情況 ? > * 參考回答: > * 首先要了解Java四種引用類型的場景和使用(強引用、軟引用、弱引用、虛引用) > * 舉個場景例子:**SoftReference**對象是用來保存軟引用的,但它同時也是一個Java對象,所以當軟引用對象被回收之后,雖然這個**SoftReference**對象的get方法返回null,但**SoftReference**對象本身并不是null,而此時這個**SoftReference**對象已經不再具有存在的價值,需要一個適當的清除機制,避免大量**SoftReference**對象帶來的**內存泄露** > * 因此,Java提供**ReferenceQueue**來處理引用對象的回收情況。當**SoftReference**所引用的對象被GC后,**JVM**會先將**softReference**對象添加到**ReferenceQueue**這個隊列中。當我們調用**ReferenceQueue的poll()方法**,如果這個隊列中不是空隊列,那么將返回并移除前面添加的那個Reference對象。 > > ![](https://user-gold-cdn.xitu.io/2019/3/27/169bd0c28741e8e0?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) > > * 推薦文章:[Java中的四種引用類型:強引用、軟引用、弱引用和虛引用](https://segmentfault.com/a/1190000015282652#articleHeader3) #### 3、Apk的大小如何壓縮 ? > * 參考回答: > * 一個完整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格式。 > > ![](https://user-gold-cdn.xitu.io/2019/3/27/169bd48e53be9928?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) > > * lib、class.dex和res占用了超過90%的空間,所以這三塊是優化Apk大小的重點(實際情況不唯一) > * **減少res,壓縮圖文文件** > * 圖片文件壓縮是針對jpg和png格式的圖片。我們通常會放置多套不同分辨率的圖片以適配不同的屏幕,這里可以進行適當的刪減。在實際使用中,只保留一到兩套就足夠了(保留一套的話建議保留xxhdpi,兩套的話就加上hdpi),然后再對剩余的圖片進行壓縮(jpg采用優圖壓縮,png嘗試采用pngquant壓縮) > * **減少dex文件大小** > * 添加資源混淆 > > ![](https://user-gold-cdn.xitu.io/2019/3/27/169be5f6fe340e53?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) > > * shrinkResources為true表示移除未引用資源,和代碼壓縮協同工作。 > * minifyEnabled為true表示通過ProGuard啟用代碼壓縮,配合proguardFiles的配置對代碼進行混淆并移除未使用的代碼。 > * 代碼混淆在壓縮apk的同時,也提升了安全性。 > * 推薦文章:[Android混淆最佳實踐](https://www.jianshu.com/p/cba8ca7fc36d) > * **減少lib文件大小** > * 由于引用了很多第三方庫,lib文件夾占用的空間通常都很大,特別是有so庫的情況下。很多so庫會同時引入armeabi、armeabi-v7a和x86這幾種類型,這里可以只保留armeabi或armeabi-v7a的其中一個就可以了,實際上微信等主流app都是這么做的。 > * 只需在build.gradle直接配置即可,NDK配置同理 > > ![](https://user-gold-cdn.xitu.io/2019/3/27/169be64df0148df3?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) > > * 推薦文章: > * [APK瘦身](https://www.jianshu.com/p/5921e9561f5f) #### 4、如何通過Gradle配置多渠道包? > * 參考回答: > * 首先要了解設置多渠道的原因。在安裝包中添加不同的標識,配合自動化埋點,應用在請求網絡的時候攜帶渠道信息,方便后臺做運營統計,比如說統計我們的應用在不同應用市場的下載量等信息 > * 這里以友盟統計為例 > * 首先在manifest.xml文件中設置動態渠道變量: > > ![](https://user-gold-cdn.xitu.io/2019/3/28/169c30d0cdbfb111?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) > > * 接著在app目錄下的build.gradle中配置productFlavors,也就是配置打包的渠道: > > ![](https://user-gold-cdn.xitu.io/2019/3/28/169c31116ef61848?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) > > * 最后在編輯器下方的Teminal輸出命令行 > * **執行./gradlew assembleRelease ,將會打出所有渠道的release包;** > * **執行./gradlew assembleVIVO,將會打出VIVO渠道的release和debug版的包;** > * **執行./gradlew assembleVIVORelease將生成VIVO的release包。** > * 推薦文章: > * [美團Android自動化之旅—Walle生成渠道包](https://github.com/Meituan-Dianping/walle) #### 5、插件化原理分析 > * 參考回答: > * **插件化**是指將 APK 分為**宿主**和**插件**的部分。把需要實現的模塊或功能當做一個獨立的提取出來,在 APP 運行時,我們可以動態的**載入**或者**替換插件**部分,減少**宿主**的規模 > * 宿主: 就是當前運行的APP。 > * 插件: 相對于插件化技術來說,就是要加載運行的apk類文件。 > * 而**熱修復**則是從修復bug的角度出發,強調的是在不需要二次安裝應用的前提下修復已知的bug。能 > > ![](https://user-gold-cdn.xitu.io/2019/4/7/169f6c21ae14fee0?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) > > * **類加載機制** > * 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對象。 > * 推薦文章: > * [Android動態加載技術 簡單易懂的介紹方式](https://segmentfault.com/a/1190000004062866#articleHeader1) > * [深入理解Android插件化技術](https://yq.aliyun.com/articles/361233?utm_content=m_40296) > * [為什么要做熱更新](https://www.cnblogs.com/baiqiantao/p/9160806.html) #### 6、組件化原理 > * 參考回答: > * **引入組件化的原因**:項目隨著需求的增加規模變得越來越大,規模的增大導致了各種業務錯中復雜的交織在一起, 每個業務模塊之間,代碼沒有約束,帶來了代碼邊界的模糊,代碼沖突時有發生, 更改一個小問題可能引起一些新的問題, 牽一發而動全身,增加一個新需求,需要熟悉相關的代碼邏輯,增加開發時間 > * **避免重復造輪子,可以節省開發和維護的成本。** > * **可以通過組件和模塊為業務基準合理地安排人力,提高開發效率。** > * **不同的項目可以共用一個組件或模塊,確保整體技術方案的統一性。** > * **為未來插件化共用同一套底層模型做準備。** > * **組件化開發流程**就是把一個功能完整的App或模塊拆分成**多個子模塊(Module)**,每個子模塊可以**獨立編譯運行**,也可以任意組合成另一個新的 App或模塊,每個模塊即不相互依賴但又可以相互交互,但是最終發布的時候是將這些組件合并統一成一個apk,遇到某些特殊情況甚至可以**升級**或者**降級** > * 舉個簡單的模型例子 > > ![APP架構圖](https://user-gold-cdn.xitu.io/2019/4/7/169f692c69f60c06?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) > > ![APP代碼結構圖](https://user-gold-cdn.xitu.io/2019/4/7/169f690af8eea279?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) > > App是主application,ModuleA和ModuleB是兩個業務模塊(**相對獨立,互不影響**),Library是基礎模塊,包含所有模塊需要的依賴庫,以及一些工具類:如網絡訪問、時間工具等 > * **注意:提供給各業務模塊的基礎組件,需要根據具體情況拆分成 aar 或者 library,像登錄,基礎網絡層這樣較為穩定的組件,一般直接打包成 aar,減少編譯耗時。而像自定義 View 組件,由于隨著版本迭代會有較多變化,就直接以源碼形式抽離成 Library** > * 推薦文章: > * [干貨 | 從智行 Android 項目看組件化架構實踐](https://mp.weixin.qq.com/s?__biz=MjM5MDI3MjA5MQ==&mid=2697268363&idx=1&sn=3db2dce36a912936961c671dd1f71c78&scene=21#wechat_redirect) #### 7、跨組件通信 > * 參考回答: > * **跨組件通信場景:** > * 第一種是組件之間的頁面跳轉 (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注解的形式制造出跳轉規則,并人為地攔截跳轉和設置跳轉條件。 > * 常見的組件化方案如下 > > ![](https://user-gold-cdn.xitu.io/2019/4/7/169f6a3d472ef431?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) > #### 8、組件化中路由、埋點的實現 > * 參考回答: > * 因為在組件化中,各個業務模塊之間是各自**獨立**的, 并不會存在相互依賴的關系, 所以一個業務模塊是訪問不了其他業務模塊的代碼的, 如果想從 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端自動采集全部事件并上報埋點數據,在后端數據計算時過濾出有用數據 > * 推薦文章: > * [安卓組件化開源方案實現](https://juejin.im/post/5a7ab8846fb9a0634514a2f5) #### 9、Hook以及插樁技術 > * 參考回答: > * **Hook**是一種用于**改變API執行結果**的技術,能夠將系統的API函數執行**重定向**(應用的**觸發事件**和**后臺邏輯處理**是根據事件流程一步步地向下執行。而**Hook**的意思,就是在事件傳送到終點前截獲并監控事件的傳輸,像個鉤子鉤上事件一樣,并且能夠在鉤上事件時,處理一些自己特定的事件,例如逆向破解App) > > ![](https://user-gold-cdn.xitu.io/2019/4/17/16a2a2f8cf3e4448?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) > > * Android 中的 Hook 機制,大致有兩個方式: > * 要 root 權限,直接 Hook 系統,可以干掉所有的 App。 > * 無 root 權限,但是只能 Hook 自身app,對系統其它 App 無能為力。 > * **插樁**是以靜態的方式修改第三方的代碼,也就是從編譯階段,對源代碼(中間代碼)進行編譯,而后重新打包,是**靜態的篡改**; 而**Hook**則不需要再編譯階段修改第三方的源碼或中間代碼,是在運行時通過反射的方式修改調用,是一種**動態的篡改** > * 推薦文章: > * [Android插件化原理解析——Hook機制之動態代理](http://weishu.me/2016/01/28/understand-plugin-framework-proxy-hook/) > * [android 插樁基本概念](https://blog.csdn.net/fei20121106/article/details/51879047) > * [Android逆向之旅](http://www.520monkey.com/) #### 10、Android的簽名機制? > * 參考回答: > * Android的簽名機制包含有**消息摘要**、**數字簽名**和**數字證書** > * **消息摘要**:在消息數據上,執行一個單向的 Hash 函數,生成一個固定長度的Hash值 > * **數字簽名**:一種以電子形式存儲消息簽名的方法,一個完整的數字簽名方案應該由兩部分組成:**簽名算法和驗證算法** > * **數字證書**:一個經證書授權(Certificate Authentication)中心數字簽名的包含公鑰擁有者信息以及公鑰的文件 > * 推薦文章: > * [一篇文章看明白 Android v1 & v2 簽名機制](https://blog.csdn.net/freekiteyu/article/details/84849651) #### 11、v3簽名key和v2還有v1有什么區別 > * 參考回答: > * 在**v1版本**的簽名中,簽名以文件的形式存在于apk包中,這個版本的apk包就是一個標準的zip包,**V2**和**V1**的差別是**V2**是對整個zip包進行簽名,而且在zip包中增加了一個**apk signature block**,里面保存簽名信息。 > > ![](https://user-gold-cdn.xitu.io/2019/4/1/169d7c3ea2437de3?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) > > * **v2版本**簽名塊(APK Signing Block)本身又主要分成三部分: > * **SignerData**(簽名者數據):主要包括簽名者的證書,整個APK完整性校驗hash,以及一些必要信息 > * **Signature**(簽名):開發者對SignerData部分數據的簽名數據 > * **PublicKey**(公鑰):用于驗簽的公鑰數據 > * **v3版本**簽名塊也分成同樣的三部分,與v2不同的是在SignerData部分,v3新增了attr塊,其中是由更小的level塊組成。每個level塊中可以存儲一個證書信息。前一個level塊證書驗證下一個level證書,以此類推。最后一個level塊的證書,要符合SignerData中本身的證書,即用來簽名整個APK的公鑰所屬于的證書 > > ![](https://user-gold-cdn.xitu.io/2019/4/1/169d7c5908d3c159?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) > > * 推薦文章: > * [APK 簽名方案 v3](https://source.android.google.cn/security/apksigning/v3) > * [Android P v3簽名新特性](https://xuanxuanblingbling.github.io/ctf/android/2018/12/30/signature/) #### 12、Android5.0~10.0之間大的變化 > * 參考回答: > * **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 官方文檔](https://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels) #### 13、說下Measurepec這個類 > * 參考回答: > * 作用:通過寬測量值**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**值共同決定。具體規則見下圖: > > ![](https://user-gold-cdn.xitu.io/2019/4/1/169d7a649cc67de5?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) > #### 14、請例舉Android中常用布局類型,并簡述其用法以及排版效率 > * 參考回答: > * Android中常用布局分為**傳統布局**和**新型布局** > * 傳統布局(編寫XML代碼、代碼生成): > * **框架布局(FrameLayout)**: > * **線性布局(LinearLayout)**: > * **絕對布局(AbsoluteLayout)**: > * **相對布局(RelativeLayout)**: > * **表格布局(TableLayout)**: > * 新型布局(**可視化拖拽控件**、編寫XML代碼、代碼生成): > * **約束布局(ConstrainLayout)**: > > ![](https://user-gold-cdn.xitu.io/2019/4/18/16a2f8e1327c53b4?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) > > * 注:圖片出自Carson\_Ho的[Android:常用布局介紹&屬性設置大全](https://blog.csdn.net/carson_ho/article/details/51719519) > * 對于嵌套多層View而言,其排版效率:**LinearLayout = FrameLayout >> RelativeLayout** #### 15、區別Animation和Animator的用法,概述其原理 > * 參考回答: > * **動畫的種類**:前者只有**透明度**,**旋轉**,**平移**,**伸縮**4種屬性,而對于后者,只要是該控件的屬性,且有setter該屬性的方法就都可以對該屬性執行一種**動態變化**的效果。 > * **可操作的對象**:前者只能對**UI組件**執行動畫,但屬性動畫幾乎可以對**任何對象**執行動畫(不管它是否顯示在屏幕上)。 > * **動畫播放順序**:在Animator中,AnimatorSet正是通過playTogether()、playSequentially()、animSet.play().with()、before()、after()這些方法來控制多個動畫協同工作,從而做到對動畫播放順序的精確控制 > > ![](https://user-gold-cdn.xitu.io/2019/4/18/16a2fb2adc635679?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) > #### 16、使用過什么圖片加載庫?Glide的源碼設計哪里很微妙? > * 參考回答: > * 圖片加載庫:**Fresco、Glide、Picasso**等 > * Glide的設計微妙在于: > * **Glide的生命周期綁定**:可以控制圖片的加載狀態與當前頁面的生命周期同步,使整個加載過程隨著頁面的狀態而啟動/恢復,停止,銷毀 > * **Glide的緩存設計**:通過(三級緩存,Lru算法,Bitmap復用)對Resource進行緩存設計 > * **Glide的完整加載過程**:采用Engine引擎類暴露了一系列方法供Request操作 > * 推薦文章: > * [Glide 源碼分析](https://user-gold-cdn.xitu.io/2019/4/24/16a4ec49c3af1f5c) #### 17、如何繞過9.0限制? > * 參考回答: > > ![](https://user-gold-cdn.xitu.io/2019/4/19/16a33b0c703f615b?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) > #### 18、用過哪些網絡加載庫?OkHttp、Retrofit實現原理? > * 參考回答: > * 網絡加載庫:OkHttp、Retrofit、xUtils、Volley等 > * 推薦文章: > * [Android OkHttp源碼解析入門教程(一)](https://juejin.im/post/5c46822c6fb9a049ea394510) > * [Android OkHttp源碼解析入門教程(二)](https://juejin.im/post/5c4682d2f265da6130752a1d) #### 19、對于應用更新這塊是如何做的? (灰度,強制更新、分區域更新) > * 參考回答: > * **內部更新**: > * 通過接口獲取線上版本號,versionCode > * 比較線上的versionCode 和本地的versionCode,彈出更新窗口 > * 下載APK文件(文件下載) > * 安裝APK > * **灰度更新**: > * 找單一渠道投放特別版本。 > * 做升級平臺的改造,允許針對部分用戶推送升級通知甚至版本強制升級。 > * 開放單獨的下載入口。 > * 是兩個版本的代碼都打到app包里,然后在app端植入測試框架,用來控制顯示哪個版本。測試框架負責與服務器端api通信,由服務器端控制app上A/B版本的分布,可以實現指定的一組用戶看到A版本,其它用戶看到B版本。服務端會有相應的報表來顯示A/B版本的數量和效果對比。最后可以由服務端的后臺來控制,全部用戶在線切換到A或者B版本~ > * **無論哪種方法都需要做好版本管理工作,分配特別的版本號以示區別。 當然,既然是做灰度,數據監控(常規數據、新特性數據、主要業務數據)還是要做到位,該打的數據樁要打。 還有,灰度版最好有收回的能力,一般就是強制升級下一個正式版。** > * **強制更新**: > * 一般的處理就是進入應用就彈窗通知用戶有版本更新,彈窗可以沒有取消按鈕并不能取消。這樣用戶就只能選擇更新或者關閉應用了,當然也可以添加取消按鈕,但是如果用戶選擇取消則直接退出應用。 > * **增量更新**: > * 二進制差分工具bsdiff是相應的補丁合成工具,根據兩個不同版本的二進制文件,生成補丁文件.patch文件。通過bspatch使舊的apk文件與不定文件合成新的apk。 注意通過apk文件的md5值進行區分版本。 #### 20、會用Kotlin、Fultter嗎? 談談你的理解 > * 參考回答: > * Kotlin是一種具有類型推斷的跨平臺,靜態類型的通用編程語言。 Kotlin旨在與Java完全互操作,其標準庫的JVM版本依賴于Java類庫,但類型推斷允許其語法更簡潔。 > * Flutter是由Google創建的開源移動應用程序開發框架。它用于開發Android和iOS的應用程序,以及為Google Fuchsia創建應用程序的主要方法 > * 關于kotlin的重要性,相信大家在日常開發可以體會到,應用到實際開發中,需要避免語法糖(例如單列模式、空值判斷、高階函數等) > * 至于Flutter,目前Google官方文檔還不完善,市面上采用此語言編寫的項目較少,如需要具體深入,請參考閑魚和官方文檔 鏈接:https://juejin.im/post/5c984e926fb9a070c975a9b4
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看