關於2019的一些面試實戰小結

今日頭條屏幕適配的原理?

1:首先計算出 density,計算公式:當前設備屏幕總寬度(單位為像素)/ 設計圖總寬度(單位為 dp) = densitydensity 的意思就是 1 dp 占當前設備多少像素計算density 的原因:在布局文件中填寫的是什麼單位,最後都會被轉化為 px,系統就是通過上面的方法,將你在項目中任何地方填寫的單位都轉換為 px

但是,今日頭條適配方案默認項目中只能以高或寬中的一個作為基準,來進行適配

簡述Android中的加固和使用平台?

加固:防止代碼反編譯,提高代碼安全性

加固三方平台,梆梆安全,360加固,愛加密等

區別:梆梆安全,360加固看不到項目中的類,愛加密看的到Java類,單看不到裡面的方法實現體,效果比前面差一點點

加固的底層原理:第三方加固的應用會生成一個Apk,然後把你的APK讀取出來,在封裝到這個第三方應用的APK裡面.

如何對APK瘦身?

1)使用混淆,

2)開啟shrinkResourse(shrink-收縮),會將沒有用到的圖片變成一個像素點

3)刪除無用的語言資源(刪除國際化文件)

4)對於非透明的大圖,使用JPG(沒有透明度信息),代替PNG格式

5)使用tinypng進行圖片壓縮

6)使用webp圖片格式,進一步壓縮圖片資源

7)使用第三方包時把用到的代碼加到項目中來,避免引用整一個第三方庫

簡述多渠道打包及原理和常用操作?

針對每一個渠道(應用市場)都生成一個帶有渠道標識的apk文件

原理:用戶下載啟動應用,獲取渠道標識,和設備的唯一標識,並上傳到伺服器裡面,伺服器這裡就 會根據獲取的記錄,根據渠道號然後判斷是否存在該伺服器的表裡面.(打標記,取標記,上傳標記)

1)友盟多渠道打包:在清單文件中定義一個佔位符,在gradle腳本中替換佔位符(會使用到Python)

2)美團打包,在meta-data中創建一個空的文件,以文件名標識渠道,做一個解壓與壓縮的操作,速度會比較快

3)新一代多渠道打包,將渠道標識添加到.apk文件的末尾,並不會對源文件損壞

Android下的數據存儲方式有那些?

1)內部存儲,直接存儲在內部文件中

2)外部存儲,首先要判斷外部存儲條件是否可用,然後進行存儲

3)SP存儲,底層是Xml實現的,以鍵值對形式存儲內部的數據,適宜於輕量級的存儲,存儲的數據類型有,boolean,String,int

4)資料庫存儲,SQlite存儲,輕量級的資料庫,強大的增刪改查功能

5)內容提供者,ContentProvider,將自己願意暴露的一部分數據供外部使用操作

6)網路存儲,等等

Sharepreference 線程安全問題?

官方文檔明確指出,SharedPreferences不支持多線程,進程也是不安全的

如果想要實現線程安全需重新實現其介面,如下

假設在多進程訪問SharePreferences的情況下,該如何保證進程安全和共享數據?

解決辦法就是:將需要共享數據的欄位提出來統一存儲到一個文件中。

Android開發下如何有效進行屏幕適配?

1:機型適配,去一些統計網站諸如友盟,現在叫友盟+去看一下市場上最流行的Android機型,有針對性的切圖

2:屏幕適配,適配主流xhdpi屏幕尺寸,使用relativelayout,linerlayout等布局,多使用matchparent,wrapcontent,及配合weight,權重處理,

3:還有就是在代碼中,設計到具體尺寸的要使用dp2px的轉換,

4:圖片使用可拉伸.9圖片,imageview使用scaletype縮放;

5:使用權重,等比例,百分比布局等等

對象序列化:

為什麼要序列化?

1)永久性保存對象,保存對象的位元組序列到本地文件中;

2)通過序列化對象在網路中傳遞對象;

3)通過序列化在進程間傳遞對象。

在Android中實現序列化有兩個選擇:一是實現Serializable介面(是JavaSE本身就支持的),一是實現Parcelable介面(是Android特有功能,效率比實現Serializable介面高效,可用於Intent數據傳遞,也可以用於進程間通信(IPC))。實現Serializable介面非常簡單,聲明一下就可以了,而實現Parcelable介面稍微複雜一些,但效率更高,推薦用這種方法提高性能。兩種實現方式依舊是貼url,方便大家快速查詢

兩種序列化相關

既然Google推薦Parcelable這種序列化,在這裡,推薦一鍵生成序列化的插件,

在Android Studio裡面搜索插件,如下圖,寫起序列化(根本不用你寫)那就是一個美滋滋吶~

OkHttp相關?

OkHttp支持同步和非同步數據請求,但非同步請求是在子線程 (因為原生OkHttp的使用時回調方法是在子線程進行的,要刷新界面還需要用Handler作處理,可以使用第三方的okhttp-utils,Okgo等等);

OkHttp裡面封裝了線程池、數據轉換、GZIP壓縮(減少流量的傳輸)、HTTP協議緩存等,

OKHttp優點—-使用GZip壓縮減少傳輸的數據量,緩存(減少重複請求);

失敗重試(如果你的服務有多個IP地址,如果第一次連接失敗,OKHttp將使用備用地址)

OKhttp是對http協議的封裝,比較底層,因此拓展性強,便於封裝;

OKhttp基於NIO(JDK1.5,非阻塞式IO)效率更高

ButterKnife相關?

簡介:一款快速高效的注入框架,節約開發時間減少代碼量(依靠插件動態生成View,點擊事件等等)

優點:

1.強大的View綁定和Click事件處理功能,簡化代碼,提升開發效率

2.方便的處理Adapter里的ViewHolder綁定問題

3.運行時不會影響APP效率,使用配置方便

4.代碼清晰,可讀性強

使用經驗:

1.Activity ButterKnife.bind(this);必須在setContentView();之後,且父類bind綁定後,子類不需要再bind

2.Fragment ButterKnife.bind(this, mRootView);

3.屬性布局不能用private or static 修飾,否則會報錯,(注意許可權)

4.setContentView()不能通過註解實現。(其他的有些註解框架可以)

原理:利用註解和反射去獲取綁定ViewID,

關於原理詳情可參考筆者的這一篇:Android-定製專屬ButterKnife框架,該文詳細介紹了ButterKnife框架並模仿了一個註解綁定View的框架

Rxjava概念,常用操作符及拓展?

簡介:

一款優雅的非同步框架,代替之前的AsyncTask / Handler / XXX / …

其強大的操作符和鏈式寫法,線程切換等有助於提高開發效率和快速定位Bug

與Retrofit搭配使用更是有意想不到的效果,

底層原理:觀察者模式

等一些相應的博客

缺點:

1:操作符太多會增加學習成本時間

2:使用不好,容易導致內存泄露(解決方式,推薦Rxlifecycle結合Rxjava,規避內存泄漏風險)

ANR相關

ANR全名Application Not Responding, 也就是」應用無響應」. 當操作在一段時間內系統無法處理時, 系統層面會彈出上圖那樣的ANR對話框.

在Android里, App的響應能力是由Activity Manager和Window Manager系統服務來監控的. 通常在如下兩種情況下會彈出ANR對話框:

A) 5s內無法響應用戶輸入事件(例如鍵盤輸入, 觸摸屏幕等).

B) BroadcastReceiver在10s內無法結束.

造成以上兩種情況的首要原因就是在主線程(UI線程)裡面做了太多的阻塞耗時操作, 例如文件讀寫, 資料庫讀寫, 網路查詢等等.

如何分析ANR?

ANR產生時, 系統會生成一個traces.txt的文件放在/data/anr/下. 開發人員可通過adb命令將其導出到本地 ($adb pull data/anr/traces.txt .)通過分析,我們可以根據具體的日誌查看Anr原因( 如: 普通阻塞,CPU滿負荷,內存泄露 )

Android中那些場景是執行在主線程的?

1)Activity生命周期回調都是執行在主線程的.

2)Service默認是執行在主線程的.

3)BroadcastReceiver的onReceive回調是執行在主線程的.

4)沒有使用子線程的looper的Handler的handleMessage, post(Runnable)是執行在主線程的.

5)AsyncTask的回調中除了doInBackground, 其他都是執行在主線程的.

6)View的post(Runnable)是執行在主線程的.等等

三級緩存:

當我們第一次打開應用獲取圖片或其它資源時,首先到網路去下載,然後依次存入內存緩存,磁碟緩存,

當我們再一次需要用到剛才下載的這張圖片時,就不需要再重複的到網路上去下載,直接可以從內存緩存和磁碟緩存中找,由於內存緩存速度較快,我們優先到內存緩存中尋找該圖片,如果找到則運用,

如果沒有找到(內存緩存大小有限),那麼我們再到磁碟緩存中去找。

只要我們合理的去協調這三層緩存運用,便可以提升應用性能,給用戶更好的體驗

三級緩存指的是:內存緩存、本地緩存、網路緩存。其各自的特點是內存緩存速度快, 優先讀取,本地緩存速度其次, 內存沒有該資源信息就去讀取本地內存,網路緩存速度較慢(比較對象是內存緩存和本地緩存),假設本地內存也沒有,才請求網路獲取。

內存泄漏:

當應用內部不再需要某個實例後,但是這個對象卻仍然被引用,這個情況就叫做內存泄露(Memory Leak)。安卓虛擬機為每一個應用分配一定的內存空間,當內存泄露到達一定的程度就會造成內存溢出。

導致內存泄露常見原因:

1)靜態變數直接或者間接地引用了Activity對象就會造成內存泄露

2)Activity使用了靜態的View(View會持有Activity的對象的引用)

3)Activity定義了靜態View變數???

4)ImageSpan引用了Activity Context

5)單例中引用了Activity的Context(需要使用Application的Context)

6)對於使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等資源,應該在Activity銷毀時及時關閉或者註銷,否則這些資源將不會被回收,從而造成內存泄漏。

7)靜態集合保存的對象沒有及時消除(不使用的時候置為null)

8)在Java中,非靜態(匿名)內部類會引用外部類對象,而靜態內部類不會引用外部類對象

9)在Activity中,創建了非靜態內部類(內部類直接或者間接引用了Activity)的靜態成員變數

10)線程包括AsyncTask的使用,Activity退出後線程還在運行(線程在死循環),並且在線程中使用了Activity或view對象(解決方法:不要直接寫死循環,可以設置一個布爾類型的TAG,當activity推出的時候,設置TAG為False)

11)Handler對象的使用,Activity退出後Handler還是有消息需要處理(解決方法:在退出activity之後,移除消息)

12)WebView造成的內存泄漏(在onDestory中銷毀)

如何進行內存泄露分析?

A: 通過Android Studio 窗口進行分析,查看內存分配情況,如果操作應用是內存一直往上漲說明存在內存泄露

B: 定位內存泄露分析的工具—-MAT(Memory Analyzer tool)

C: 使用開源庫LeakCanary快速定位內存泄露

Android中的四大組件相關?

Activity:

Activity是一個應用程序組件,提供一個屏幕(狹義的理解就是當前APP的界面),用戶可以用來交互為了完成某項任務。(點擊,登錄,跳轉頁面)

Activity中所有操作都與用戶密切相關,是一個負責與用戶交互的組件,可以通過setContentView(View)來顯示指定控制項(設置布局文件)。

在一個android應用中,一個Activity通常就是一個單獨的屏幕,它上面可以顯示一些控制項也可以監聽並處理用戶的事件做出響應。

Activity四種啟動模式?

Activity的啟動模式指,可以根據實際開發需求為Activity設置對應的啟動模式,從而可以避免創建大量重複的Activity等問題。

1)standard

standard為Activity的默認啟動模式,可以不用寫配置。在這個模式下,都會默認創建一個新的實例。因此,在這種模式下,可以有多個相同的實例,也允許多個相同Activity疊加。(點back鍵會依照棧順序依次退出)

2)singleTop

singleTop模式下,Activity可以有多個實例,但是不允許多個相同Activity疊加。即,如果Activity在棧頂的時候,啟動相同的Activity,不會創建新的實例,而會調用其onNewIntent方法。

3)singleTask

singleTask表示只有一個實例。在同一個應用程序中啟動他的時候,若Activity不存在,則會在當前task創建一個新的實例,若存在,則會把task中在其之上的其它Activity destory掉並調用它的onNewIntent方法。如果是在別的應用程序中啟動它,則會新建一個task,並在該task中啟動這個Activity,singleTask允許別的Activity與其在一個task中共存,也就是說,如果我在這個singleTask的實例中再打開新的Activity,這個新的Activity還是會在singleTask的實例的task中。

4)singleInstance

只有一個實例,並且這個實例獨立運行在一個task中,這個task只有這個實例,不允許有別的Activity存在。

BraodcastReceiver:(待補充)

使用了設計模式中的觀察者模式:基於消息的發布/訂閱事件模型。

註冊的方式分為兩種:靜態註冊、動態註冊

ContentProvider:(待補充)

外界可以通過ContentResolver介面來訪問ContentProvider(內容提供者)中的數據。Uri 通用資源標誌符(Universal Resource Identifier)Uri代表要操作的數據,Android中可用的每種資源 - 圖像、視頻片段等都可以用Uri來表示。ContentProvider共享數據是通過定義一個對外開放的統一的介面來實現的。然而,應用程序並不直接調用這些方法,而是使用一個 ContentResolver 對象,調用它的方法作為替代。ContentResolver可以與任意內容提供者進行會話,與其合作來對所有相關交互通訊進行管理。當外部應用需要對ContentProvider中的數據進行添加、刪除、修改和查詢操作時,可以使用ContentResolver類來完成,要獲取ContentResolver對象,可以使用Context提供的getContentResolver()方法。

IntentService:

IntentService是Service的子類,比普通的Service增加了額外的功能。IntentService會創建獨立的worker線程來處理所有的Intent請求;會創建獨立的worker線程來處理onHandleIntent()方法實現的代碼,無需處理多線程的問題;所有請求處理完成後,IntentService會自動停止,開發者無需手動調用stopSelf()方法停止Service;

簡述System.exit(0) 、onDestory()、Activity.finish()三者的區別

1)System.exit(0) 是你正常結束程序,kill 掉當前進程,針對的是整個Application

2)onDestory()方法是Activity生命周期的最後一步,資源空間等就被回收了。當重新進入此Activity的時候,必須重新創建,執行onCreate()方法.

3)Activity.finish()當你調用此方法的時候,系統只是將最上面的Activity移出了棧,並沒有及時的調用onDestory()方法,也就是佔用的資源沒有被及時釋放。

圖片優化,以及圖片載入框架的使用,如Picasso、 Fresco、Glide等?

1)盡量使用小的圖片,對圖片進行壓縮,bitmapfactory.options圖片配置類,insimplesize進行縮放,設置圖片的編碼方式;對圖片使用軟引用,內存不夠時即時釋圖片內存;對圖片的復用,三級緩存的使用;

即時回收不再使用的bitmap對象;

2)Picasso,不支持gif,緩存的是Argb8888的原圖,佔用內存較大,圖片的框架使用了OkHttp緩存機制,使用Http協議緩存,也是非同步載入.

3)Fresco,框架是FaceBook公司推出的,適合批量載入圖片,底層是通過三級緩存(2級內存,1級磁碟)

載入成功後自動替換成目標圖片

4)glide,Google公司14年推出來的,可以載入GIF圖,也可以根據指定圖片清晰度,底層的原理:為Bitmap維護一個對象池,對象池的目的是通過減少對象的分配,以重用來提高性能.對象池也可以幫助提高滾動的性能。API簡潔易調用

Handle相關:

Handler 工作流程基本包括 Handler、Looper、Message、MessageQueue 四個部分。但我們在日常開發中,經常都只會用到 Handler 和 Message 兩個類。Message 負責消息的搭載,裡面有個target用於標記消息,obj用於存放內容,Handler 負責消息的分發和處理。

一般在開發中是怎麼使用 Handler 的?

官方不允許在子線程中更新 UI,所以我們經常會把需要更新 UI 的消息直接發給處理器 Handler,通過重寫 Handler 的handleMessage()方法進行 UI 的相關操作。

Handle使用中就沒什麼需要注意的嗎?

有,Handler 如果設置為私有變數的話,Android Studio 會報警告,提示可能會造成內存泄漏,這種情況可以通過設置為靜態內部類 + 弱引用,或者在onDestroy()方法中調用Handler.removeCallbacksAndMessages(null)即可避免

Handler 整體工作流程淺析分為以下四個步驟:

非同步通信準備 => 消息入隊 => 消息循環 => 消息處理

A:非同步通信準備

I:假定是在主線程創建 Handler,則會直接在主線程中創建處理器對象Looper、消息隊列對象MessageQueue和 Handler 對象。

需要注意的是,Looper和MessageQueue均是屬於其創建線程的。

II:Looper對象的創建一般通過Looper.prepareMainLooper()和Looper.prepare()兩個方法,而創建Looper對象的同時,將會自動創建MessageQueue。

III:創建好MessageQueue後,Looper將自動進入消息循環。此時,Handler自動綁定了主線程的Looper和MessageQueue。

B:消息入隊

工作線程通過Handler發送消息Message到消息隊列MessageQueue中,消息內容一般是 UI 操作。發送消息一般都是通過Handler.sendMessage(Message msg)和Handler.post(Runnabe r)兩個方法來進行的。而入隊一般是通過MessageQueue.enqueueeMessage(Message msg,long when)來處理。

C:消息循環

主要分為「消息出隊」和「消息分發」兩個步驟,Looper會通過循環取出消息隊列MessageQueue裡面的消息Message,並分發到創建該消息的處理者Handler。如果消息循環過程中,消息隊列MessageQueue為空隊列的話,則線程阻塞。

D:消息處理

Handler接收到Looper發來的消息,開始進行處理。

拓展

先簡單介紹下你自己?

分析:除了向面試官做簡單的基本自我介紹之外,還需向面試官展現自身對該職業所必須具備的一些自身特質,

比如,面試程序員職業需要間接的向面試官表示自己思維嚴謹,對細節的處理,理性思維,假設論證等等;面試產品等職業,需要向面試官通過自己的一些故事間接展現對產品的看法以及獨特的思維個性等等

切入點:自身特質能否符合該職位的預期需求

自己的興趣愛好特長有那些?

在企業和面試官看來,如果求職者的愛好和應聘的崗位在某些方面恰恰有正向關聯,就會有興趣。面試官也會通過應聘者的興趣愛好來判斷其價值觀是否與企業文化契合,能否很好地融入工作團隊。求職者的回答將有可能為面試加分。

下列興趣愛好所反映出的一些性格和職業方向可供參考:

1.籃球,足球,排球:團隊精神,適用大多數崗位。

2.圍棋,國際象棋:戰略意識,適合市場類或高端職位。

3.閱讀,古典音樂:高雅,適合文職類的職位。

4.旅遊:適應不同環境的能力,快速學習的能力,適合銷售業務類職位。

5.舞蹈:外向,易溝通,適合公關、市場類的職位。

對自己的期望和規劃?

分析:職業發展規劃表面上看是在考察你(求職者)、職位、公司三者之間長期的契合程度,但實際上,這麼大的一個問題完全不是三眼兩語間能夠表達清楚的。面試官(無論HR還是專業部門的)主要是看你回答問題時的思路是否清晰,回答中表現出的工作態度如何,順便看看你是否對公司和職位有足夠的了解。所以不管答案如何,最關鍵的就是不能茫然。

切入點:依舊自身特點,對未來期望和規劃需表述清晰,思維敏捷

談談自己的優點和缺點?

先談缺點:

技術行業面試基本是由該崗位未來同事和上司進行。這種面試技術性強,行為問題主要考察就是你是否真心想做這個工作(而不是當跳板或者聽說高薪體面而來)和你性格與文化是否相符。所有答案都應該圍繞這兩點組織(即每個經歷都應回歸到你通過這個經歷學到什麼,該職位所需關鍵技巧,這些經歷為何讓你想做這個工作,和該經歷體現出你什麼樣的個人風格)。對這個問題因為好的回答而留下好印象很難,

關鍵是避免留下壞印象。

要點以下:

1)避免避重就輕,不要談一個算不得缺點的缺點。比如熬夜會困,或者(待人接物)太客氣等等。

2)避免談非職業缺點,比如有感情潔癖,挑食,不擅長陪女友逛街,做飯經常不懂會煮糊。

3)避免談到無法改善的弱點,比如我算數必須用計算器,我腦子不好用看書不理解。

4)避免談到致命弱點,比如脾氣怪異,不喜歡合作,遲到早退等。

那談什麼最好呢?我認為要點有三:

1)談已經在改正的缺點/有明確計劃來改正的缺點。尤其是你能夠充分論證在近期就可以解決的缺點。

2)談一個利用你的優點改正的缺點,順便帶出一個優點。(這是較高效的溝通技巧)

相對較好的回答:

1)喜歡追求細節導致項目/作業未能按期完成。通過時間管理能力改變工作方式,先完成框架再改善細節得以解決;

2)不知如何拒絕,同事要求幫忙一概攬下,影響自身工作進度。通過多任務處理能力設定優先順序,以該優先順序表向求助同事展示自己手上工作,並給其一個自己在何時可以給予幫助的時間估計,讓求助人自行決定是否求助,問題解決

3)對處理同一問題的解決辦法上,由於組員自己的技術偏好和技術構成不一樣容易造成溝通障礙及影響項目計劃,所以,應學會高效和有效溝通方式及工作技巧

關於2019的一些面試實戰就小結到這裡了,另外分享一些關於Android開發進階的小資料給大家,評論或者私信回復【資料】即可領取。


推薦閱讀:

TAG:Android | Android開發 | AndroidStudio |