溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

答應(yīng)我,我踩過的坑你別再踩了好嘛,那些年社招的坑坑洼洼

發(fā)布時間:2020-02-25 03:50:27 來源:網(wǎng)絡(luò) 閱讀:213 作者:Android丶VG 欄目:移動開發(fā)

回想起前年左右,自己去社招的時候,一連串下來問了好多現(xiàn)在都是歷歷在目?;叵肫鹨郧安庞X得紙上得來終覺淺,絕知此事要躬行

所有的面試題答案并不是百分百的標(biāo)準(zhǔn),要靠你自己的感悟和有自己的想法,才能獨樹一幟脫穎而出的。所有僅供參考
答應(yīng)我,我踩過的坑你別再踩了好嘛,那些年社招的坑坑洼洼
所有的都在這個PDF中有所匯總,983頁花了幾十個小時整理出來的。還是比較全面的有Android,Java小知識,到性能優(yōu)化.線程.View.OpenCV.NDK.大廠面試,算法等等,大家可以聯(lián)系我看看對自身有沒有用

(更多完整項目下載。未完待續(xù)。源碼。圖文知識后續(xù)上傳github。)
可以聯(lián)系我獲取完整PDF
(VX:mm14525201314)

1丶如何進(jìn)行單元測試,如何保證 App 穩(wěn)定 ?
要測試 Android 應(yīng)用程序,通常會創(chuàng)建以下類型自動單元測試
  • 本地測試: 只在本地機(jī)器 JVM 上運(yùn)行,以最小化執(zhí)行時間,這種單元測試不依賴于 Android 框架,或者即使有依賴,也很方便使用模擬框架來模擬依賴,以達(dá)到隔離 Android 依賴的目的,模擬框架如Google 推薦的 Mockito;
  • 檢測測試: 真機(jī)或模擬器上運(yùn)行的單元測試,由于需要跑到設(shè)備上,比較慢,這些測試可以訪問儀器(Android 系統(tǒng))信息,比如被測應(yīng)用程序的上下文,一般地,依賴不太方便通過模擬框架模擬時采用這種方式;

注意: 單元測試不適合測試復(fù)雜的 UI 交互事件

  • App 的穩(wěn)定主要決定于整體的系統(tǒng)架構(gòu)設(shè)計,同時也不可忽略代碼編程的細(xì)節(jié)規(guī)范,正所謂“千里之堤,潰于蟻穴”,一旦考慮不周,看似無關(guān)緊要的代碼片段可能會帶來整體軟件系統(tǒng)的崩潰,所以上線之前除了自己 本地化測試之外還需要進(jìn)行 y Monkey 壓力測試
  • 少部分面試官可能會延伸,如 Gradle自動化測試、機(jī)型適配測試等
    2 、 Android 中如何查看一個對象的回收情況 ?

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

  • 舉個場景例子: SoftReference 對象是用來保存軟引用的,但它同時也是一個 Java 對象,所以當(dāng)軟引用對象被回收之后,雖然這個 SoftReference 對象的 get 方法返回null,但 SoftReference 對象本身并不是 null,而此時這個 SoftReference 對象已經(jīng)不再具有存在的價值,需要一個適當(dāng)?shù)那宄龣C(jī)制,避免大量SoftReference 對象帶來的內(nèi)存泄露
  • 因此,Java 提供 ReferenceQueue 來處理引用對象的回收情況。當(dāng) SoftReference 所引用的對象被 GC 后,JVM 會先將 softReference 對象添加到ReferenceQueue 這個隊列中。當(dāng)我們調(diào)用 ReferenceQueue 的 的 poll() 方法,如果這個隊列中不是空隊列,那么將返回并移除前面添加的那個Reference 對象

    public static void main(String[] args) throws InterruptedException {
    
          //假設(shè)當(dāng)前JVM內(nèi)存只有8m
         Person person = new Person( "/K=" );
         ReferenceQueue Person> queue = new ReferenceQueue>( );
         Sof tReference Person> softReference = new SoftReference<Person>(person, queue );
    
         реr?оn = null;// 去掉強(qiáng)引用, new Person ( "/K=" );的這個對象只有軟引用了
    
         Person anotherPerson = new Person( "/L=" )//沒有足夠的空間同事保留兩個Person對象,所以觸發(fā)GC機(jī)制
         Thread.sleep(1000);
    
         Sys tem. err . println( "軟引用的對象 ------" > softReference.get( ));
    
         Reference softPollRef = queue . poll( );
         if (softPollRef != null) f
              System.err.println( " SoftReference對象中保存的軟引用對象已經(jīng)被GC,準(zhǔn)備清理SoftReference對象");
                //清理softReference
         }
    }
    3丶壓縮APK大小
    一個完整 APK 包含以下目錄(將 APK 文件拖到 Android Studio):
  • META-INF/: 包含 CERT.SFCERT.RSA 簽名文件以及 MANIFEST.MF 清單文件。
  • assets/: 包含應(yīng)用可以使用 AssetManager 對象檢索的應(yīng)用資源。
  • res/: 包含未編譯到的資源 resources.arsc。
  • lib/: 包含特定于處理器軟件層的編譯代碼。該目錄包含了每種平臺的子目錄,像 armeabi armeabi-v7aarm64-v8a , x86x86_64 ,和mips
  • resources.arsc 包含已編譯的資源。該文件包含res/values/ 文件夾所有配置中的 XML 內(nèi)容。打包工具提取此 XML 內(nèi)容,將其編譯為二進(jìn)制格式,并將內(nèi)容歸檔。此內(nèi)容包括語言字符串和樣式,以及直接包含在resources.arsc8文件中的內(nèi)容路徑 ,例如布局文件和圖像。
  • classes.dex:包含以 Dalvik / ART 虛擬機(jī)可理解的X DEX 文件格式編譯的類。
  • AndroidManifest.xml 包含核心 Android 清單文件。該文件列出應(yīng)用程序的名稱,版本,訪問權(quán)限和引用的庫文件.該文件使用 Android 的二進(jìn)制XML 格式。
    答應(yīng)我,我踩過的坑你別再踩了好嘛,那些年社招的坑坑洼洼
  • lib、class.dex 和 res 占用了超過 90%的空間,所以這三塊是優(yōu)化 Apk 大小的重點(實際情況不唯一)
減少 res ,壓縮圖文文件

圖片文件壓縮是針對 jpgpng 格式的圖片。我們通常會放置多套不同分辨率的圖片以適配不同的屏幕,這里可以進(jìn)行適當(dāng)?shù)膭h減。在實際使用中,只保留一到兩套就足夠了(保留一套的話建議保留xxhdpi,兩套的話就加上 hdpi),然后再對剩余的圖片進(jìn)行壓縮(jpg 采用優(yōu)圖壓縮,png 嘗試采用pngquant 壓縮)

減少 dex
  • 添加資源混淆
    buildTypes {
      release  {
            shrinkResources true
            minifyEnabled  true
            proguardFiles  getDefaultProguardFile("proguard-android. txt"),’proguard-rules.pro’
      }
    }
  • shrinkResources 為 true 表示移除未引用資源,和代碼壓縮協(xié)同工作。
  • minifyEnabled 為 true 表示通過 ProGuard 啟用代碼壓縮,配合 proguardFiles 的配置對代碼進(jìn)行混淆并移除未使用的代碼。
  • 代碼混淆在壓縮 apk 的同時,也提升了安全性。
    減少 lib
  • 由于引用了很多第三方庫,lib 文件夾占用的空間通常都很大,特別是有 so 庫的情況下。很多 so 庫會同時引入 armeabi、armeabi-v7ax86 這幾種類型,這里可以只保留 armeabiarmeabi-v7a 的其中一個就可以了,實際上微信等主流 app 都是這么做的。
  • 只需在 build.gradle 直接配置即可,NDK 配置同理
    defaultConfig {
      ndk  {
             abiFilters 'armeabi'
      }
    }
    4丶插件化原理分析

    插件化是指將 APK 分為 宿主插件的部分。把需要實現(xiàn)的模塊或功能當(dāng)做一個獨立的提取出來,在 APP 運(yùn)行時,我們可以動態(tài)的 載入或者 替換插件部分,減少 宿主的規(guī)模

  • 宿主: 就是當(dāng)前運(yùn)行的 APP。
  • 插件: 相對于插件化技術(shù)來說,就是要加載運(yùn)行的apk 類文件

熱修復(fù)則是從修復(fù) bug 的角度出發(fā),強(qiáng)調(diào)的是在不需要二次安裝應(yīng)用的前提下修復(fù)已知的 bug。

類加載機(jī)制:

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

插件通信:

通過給插件 apk 生成相應(yīng)的 DexClassLoader 便可以訪問其中的類,可分為單 DexClassLoader 和多DexClassLoader 兩種結(jié)構(gòu)。

  • 若使用多 ClassLoader 機(jī)制,主工程引用插件中類需要先通過插件的 ClassLoader 加載該類再通過 反
    射調(diào)用其方法。插件化框架一般會通過統(tǒng)一的入口去管理對各個插件中類的訪問,并且做一定的限制。
  • 若使用單 ClassLoader 機(jī)制,主工程則可以 直接通過類名去訪問插件中的類。該方式有個弊端,若兩個不同的插件工程引用了一個庫的不同版本,則程序可能會出錯。
    資源加載:

    原理在于通過反射將插件 apk 的路徑加入AssetManager 中并創(chuàng)建 Resource 對象加載資源,有兩種處理方式:

  • 合并式: addAssetPath 時加入所有插件和主工程的路徑;由于 AssetManager 中加入了所有插件和主工程的路徑,因此生成的Resource 可以同時訪問插件和主工程的資源。但是由于主工程和各個插件都是獨立編譯的,生成的資源 id 會存在相同的情況,在訪問時會產(chǎn)生資源沖突。
  • 獨立式: 各個插件只添加自己 apk 路徑,各個插件的資源是互相隔離的,不過如果想要實現(xiàn)資源的共享,必須拿到對應(yīng)的 Resource對象。
    5 、組件化原理

    引入組件化的原因: 項目隨著需求的增加規(guī)模變得越來越大,規(guī)模的增大導(dǎo)致了各種業(yè)務(wù)錯中復(fù)雜的交織在一起,每個業(yè)務(wù)模塊之間,代碼沒有約束,帶來了代碼邊界的模糊,代碼沖突時有發(fā)生, 更改一個小問題可能引起一些新的問題, 牽一發(fā)而動全身,增加一個新需求,需要熟悉相關(guān)的代碼邏輯,增加開發(fā)時間

  • 避免重復(fù)造輪子,可以節(jié)省開發(fā)和維護(hù)的成本。
  • 可以通過組件和模塊為業(yè)務(wù)基準(zhǔn)合理地安排人力,提高開發(fā)效率。
  • 不同的項目可以共用一個組件或模塊,確保整體技術(shù)方案的統(tǒng)一性。
  • 為未來插件化共用同一套底層模型做準(zhǔn)備。

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

6、跨組件通信
跨組件通信場景:
  • 第一種是組件之間的頁面跳轉(zhuǎn) (Activity 到Activity, Fragment 到 Fragment, Activity 到Fragment, Fragment 到 Activity) 以及跳轉(zhuǎn)時的數(shù)據(jù)傳遞 (基礎(chǔ)數(shù)據(jù)類型和可序列化的自定義類型)
  • 第二種是組件之間的自定義類和自定義方法的調(diào)用(組件向外提供服務(wù))
    跨組件通信方案分析:
  • 第一種 組件之間的頁面跳轉(zhuǎn)實現(xiàn)簡單,跳轉(zhuǎn)時想傳遞不同類型的數(shù)據(jù)提供有相應(yīng)的 API 即可。
  • 第二種組件之間的自定義類和 自定義方法的調(diào)用要稍微復(fù)雜點,需要 ARouter 配合架構(gòu)中的 公共服務(wù)(CommonService) 實現(xiàn):
    • 提供服務(wù)的業(yè)務(wù)模塊: 在公共服務(wù)(CommonService) 中聲明 Service接口 (含有需要被調(diào)用的自定義方法), 然后在自己的模塊中實現(xiàn)這個 Service 接口, 再通過 ARouter API 暴露實現(xiàn)類。
    • 使用服務(wù)的業(yè)務(wù)模塊: 通過 ARouter 的 API 拿到這個Service 接口(多態(tài)持有, 實際持有實現(xiàn)類), 即可調(diào)用 Service 接口中聲明的自定義方法, 這樣就可以達(dá)到模塊之間的交互。
  • 此外,可以使用 AndroidEventBus 其獨有的Tag, 可以在開發(fā)時更容易定位發(fā)送事件和接受事件的代碼, 如果以組件名來作為 Tag 的前綴進(jìn)行分組, 也可以更好的統(tǒng)一管理和查看每個組件的事件, 當(dāng)然也不建議大家過多使用 EventBus。
如何管理過多的路由表?
  • RouterHub 存在于基礎(chǔ)庫, 可以被看作是所有組件都需要遵守的通訊協(xié)議, 里面不僅可以放路由地址常量, 還可以放跨組件傳遞數(shù)據(jù)時命名的各種 Key 值,再配以適當(dāng)注釋, 任何組件開發(fā)人員不需要事先溝通只要依賴了這個協(xié)議, 就知道了各自該怎樣協(xié)同工作, 既提高了效率又降低了出錯風(fēng)險, 約定的東西自然要比口頭上說強(qiáng)。
  • Tips: 如果您覺得把每個路由地址都寫在基礎(chǔ)庫的RouterHub 中, 太麻煩了, 也可以在每個組件內(nèi)部建立一個私有 RouterHub, 將不需要跨組件的路由地址放入私有 RouterHub 中管理, 只將需要跨組件的路由地址放入基礎(chǔ)庫的公有 RouterHub 中管理, 如果您不需要集中管理所有路由地址的話, 這也是比較推薦的一種方式。
    ARouter 路由原理:

    ARouter維護(hù)了一個路由表 Warehouse,其中保存著全部的模塊跳轉(zhuǎn)關(guān)系,ARouter 路由跳轉(zhuǎn)實際上還是調(diào)用了 startActivity 的跳轉(zhuǎn),使用了原生的Framework 機(jī)制,只是通過 apt 注解的形式制造出跳轉(zhuǎn)規(guī)則,并人為地攔截跳轉(zhuǎn)和設(shè)置跳轉(zhuǎn)條件

    7 、 Hook 以及插樁技術(shù)

    Hook 是一種用于 改變 API執(zhí)行結(jié)果的技術(shù),能夠?qū)⑾到y(tǒng)的API 函數(shù)執(zhí)行 重定向(應(yīng)用的 觸發(fā)事件后臺邏輯處理是根據(jù)事件流程一步步地向下執(zhí)行。而 Hook 的意思,就是在事件傳送到終點前截獲并監(jiān)控事件的傳輸,像個鉤子鉤上事件一樣,并且能夠在鉤上事件時,處理一些自己特定的事件,例如逆向破解 App)
    答應(yīng)我,我踩過的坑你別再踩了好嘛,那些年社招的坑坑洼洼

    Android 中的 Hook 機(jī)制,大致有兩個方式:
  • 要 root 權(quán)限,直接 Hook 系統(tǒng),可以干掉所有的App。
  • 無 root 權(quán)限,但是只能 Hook 自身 app,對系統(tǒng)其它 App 無能為力。

插樁是以靜態(tài)的方式修改第三方的代碼,也就是從編譯階段,對源代碼(中間代碼)進(jìn)行編譯,而后重新打包,是靜態(tài)的篡改; 而 Hook則不需要再編譯階段修改第三方的源碼或中間代碼,是在運(yùn)行時通過反射的方式修改調(diào)用,是一種 動態(tài)的篡改

8 、說下 Measurepec 這個類

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

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

三種模式:

  • UNSPECIFIED: 父容器不對 View 有任何限制,要多大有多大。常用于系統(tǒng)內(nèi)部。
  • EXACTLY(精確模式): 父視圖為子視圖指定一個確切的尺寸 SpecSize。對應(yīng) LyaoutParams 中的match_parent 或具體數(shù)值。
  • AT_MOST(最大模式): 父容器為子視圖指定一個最大尺寸 SpecSize,View 的大小不能大于這個值。對應(yīng)LayoutParams 中的 wrap_content。
9丶圖片加載庫Glide

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

Glide 的設(shè)計:
  • Glide 的生命周期綁定: 可以控制圖片的加載狀態(tài)與當(dāng)前頁面的生命周期同步,使整個加載過程隨著頁面的狀態(tài)而啟動/恢復(fù),停止,銷毀
  • Glide 的緩存設(shè)計: 通過(三級緩存,Lru 算法,Bitmap 復(fù)用)對 Resource 進(jìn)行緩存設(shè)計
  • Glide 的完整加載過程: 采用 Engine 引擎類暴露了一系列方法供 Request 操作
    10 、區(qū)別 Animation 和 和 Animator
  • 動畫的種類: 前者只有 透明度, 旋轉(zhuǎn), 平移, 伸縮 4 種屬性,而對于后者,只要是該控件的屬性,且有 setter 該屬性的方法就都可以對該屬性執(zhí)行一種 動態(tài)變化的效果。
  • 可操作的對象: 前者只能對 I UI 組件執(zhí)行動畫,但屬性動畫幾乎可以對任何對象執(zhí)行動畫(不管它是否顯示在屏幕上)。
  • 動畫播放順序: 在 Animator 中,AnimatorSet正是通過
    playTogether() 、playSequentially()animSet.play().with()、before()after()這些方法來控制多個動畫協(xié)同工作,從而做到對動畫播放順序的精確控制
// animation主要用于tween動畫
   //根據(jù)資源得到動畫
   Animation roitateAnimation = AnimationUtils.loadAnimation(this,R.anim.rotata_anim);
  //播放動畫完成之后,保留動畫最后的狀態(tài)
   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);
   //旋轉(zhuǎn)
       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版
(更多完整項目下載。未完待續(xù)。源碼。圖文知識后續(xù)上傳github。)
可以聯(lián)系我獲取完整PDF
(VX:mm14525201314)

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI