Android中高級工程師面試題

https://www.cnblogs.com/huangjialin/p/8657565.html(存在很多答案錯誤,可參照知識點複習,答案不可全信)  上html

https://www.cnblogs.com/huangjialin/p/8657696.html  下  2五、java

 

https://www.cnblogs.com/huangjialin/p/8622506.html  面試經歷linux

 

19String爲何要設計成不可變的? android

一、字符串池的需求ios

字符串池是方法區(Method Area)中的一塊特殊的存儲區域。當一個字符串已經被建立而且該字符串在 池 中,該字符串的引用會當即返回給變量,而不是從新建立一個字符串再將引用返回給變量。若是字符串是可變的,那麼改變一個引用(如: string2)的字符串將會致使另外一個引用(如: string1)出現髒數據。面試

二、容許字符串緩存哈希碼api

在java中經常會用到字符串的哈希碼,例如: HashMap 。String的不變性保證哈希碼始終一,所以,他能夠不用擔憂變化的出現。 這種方法意味着沒必要每次使用時都從新計算一次哈希碼——這樣,效率會高不少。數組

三、安全緩存

String普遍的用於java 類中的參數,如:網絡鏈接(Network connetion),打開文件(opening files )等等。若是String不是不可變的,網絡鏈接、文件將會被改變——這將會致使一系列的安全威脅。操做的方法本覺得鏈接上了一臺機器,但實際上卻不是因爲反射中的參數都是字符串,一樣,也會引發一系列的安全問題。安全

 

39、如何控制某個方法容許併發訪問線程的個數?

semaphore.acquire() 請求一個信號量,這時候的信號量個數-1(一旦沒有可以使用的信號量,也即信號量個數變爲負數時,再次請求的時候就會阻塞,直到其餘線程釋放了信號量)

semaphore.release() 釋放一個信號量,此時信號量個數+1

 

45、線程間操做List 

List list = Collections.synchronizedList(new ArrayList());  //封裝好的使用synchronized實現的線程安全List

 

5三、死鎖的發生必須知足如下四個條件

  • 互斥條件:一個資源每次只能被一個進程使用。
  • 請求與保持條件:一個進程因請求資源而阻塞時,對已得到的資源保持不放。
  • 不可剝奪條件:進程已得到的資源,在末使用完以前,不能強行剝奪。
  • 循環等待條件:若干進程之間造成一種頭尾相接的循環等待資源關係。

避免死鎖最簡單的方法就是阻止循環等待條件,將系統中全部的資源設置標誌位、排序,規定全部的進程申請資源必須以必定的順序(升序或降序)作操做來避免死鎖。

56、什麼是線程池,如何使用?

建立線程要花費昂貴的資源和時間,若是任務來了才建立線程那麼響應時間會變長,並且一個進程能建立的線程數有限。爲了不這些問題,在程序啓動的時候就建立若干線程來響應處理,它們被稱爲線程池,裏面的線程叫工做線程。

從JDK1.5開始,Java API提供了Executors框架讓你能夠建立不一樣的線程池。好比

單線程池:newSingleThreadExecutor,每次處理一個任務;

數目固定的線程池:newFixedThreadPool

緩存線程池:newCachedThreadPool,適合不少生存期短的任務的可擴展線程池)

週期性執行線程池:newScheduledThreadPool

5八、線程間通訊

Android中主要是使用handler。handler經過調用sendmessage方法,將保存消息的Message發送到Messagequeue中,而looper對象不斷的調用loop方法,從messageueue中取出message,交給同一個handler處理,從而完成線程間通訊。

 

59.Binder的工做機制

 直觀來講,Binder是Android中的一個類,它實現了IBinder接口,從IPC的角度來講,Binder是Android中的一種跨進程通訊的一種方式,同時還能夠理解爲是一種虛擬的物理設備,它的設備驅動是/dev/binder/。從Framework角度來講,Binder是ServiceManager的橋樑。從應用層來講,Binder是客戶端和服務端進行通訊的媒介。

咱們先來了解一下這個類中每一個方法的含義:

DESCRIPTOR:Binder的惟一標識,通常用於當前Binder的類名錶示。

asInterface(android.os.IBinder obj):用於將服務端的Binder對象轉換成客戶端所需的AIDL接口類型的對象,這種轉化過程是區分進程的,若是客戶端和服務端位於同一個進程,那麼這個方法返回的是服務端的stub對象自己,不然返回的是系統封裝後的Stub.proxy對象。 

asBinder():用於返回當前Binder對象

onTransact:該方法運行在服務端的Binder線程池中,當客戶端發起跨進程通訊請求的時候,遠程請求經過系統底層封裝後交給該方法處理。注意這個方法public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags),服務端經過code能夠肯定客戶端所請求的目標方法是什麼,接着從data中取出目標方法所需的參數,而後執行目標方法。當目標方法執行完畢後,就向reply中寫入返回值。這個方法的執行過程就是這樣的。若是這個方法返回false,客戶端是會請求失敗的,因此咱們能夠在這個方法中作一些安全驗證。 

Binder的工做機制可是要注意一些問題:

一、當客戶端發起請求時,因爲當前線程會被掛起,直到服務端返回數據,若是這個遠程方法很耗時的話,那麼是不可以在UI線程,也就是主線程中發起這個遠程請求的。

二、因爲Service的Binder方法運行在線程池中,因此Binder方法無論是耗時仍是不耗時都應該採用同步的方式,由於它已經運行在一個線程中了。

 

60、Android中性能優化

因爲手機硬件的限制,內存和CPU都沒法像pc同樣具備超大的內存,Android手機上,過多的使用內存,會容易致使oom,過多的使用CPU資源,會致使手機卡頓,甚至致使anr。我主要是從一下幾部分進行優化:

App啓動優化,佈局優化,繪製優化,內存泄漏優化,響應速度優化,listview優化,圖片優化,線程優化,電池優化,網絡優化

 

App啓動優化
App啓動的方式有三種:
冷啓動:App沒有啓動過或App進程被killed, 系統中不存在該App進程, 此時啓動App即爲冷啓動。
熱啓動:熱啓動意味着你的App進程只是處於後臺, 系統只是將其從後臺帶到前臺, 展現給用戶。
暖啓動:介於冷啓動和熱啓動之間, 通常來講在如下兩種狀況下發生:
(1)用戶back退出了App, 而後又啓動. App進程可能還在運行, 可是activity須要重建。
(2)用戶退出App後, 系統可能因爲內存緣由將App殺死, 進程和activity都須要重啓, 可是能夠在onCreate中將被動殺死所保存的狀態(onSaveInstanceState)恢復。
 
優化(針對冷啓動):
Application的onCreate(特別是第三方SDK初始化),首屏Activity的渲染都不要進行耗時操做,若是有,就能夠放到子線程或者IntentService中
 

佈局優化:工具 hierarchyviewer,解決方式:

一、刪除無用的空間和層級。

二、選擇性能較低的viewgroup,如Relativelayout,若是能夠選擇Relativelayout也可使用LinearLayout,就優先使用LinearLayout,由於相對來講Relativelayout功能較爲複雜,會佔用更多的CPU資源。

三、使用標籤<include/>重用佈局,<Merge/>減小層級,<viewStub/>進行預加載,使用的時候才加載。

 

繪製優化

繪製優化指view在ondraw方法中避免大量的耗時操做,因爲ondraw方法可能會被頻繁的調用。

一、ondraw方法中不要建立新的局部變量,ondraw方法被頻繁的調用,很容易引發GC。

二、ondraw方法不要作耗時操做。

 

內存優化(部分)

1)少用枚舉,枚舉佔用空間大。

2)使用Android特有的數據結構,如SparseArray來代替hashMap。

3)適當的使用軟引用和弱引用。

 

響應優化

ANR方面:主線程不能作耗時操做,觸摸事件5s,廣播10s,service20s。

UI刷新方面:Android系統每隔16ms會發出VSYNC信號重繪咱們的界面(Activity)。
頁面卡頓的緣由:
(1)過於複雜的佈局.
(2)UI線程的複雜運算
(3)頻繁的GC,致使頻繁GC有兩個緣由:  一、內存抖動, 即大量的對象被建立又在短期內立刻被釋放 -->對象池  .二、瞬間產生大量的對象會嚴重佔用內存區域  -->避免。

 

listview優化

一、getview方法中避免耗時操做。

二、view的複用和viewholder的使用。

三、滑動不適合開啓異步加載。

四、分頁處理數據。

 

圖片優化
(1)對圖片自己進行操做。儘可能不要使用setImageBitmap、setImageResource、BitmapFactory.decodeResource來設置一張大圖,由於這些方法在完成decode後,最終都是經過java層的createBitmap來完成的,須要消耗更多內存.
(2)等比例壓縮圖片。另外,圖片進行縮放的比例,SDK中建議其值是2的指數值,值越大會致使圖片不清晰。
(3)不用的圖片記得調用圖片的recycle()方法
(4)圖片加載使用三級緩存。

 

線程優化

線程優化的思想是使用線程池來管理和複用線程,避免程序中有大量的Thread,同時能夠控制線程的併發數,避免相互搶佔資源而致使線程阻塞。 

電池使用優化(使用工具:Batterystats & bugreport)
(1)優化網絡請求
(2)定位中使用GPS, 請記得及時關閉
(3)JobService喚醒頻率及條件控制
(4)減小IO交互
 
網絡優化(網絡鏈接對用戶的影響:流量,電量,用戶等待)可在Android studio下方logcat旁邊那個工具Network Monitor檢測
API設計:App與Server之間的API設計要考慮網絡請求的頻次, 資源的狀態等. 以便App能夠以較少的請求來完成業務需求和界面的展現.
Gzip壓縮: 使用Gzip來壓縮request和response, 減小傳輸數據量, 從而減小流量消耗.
圖片的Size:能夠在獲取圖片時 告知服務器須要的圖片的寬高, 以便服務器給出合適的圖片, 避免浪費.
網絡緩存:適當的 緩存, 既可讓咱們的應用看起來更快, 也能避免一些沒必要要的流量消耗.

 

四、廣播是分爲有序廣播和無序廣播。

 

五、HttpClient與HttpUrlConnection的區別 
此處延伸:Volley裏用的哪一種請求方式(2.3前HttpClient,2.3後HttpUrlConnection)
 
首先HttpClient和HttpUrlConnection 這兩種方式都支持Https協議,都是以流的形式進行上傳或者下載數據,也能夠說是以流的形式進行數據的傳輸,還有ipv6,以及鏈接池等功能。HttpClient這個擁有很是多的API,因此若是想要進行擴展的話,而且不破壞它的兼容性的話,很難進行擴展,也就是這個緣由,Google在Android6.0的時候,直接就棄用了這個HttpClient.
而HttpUrlConnection相對來講就是比較輕量級了,API比較少,容易擴展,而且可以知足Android大部分的數據傳輸。比較經典的一個框架volley,在2.3版本之前都是使用HttpClient,在2.3之後就使用了HttpUrlConnection。
 
七、進程保活(不死進程)
此處延伸:進程的優先級是什麼
當前業界的Android進程保活手段主要分爲** 黑、白、灰 **三種,其大體的實現思路以下:
黑色保活:不一樣的app進程,用廣播相互喚醒(包括利用系統提供的廣播進行喚醒)
白色保活:啓動前臺Service
灰色保活:利用系統的漏洞啓動前臺Service
黑色保活
所謂黑色保活,就是利用不一樣的app進程使用廣播來進行相互喚醒。舉個3個比較常見的場景:
場景1:開機,網絡切換、拍照、拍視頻時候,利用系統產生的廣播喚醒app
場景2:接入第三方SDK也會喚醒相應的app進程,如微信sdk會喚醒微信,支付寶sdk會喚醒支付寶。由此發散開去,就會直接觸發了下面的 場景3
場景3:假如你手機裏裝了支付寶、淘寶、天貓、UC等阿里系的app,那麼你打開任意一個阿里系的app後,有可能就順便把其餘阿里系的app給喚醒了。(只是拿阿里打個比方,其實BAT系都差很少)
白色保活
白色保活手段很是簡單,就是調用系統api啓動一個前臺的Service進程,這樣會在系統的通知欄生成一個Notification,用來讓用戶知道有這樣一個app在運行着,哪怕當前的app退到了後臺。以下方的LBE和QQ音樂這樣:
灰色保活
灰色保活,這種保活手段是應用範圍最普遍。它是利用系統的漏洞來啓動一個前臺的Service進程,與普通的啓動方式區別在於,它不會在系統通知欄處出現一個Notification,看起來就如同運行着一個後臺Service進程同樣。這樣作帶來的好處就是,用戶沒法察覺到你運行着一個前臺進程(由於看不到Notification),但你的進程優先級又是高於普通後臺進程的。那麼如何利用系統的漏洞呢,大體的實現思路和代碼以下:
思路一:API < 18,啓動前臺Service時直接傳入new Notification();
思路二:API >= 18,同時啓動兩個id相同的前臺Service,而後再將後啓動的Service作stop處理
熟悉Android系統的童鞋都知道,系統出於體驗和性能上的考慮,app在退到後臺時系統並不會真正的kill掉這個進程,而是將其緩存起來。打開的應用越多,後臺緩存的進程也越多。在系統內存不足的狀況下,系統開始依據自身的一套進程回收機制來判斷要kill掉哪些進程,以騰出內存來供給須要的app。這套殺進程回收內存的機制就叫 Low Memory Killer ,它是基於Linux內核的 OOM Killer(Out-Of-Memory killer)機制誕生。
進程的重要性,劃分5級:
前臺進程 (Foreground process)
可見進程 (Visible process)
服務進程 (Service process)
後臺進程 (Background process)
空進程 (Empty process)
 
瞭解完 Low Memory Killer,再科普一下oom_adj。什麼是oom_adj?它是linux內核分配給每一個系統進程的一個值,表明進程的優先級,進程回收機制就是根據這個優先級來決定是否進行回收。對於oom_adj的做用,你只須要記住如下幾點便可:
進程的oom_adj越大,表示此進程優先級越低,越容易被殺回收;越小,表示進程優先級越高,越不容易被殺回收
普通app進程的oom_adj>=0,系統進程的oom_adj纔可能<0
有些手機廠商把這些知名的app放入了本身的白名單中,保證了進程不死來提升用戶體驗(如微信、QQ、陌陌都在小米的白名單中)。若是從白名單中移除,他們終究仍是和普通app同樣躲避不了被殺的命運,爲了儘可能避免被殺,仍是老老實實去作好優化工做吧。
因此,進程保活的根本方案終究仍是回到了性能優化上,進程永生不死終究是個徹頭徹尾的僞命題!
 
八、講解一下Context 
Context是一個抽象基類。在翻譯爲上下文,也能夠理解爲環境,是提供一些程序的運行環境基礎信息。Context下有兩個子類,ContextWrapper是上下文功能的封裝類,而ContextImpl則是上下文功能的實現類。而ContextWrapper又有三個直接的子類, ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是一個帶主題的封裝類,而它有一個直接子類就是Activity,因此Activity和Service以及Application的Context是不同的,只有Activity須要主題,Service不須要主題。Context一共有三種類型,分別是Application、Activity和Service。這三個類雖然分別各類承擔着不一樣的做用,但它們都屬於Context的一種,而它們具體Context的功能則是由ContextImpl類去實現的,所以在絕大多數場景下,Activity、Service和Application這三種類型的Context都是能夠通用的。不過有幾種場景比較特殊,好比啓動Activity,還有彈出Dialog。出於安全緣由的考慮,Android是不容許Activity或Dialog憑空出現的,一個Activity的啓動必需要創建在另外一個Activity的基礎之上,也就是以此造成的返回棧。而Dialog則必須在一個Activity上面彈出(除非是System Alert類型的Dialog),所以在這種場景下,咱們只能使用Activity類型的Context,不然將會出錯。
 
getApplicationContext()和getApplication()方法獲得的對象都是同一個application對象,只是對象的類型不同。
Context數量 = Activity數量 + Service數量 + 1 (1爲Application)
 
1三、保存Activity狀態
onSaveInstanceState(Bundle)會在activity轉入後臺狀態以前被調用,也就是onStop()方法以前,onPause方法以後被調用;
 
1五、Android中跨進程通信的幾種方式
Android 跨進程通訊,像intent,contentProvider,廣播,service均可以跨進程通訊。
intent:這種跨進程方式並非訪問內存的形式,它須要傳遞一個uri,好比說打電話。
contentProvider:這種形式,是使用數據共享的形式進行數據共享。
service:遠程服務,aidl
廣播
 
1六、AIDL理解
AIDL: 每個進程都有本身的Dalvik VM實例,都有本身的一塊獨立的內存,都在本身的內存上存儲本身的數據,執行着本身的操做,都在本身的那片狹小的空間裏過完本身的一輩子。而aidl就相似與兩個進程之間的橋樑,使得兩個進程之間能夠進行數據的傳輸,跨進程通訊有多種選擇,好比 BroadcastReceiver , Messenger 等,可是 BroadcastReceiver 佔用的系統資源比較多,若是是頻繁的跨進程通訊的話顯然是不可取的;Messenger 進行跨進程通訊時請求隊列是同步進行的,沒法併發執行。
 
Binde機制簡單理解:
在Android系統的Binder機制中,是有Client,Service,ServiceManager,Binder驅動程序組成的,其中Client,service,Service Manager運行在用戶空間,Binder驅動程序是運行在內核空間的。而Binder就是把這4種組件粘合在一塊的粘合劑,其中核心的組件就是Binder驅動程序,Service Manager提供輔助管理的功能,而Client和Service正是在Binder驅動程序和Service Manager提供的基礎設施上實現C/S 之間的通訊。其中Binder驅動程序提供設備文件/dev/binder與用戶控件進行交互,
Client、Service,Service Manager經過open和ioctl文件操做相應的方法與Binder驅動程序進行通訊。而Client和Service之間的進程間通訊是經過Binder驅動程序間接實現的。而Binder Manager是一個守護進程,用來管理Service,並向Client提供查詢Service接口的能力。
 

1九、QQ空間熱修復的原理
咱們知道Java虛擬機 —— JVM 是加載類的class文件的,而Android虛擬機——Dalvik/ART VM 是加載類的dex文件,
而他們加載類的時候都須要ClassLoader,ClassLoader有一個子類BaseDexClassLoader,而 BaseDexClassLoader下有一個
數組——DexPathList,是用來存放dex文件,當BaseDexClassLoader經過調用findClass方法時,實際上就是遍歷數組,
找到相應的dex文件,找到,則直接將它return。而熱修復的解決方法就是將新的dex添加到該集合中,而且是在舊的dex的前面,
因此就會優先被取出來而且return返回。
 
2五、HybridApp WebView和JS交互
(一)Android調用JS的代碼
1. 經過WebView的loadUrl(),使用該方法比較簡潔,方便。可是效率比較低,獲取返回值比較困難。
2. 經過WebView的evaluateJavascript(),能夠直接傳入結果的回調方法。該方法效率高,可是4.4以上的版本才支持,4.4如下版本不支持。因此建議二者混合使用。
 
(二)JS調用Android的代碼
1.經過WebView的addJavascriptInterface()進行對象映射
該方法使用簡單,僅將Android對象和JS對象映射便可,可是存在比較大的漏洞。漏洞產生緣由是:當JS拿到Android這個對象後,就 能夠調用這個Android對象中全部的方法,包括系統類(java.lang.Runtime 類),從而進行任意代碼執行。
解決方式:
(1)Google 在Android 4.2 版本中規定對被調用的函數以 @JavascriptInterface進行註解從而避免漏洞攻擊。
(2)在Android 4.2版本以前採用攔截prompt()進行漏洞修復
2.經過 WebViewClient 的shouldOverrideUrlLoading ()方法回調攔截 url
這種方式的優勢:不存在方式1的漏洞; 缺點:JS獲取Android方法的返回值複雜。(ios主要用的是這個方式)
(1)Android經過 WebViewClient 的回調方法shouldOverrideUrlLoading ()攔截 url
(2)解析該 url 的協議
(3)若是檢測到是預先約定好的協議,就調用相應方法
3. 經過 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回調攔截JS對話框alert()、confirm()、prompt()消息
這種方式的優勢:不存在方式1的漏洞;缺點:JS獲取Android方法的返回值複雜。
 https://www.cnblogs.com/zhangqie/p/6387433.html
https://www.cnblogs.com/itpepe/p/4882012.html
相關文章
相關標籤/搜索