當前位置:
首頁 > 最新 > Android程序猿 面試秘籍

Android程序猿 面試秘籍

惟楚有才於斯為盛!!!

又到夏季招聘好時節了,程序員面試考核一直都是熱門話題,今年也不例外。

而對於Android程序員來說,面試時候什麼最重要呢?絕對是技術,如今很多企業招聘Android工程師會不僅會給一份筆試考題,還會在面試中不斷的問你技術問題,從Android基礎到Android項目,難度不亞於一場高考,哪怕是技術過硬的Android程序員在面試+筆記的連番炮轟下,也會蒙圈。

但是,從今天開始,各位Android程序員再也不用擔心面試了,我根據自己以往的一些面試經歷,總結了一些面試官面試中可能會去問的問題來給大家分享一下。做事就要做到極致,希望每位同胞們能夠過五關斬六將:去到自己心儀的公司,能夠擁有屬於自己的那一份美好的未來.

一款App流暢與否安裝在自己的真機里,玩幾天就能有個大概的感性認識。不過通過專業的分析工具可以使我們更好的分析我們的應用。而在實際開發中,我們解決完當前應用所有bug後,就會開始考慮到新能的優化。

如果不考慮使用其他第三方性能分析工具的話,我們可以直接使用ddms中的工具,其實ddms工具已經非常的強大了。ddms中有traceview、heap、allocation tracker等工具都可以幫助我們分析應用的方法執行時間效率和內存使用情況。

traceview

TraceView簡介

Traceview是Android平台特有的數據採集和分析工具,它主要用於分析Android中應用程序的hotspot(瓶頸)。Traceview本身只是一個數據分析工具,而數據的採集則需要使用Android SDK中的Debug類或者利用DDMS工具。

二者的用法如下:

開發者在一些關鍵代碼段開始前調用Android SDK中Debug類的startMethodTracing函數,並在關鍵代碼段結束前調用stopMethodTracing函數。這兩個函數運行過程中將採集運行時間內該應用所有線程(注意,只能是Java線程)的函數執行情況,並將採集數據保存到/mnt/sdcard/下的一個文件中。開發者然後需要利用SDK中的Traceview工具來分析這些數據


Android的虛擬機是基於寄存器的Dalvik,它的最大堆大小一般是16M,有的機器為24M。因此我們所能利用的內存空間是有限的。如果我們的內存佔用超過了一定的水平就會出現OutOfMemory的錯誤。

內存溢出的幾點原因:

(1)資源釋放問題

程序代碼的問題,長期保持某些資源,如Context、Cursor、IO流的引用,資源得不到釋放造成內存泄露。

(2)對象內存過大問題

保存了多個耗用內存過大的對象(如Bitmap、XML文件),造成內存超出限制。

(3)static關鍵字的使用問題

static是Java中的一個關鍵字,當用它來修飾成員變數時,那麼該變數就屬於該類,而不是該類的實例。所以用static修飾的變數,它的生命周期是很長的,如果用它來引用一些資源耗費過多的實例(Context的情況最多),這時就要謹慎對待了。

publicclassClassName {privatestaticContext mContext;//省略

}

以上的代碼是很危險的,如果將Activity賦值到mContext的話。那麼即使該Activity已經onDestroy,但是由於仍有對象保存它的引用,因此該Activity依然不會被釋放。

針對static的解決方案

(1) 應該盡量避免static成員變數引用資源耗費過多的實例,比如Context。

(2) 盡量使用ApplicationContext,因為Application的Context的生命周期比較長,引用它不會出現內存泄露的問題。

(3) 使用WeakReference代替強引用。比如可以使用WeakReference mContextRef;


線程產生內存泄露的主要原因在於線程生命周期的不可控。我們來考慮下面一段代碼。

這段代碼很平常也很簡單,是我們經常使用的形式。我們思考一個問題:假設MyThread的run函數是一個很費時的操作,當我們開啟該線程後,將設備的橫屏變為了豎屏,一 般情況下當屏幕轉換時會重新創建Activity,按照我們的想法,老的Activity應該會被銷毀才對,然而事實上並非如此。

由於我們的線程是Activity的內部類,所以MyThread中保存了Activity的一個引用,當MyThread的run函數沒有結束時,MyThread是不會被銷毀的,因此它所引用的老的Activity也不會被銷毀,因此就出現了內存泄露的問題。

有些人喜歡用Android提供的AsyncTask,但事實上AsyncTask的問題更加嚴重,Thread只有在run函數不結束時才出現這種內存泄露問題,然而AsyncTask內部的實現機制是運用了ThreadPoolExcutor,該類產生的Thread對象的生命周期是不確定的,是應用程序無法控制的,因此如果AsyncTask作為Activity的內部類,就更容易出現內存泄露的問題。

針對這種線程導致的內存泄露問題的解決方案:

(1) 將線程的內部類,改為靜態內部類(因為非靜態內部類擁有外部類對象的強引用,而靜態類則不擁有)。

(2) 在線程內部採用弱引用保存Context引用。

OOM內存溢出,想要避免OOM異常首先我們要知道什麼情況下會導致OOM異常。

(1)圖片過大導致OOM

Android 中用bitmap時很容易內存溢出,比如報如下錯誤:Java.lang.OutOfMemoryError : bitmap size exceeds VM budget。

解決方法:

方法1: 等比例縮小圖片

以上代碼可以優化內存溢出,但它只是改變圖片大小,並不能徹底解決內存溢出。

方法2:對圖片採用軟引用,及時地進行recyle()操作

方法3:使用載入圖片框架處理圖片,如專業處理載入圖片的ImageLoader圖片載入框架。還有我們學的XUtils的BitMapUtils來做處理。

(2)界面切換導致OOM

一般情況下,開發中都會禁止橫屏的。因為如果是來回切換話,activity的生命周期會重新銷毀然後創建。

有時候我們會發現這樣的問題,橫豎屏切換N次後 OOM了。

這種問題沒有固定的解決方法,但是我們可以從以下幾個方面下手分析。

1、看看頁面布局當中有沒有大的圖片,比如背景圖之類的。

去除xml中相關設置,改在程序中設置背景圖(放在onCreate()方法中):

在Activity destory時注意,drawable.setCallback(null);防止Activity得不到及時的釋放。

2、跟上面方法相似,直接把xml配置文件載入成view 再放到一個容器里,然後直接調用 this.setContentView(View view);方法,避免xml的重複載入。

3、 在頁面切換時儘可能少地重複使用一些代碼

比如:重複調用資料庫,反覆使用某些對象等等……

(3)查詢資料庫沒有關閉游標

程序中經常會進行查詢資料庫的操作,但是經常會有使用完畢Cursor後沒有關閉的情況。如果我們的查詢結果集比較小,對內存的消耗不容易被發現,只有在常時間大量操作的情況下才會出現內存問題,這樣就會給以後的測試和問題排查帶來困難和風險。

(4)構造Adapter時,沒有使用緩存的 convertView

在使用ListView的時候通常會使用Adapter,那麼我們應該儘可能的使用ConvertView。

為什麼要使用convertView?

當convertView為空時,用setTag()方法為每個View綁定一個存放控制項的ViewHolder對象。當convertView不為空,重複利用已經創建的view的時候,使用getTag()方法獲取綁定的ViewHolder對象,這樣就避免了findViewById對控制項的層層查詢,而是快速定位到控制項。

(5)Bitmap對象不再使用時調用recycle()釋放內存

有時我們會手工的操作Bitmap對象,如果一個Bitmap對象比較占內存,當它不再被使用的時候,可以調用Bitmap.recycle()方法回收此對象的像素所佔用的內存,但這不是必須的,視情況而定。

(6)其他

Android應用程序中最典型的需要注意釋放資源的情況是在Activity的生命周期中,在onPause()、onStop()、 onDestroy()方法中需要適當的釋放資源的情況。使用廣播沒有註銷也會產生OOM。


UncaughtExceptionHandler

1.自定義一個Application,比如叫MyApplication繼承Application實現UncaughtExceptionHandler。

2..覆寫UncaughtExceptionHandler的onCreate和uncaughtException方法。

注意:上面的代碼只是簡單的將異常列印出來。

在onCreate方法中我們給Thread類設置默認異常處理handler,如果這句代碼不執行則一切都是白搭。

在uncaughtException方法中我們必須新開闢個線程進行我們異常的收集工作,然後將系統給殺死。

在AndroidManifest中配置該Application

(二)Bug收集工具Crashlytics

Crashlytics 是專門為移動應用開發者提供的保存和分析應用崩潰的工具。國內主要使用的是友盟做數據統計。

Crashlytics的好處:

不會漏掉任何應用崩潰信息。

可以象Bug管理工具那樣,管理這些崩潰日誌。

可以每天和每周將崩潰信息匯總發到你的郵箱,所有信息一目了然。

使用步驟:

1.註冊需要審核通過才能使用,國內同類產品頂多發個郵箱激活鏈接;

2.支持Eclipse、Intellij IDEA和Android Studio等三大IDE;

3.Eclipse插件是iOS主題風格UI,跟其他plugin在一起簡直是鶴立雞群;

4.只要登錄帳號並選擇項目,會自動導入jar包並生成一個序列號,然後在AndroidManifest.xml和啟動Activity的入口添加初始化代碼,可以說是一鍵式操作,當然要使用除錯誤統計外的其他功能還是得自己添加代碼;

5.不像友盟等國內同類產品,將固定的序列號直接寫入xml文件,而是動態自動生成的;當然這個存放序列號的xml文件也是不能修改和提交到版本控制系統的;

6.後台可以設置郵件提醒,當然這個最好不要開啟,Android開發那數量驚人、千奇百怪的錯誤信息你懂的。

7.不僅能統計到UncaughtException這種未捕獲的Crash異常信息,只要在try/catch代碼塊的catch中添加一行代碼就能統計到任何異常;

try{ myMethodThatThrows(); }catch(Exception e){ Crashlytics.logException(e); //handle your exception here! }

相當詳細的錯誤信息,不僅僅是簡單的列印StackTrace信息;並且能看到最近一次crash的機器可用內存等信息,而不僅僅是簡單統計機型和版本號。

使用連接:http://blog.csdn.net/smking/article/details/39320695


在Android上,如果你的應用程序有一段時間響應不夠靈敏,系統會向用戶顯示一個對話框,這個對話框稱作應用程序無響應(ANR:Application Not Responding)對話框。用戶可以選擇讓程序繼續運行,但是,他們在使用你的應用程序時,並不希望每次都要處理這個對話框。因此,在程序里對響應性能的設計很重要,這樣,系統不會顯示ANR給用戶。

Activity 5秒 broadcast10秒

耗時的操作worker thread裡面完成, handler message…AsynTask , intentservice.等…

ANR:Application Not Responding,即應用無響應

ANR一般有三種類型:

1:KeyDispatchTimeout(5 seconds) –主要類型

按鍵或觸摸事件在特定時間內無響應

2:BroadcastTimeout(10 seconds)

BroadcastReceiver在特定時間內無法處理完成

3:ServiceTimeout(20 seconds) –小概率類型

Service在特定的時間內無法處理完成

超時的原因一般有兩種:

(1)當前的事件沒有機會得到處理(UI線程正在處理前一個事件沒有及時完成或者looper被某種原因阻塞住)

(2)當前的事件正在處理,但沒有及時完成

UI線程盡量只做跟UI相關的工作,耗時的工作(資料庫操作,I/O,連接網路或者其他可能阻礙UI線程的操作)放入單獨的線程處理,盡量用Handler來處理UI thread和thread之間的交互。

UI線程主要包括如下:

Activity:onCreate(), onResume(), onDestroy(), onKeyDown(), onClick()

AsyncTask: onPreExecute(), onProgressUpdate(), onPostExecute(), onCancel()

Mainthread handler: handleMessage(), post(runnable r)

查找ANR的方式: 1. 導出/data/data/anr/traces.txt,找出函數和調用過程,分析代碼 2. 通過性能LOG人肉查找


共享內存(變數);

文件,資料庫;

Handler;

Java里的wait(),notify(),notifyAll()


Dalvik虛擬機運行在Linux操作系統之上。Linux操作系統並沒有純粹的線程概念,只要兩個進程共享一個地址空間,那麼就可以認為它們是同一個進程的兩個線程。Linux系統提供了兩個fork和clone調用,其中,前者是用來創建進程的,而後者是用來創建線程的。

一般來說,虛擬機的進程和線程都是和目標機器本地操作系統的進程和線程一一對應的,這樣的好處是可以使本地操作系統來調度進程和線程。

每個Android應用程序進程都有一個Dalvik虛擬機實例。這樣做得好處是Android應用程序進程之間不會互相影響,也就是說,一個Android應用程序進程的意外終止,不會影響到其他的應用程序進程的正常運行。

每個Android應用程序進程都是由一種稱為Zygote的進程fork出來的。Zygote進程是由init進程啟動起來的,也就是在系統啟動的時候啟動的。Zygnote進程在啟動的時候,會創建一個虛擬機實例,並且在這個虛擬機實例將所有的Java核心庫都載入起來。每當Zygote進程需要創建一個Android應用程序進程的時候,它就通過複製自身來實現,也就是通過fork系統調用來實現。這些被fork出來的Android應用程序進程,一方面是複製了Zygote進程中的虛擬機實例,另外一方面是與Zygote進程共享了同一套Java核心庫。這樣不僅Android程序進程的創建很快,而且所有的應用程序都共享同一套Java核心庫而節省了內存空間。


android系統架構分從下往上為linux 內核層、運行庫、應用程序框架層、和應用程序層。

負責硬體的驅動程序、網路、電源、系統安全以及內存管理等功能。

即c/c++函數庫部分,大多數都是開放源代碼的函數庫,例如webkit,該函數庫負責 android網頁瀏覽器的運行,例如標準的c函數庫libc、openssl、sqlite等,當然也包括支持遊戲開發2dsgl和 3dopengles,在多媒體方面有mediaframework框架來支持各種影音和圖形文件的播放與顯示,例如mpeg4、h.264、mp3、 aac、amr、jpg和png等眾多的多媒體文件格式。android的runtime負責解釋和執行生成的dalvik格式的位元組碼。

(應用軟體架構),java應用程序開發人員主要是使用該層封裝好的api進行快速開發。

該層是java的應用程序層,android內置的googlemaps、e-mail、即時通信工具、瀏覽器、mp3播放 器等處於該層,java開發人員開發的程序也處於該層,而且和內置的應用程序具有平等的位置,可以調用內置的應用程序,也可以替換內置的應用程序。


如何限制的?

Android應用的開發語言為Java,每個應用最大可使用的堆內存受到Android系統的限制

?Android每一個應用的堆內存大小有限

?通常的情況為16M-48M

?通過ActivityManager的getMemoryClass()來查詢可用堆內存限制

?3.0(HoneyComb)以上的版本可以通過largeHeap=「true」來申請更多的堆內存

?NexueHeap 512

?如果試圖申請的內存大於當前餘下的堆內存就會引發OutOfMemoryError()

?應用程序由於各方面的限制,需要注意減少內存佔用,避免出現內存泄漏。

獲取這個代碼:


1、注意資源回收,像資料庫,輸入輸出流,定位操作這樣的對象,要在使用完及時關閉流。

2、少使用靜態變數,因為系統將靜態變數的優先順序設定的很高,會最後回收。所以可能因為靜態變數導致該回收的沒有回收。而回收了不該回收的內存。

3、注意大圖片的縮放,如果載入的圖片很大,要先經過自己程序的處理,降低解析度等。最好設置多種解析度格式的圖片,以減少內存消耗。

4、動態註冊監聽,把一些只有顯示的時候才使用到的監聽放進程序內部,而不是放在manifesat中去。

5、減少使用動畫,或者適當減少動畫的幀數。

6、注意自己的程序邏輯,在該關閉自己程序的控制項的時候,主動關閉,不要交給系統去決定。(這個要自己把握好,也不是說都自己搞定,只有那些自己確定需要關閉的對象,自己將其關閉。)


①aidl是Android interface definition Language 的英文縮寫,意思Android 介面定義語言。

②使用aidl可以幫助我們發布以及調用遠程服務,實現跨進程通信。

③將服務的aidl放到對應的src目錄,工程的gen目錄會生成相應的介面類

我們通過bindService(Intent,ServiceConnect,int)方法綁定遠程服務,在bindService中有一個ServiceConnec介面,我們需要覆寫該類的onServiceConnected(ComponentName,IBinder)方法,這個方法的第二個參數IBinder對象其實就是已經在aidl中定義的介面,因此我們可以將IBinder對象強制轉換為aidl中的介面類。

我們通過IBinder獲取到的對象(也就是aidl文件生成的介面)其實是系統產生的代理對象,該代理對象既可以跟我們的進程通信,又可以跟遠程進程通信,作為一個中間的角色實現了進程間通信。


AIDL全稱Android Interface Definition Language(AndRoid介面描述語言) 是一種介面描述語言; 編譯器可以通過aidl文件生成一段代碼,通過預先定義的介面達到兩個進程內部通信進程跨界對象訪問的目的。需要完成2件事情: 1. 引入AIDL的相關類.; 2. 調用aidl產生的class.理論上, 參數可以傳遞基本數據類型和String, 還有就是Bundle的派生類, 不過在Eclipse中,目前的ADT不支持Bundle做為參數。


[Android中的動畫有哪幾類,它們的特點和區別是什麼(★★★)

Android中動畫分為兩種,一種是Tween動畫、還有一種是Frame動畫。

Tween動畫,這種實現方式可以使視圖組件移動、放大、縮小以及產生透明度的變化;

Frame動畫,傳統的動畫方法,通過順序的播放排列好的圖片來實現,類似電影。

如何修改Activity進入和退齣動畫(★★)

可以通過兩種方式,一是通過定義Activity的主題,二是通過覆寫Activity的overridePendingTransition方法。

通過設置主題樣式

在styles.xml中編輯如下代碼:

添加themes.xml文件:

在AndroidManifest.xml中給指定的Activity指定theme。

覆寫overridePendingTransition方法

overridePendingTransition(R.anim.fade, R.anim.hold);

屬性動畫,例如一個button從A移動到B點,B點還是可以響應點擊事件,這個原理是什(★★)

補間動畫只是顯示的位置變動,View的實際位置未改變,表現為View移動到其他地方,點擊事件仍在原處才能響應。而屬性動畫控制項移動後事件相應就在控制項移動後本身進行處理.

=======分隔符======

給大家推薦個活躍的開發者社區:掘金是面向程序員的的技術社區,從大廠技術分享到安卓開發最佳實踐,掃二維碼下載掘金APP,來掘金你不會錯過任何一個技術乾貨。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Android開發中文站 的精彩文章:

TAG:Android開發中文站 |