Android開發面試經——4.常見Android進階筆試題(更新中...)


 

關注finddreams博客:http://blog.csdn.net/finddreams/article/details/44301359

上一篇文章我們已經了解了Android筆試的一些基礎題目, 
[《Android開發面試經——2.常見Android基礎筆試題》 ] 
(http://blog.csdn.net/finddreams/article/details/44219231
筆試完,就是面試官問你問題了,相比筆試,面試我們往往會有些許緊張,因為不知道面試官會問什么奇怪的問題,要是問的問題剛好不懂,這時就更加頭皮發麻了。為了能在面試提問中取得一個滿意的表現,我特別整理了一下常見的面試官提的技術問題: 
Android開發面試經——5.常見面試官提問Android題① 
Android開發面試經——6.常見面試官提問Android題②(更新中…)

但是做為一個有經驗的開發者,僅僅知道基礎題還是不夠的,你的簡歷上說有兩年以上工作經驗的話,那面試官肯定會問一些深入性的問題,看你能否回答的出。所以為了找一個更好的工作,我們還需要去了解一下Android進階的筆試題目:

1.什么是ANR,如何避免? 
ANR:Application Not Responding。 
在 Android 中,活動管理器和窗口管理器這兩個系統服務負責監視應用程序的響應。當出現下列情況時,Android 就會顯示 ANR 對話框了: 
①.用戶對應用程序的操作(如輸入事件,按鍵、觸摸屏事件)在5秒內無響應 
②. 廣播接受器(BroadcastReceiver)在10秒內仍未執行完畢 
Android 應用程序完全運行在一個獨立的線程中(例如 main)。這就意味着,任何在主 線程中運行的,需要消耗大量時間的操作都會引發 ANR。因為此時,你的應用程序已經沒有機會去響應輸入事件和意向廣播(Intentbroadcast)。 
避免方法:Activity 應該在它的關鍵生命周期方法(如 onCreate()和 onResume())里盡可能少的去做創建操作, 
潛在的耗時操作。例如網絡或數據庫操作,或者高耗時的計算如改變位圖尺寸,應該在子線程里(或者異步方式)來完成。 
主線程應該為子線程提供一個 Handler,以便完成時能夠提交給主線程。

2.Handler機制原理? 
andriod 提供了 Handler 和 Looper 來滿足線程間的通信。Handler 先進先出原則。 
Looper 類用來管理特定線程內對象之間的消息交換 (MessageExchange)。 
1)Looper: 一個線程可以產生一個 Looper 對象,由它來管理此線程里的 MessageQueue(消息隊列)。 
2)Handler: 你可以構造 Handler 對象來與 Looper 溝通,以便 push 新消息到 MessageQueue 里;或者接收 Looper 從 MessageQueue 取出)所送來的消息。 
3) Message Queue(消息隊列 ): 用來存放線程放入的消息。 
4)線程: UI thread 通常就是 main thread, 而 Android 啟動程序時會替它建立一個 MessageQueue。

3.請解釋下在單線程模型中Message、Handler、Message Queue、Looper之間的關系。 
簡單的說,Handler獲取當前線程中的 looper對象,looper 用來從存放 Message 的 MessageQueue中取出 Message,再有 Handler 進行 Message 的分發和處理. 
Message Queue(消息隊列): 用來存放通過 Handler 發布的消息, 通常附屬於某一個創建它的線程,可以通過 Looper.myQueue()得到當前線程的消息隊列 
Handler:可以發布或者處理一個消息或者操作一個 Runnable,通過 Handler發布消息, 消息將只會發送到與它關聯的消息隊列,然也只能處理該消息隊列中的消息 
Looper:是 Handler 和消息隊列之間通訊橋梁,程序組件首先通過 Handler 把消息傳遞給 Looper,Looper 把消息放入隊列。Looper 也把消息隊列里的消息廣播給所有的 
Handler:Handler 接受到消息后調用 handleMessage進行處理 
Message:消息的類型,在 Handler 類中的 handleMessage 方法中得到單個的消息進行處理 
在單線程模型下, 為了線程通信問題, Android 設計了一個 Message Queue(消息隊列), 線程間可以通過該 Message Queue 並結合 Handler 和 Looper 組件進行信息交換。 
下面將對它 們進行分別介紹: 
1. Message 
Message 消息,理解為線程間交流的信息,處理數據后台線程需要更新 UI ,則發送Message 內含一些數據給 UI 線程。 
2. Handler 
Handler處理者,是 Message 的主要處理者,負責 Message 的發送,Message 內容的執行處理。后台線程就是通過傳進來的 Handler對象引用來 sendMessage(Message)。 
而使用 Handler,需要 implement 該類的 handleMessage(Message)方法,它是處理這些 
Message 的操作內容,例如 Update UI 。通常需要子類化 Handler 來實現 handleMessage方法。 
3. Message Queue 
Message Queue 消息隊列,用來存放通過 Handler 發布的消息,按照先進先出執行。每個 message queue 都會有一個對應的 Handler。Handler 會向 messagequeue 通過兩種方法發送消息:sendMessage 或 post。這兩種消息都會插在 message queue 隊尾並 
按先進先出執行。但通過這兩種方法發送的消息執行的方式略有不同:通過 sendMessage發送的是一個 message 對象,會被 Handler 的 handleMessage()函數處理;而通過 post 方法發送的是一個 runnable 對象,則會自己執行。 
4. Looper 
Looper 是每條線程里的 Message Queue 的管家。Android 沒有 Global 的MessageQueue,而 Android 會自動替主線程(UI 線程)建立 Message Queue,但在子線程里並沒有建立 Message Queue。 所以調用 Looper.getMainLooper()得到的主線程的 Looper 不為 NULL,但調用 Looper.myLooper()得到當前線程的 Looper 就有可能為 NULL。

4.Android 中線程與線程,進程與進程之間如何通信 
1、一個 Android 程序開始運行時,會單獨啟動一個 Process。 
默認情況下,所有這個程序中的 Activity 或者 Service 都會跑在這個 Process。 
默認情況下,一個 Android 程序也只有一個 Process,但一個 Process 下卻可以有許多個 Thread。 
2、一個 Android 程序開始運行時,就有一個主線程 MainThread 被創建。該線程主要負責 UI 界面的顯示、更新和控件交互,所以又叫 UI Thread。 
一個 Android 程序創建之初,一個 Process 呈現的是單線程模型–即 Main Thread, 
所有的任務都在一個線程中運行。所以,Main Thread 所調用的每一個函數,其耗時應該 
越短越好。而對於比較費時的工作,應該設法交給子線程去做,以避免阻塞主線程(主線程被阻塞,會導致程序假死 現象) 。 
3、Android 單線程模型:Android UI 操作並不是線程安全的並且這些操作必須在 UI 線程中執行。如果在子線程中直接修改 UI,會導致異常。 
4.Android 的 的 IPC ( 進程間通信 ) 機制 
IPC 是內部進程通信的簡稱, 是共享 ” 命名管道 ” 的資源。Android 中的 IPC機制是為了讓 
Activity 和 Service之間可以隨時的進行交互,故在 Android 中該機制,只適用於 Activity 和 Service之間的通信,類似於遠程方法調用,類似於 C/S 模式的訪問。通過定義 AIDL 接口文件來定義 IPC 接口。Servier 端實現 IPC接口,Client 端調用 IPC接口本地代理。

5.Android應用程序框架 
這里寫圖片描述 
這里寫圖片描述

6.View, surfaceView, GLSurfaceView的區別 
View 是最基礎的,必須在 UI 主線程內更新畫面,速度較慢。 
SurfaceView 是 view 的子類,類似使用雙緩機制,在新的線程中更新畫面所以刷新界面速度比 view 快 GLSurfaceView 是 SurfaceView 的子類,opengl 專用的。 
區別:SurfaceView是從View基類中派生出來的顯示類,直接子類有GLSurfaceView和VideoView,可以看出GL和視頻播放以及Camera攝像頭一般均使用SurfaceView 
SurfaceView和View最本質的區別在於,surfaceView是在一個新起的單獨線程中可以重新繪制畫面而View必須在UI的主線程中更新畫面。 
那么在UI的主線程中更新畫面 可能會引發問題,比如你更新畫面的時間過長,那么你的主UI線程會被你正在畫的函數阻塞。那么將無法響應按鍵,觸屏等消息。 
當使用surfaceView 由於是在新的線程中更新畫面所以不會阻塞你的UI主線程。但這也帶來了另外一個問題,就是事件同步。比如你觸屏了一下,你需要surfaceView中thread處理,一般就需要有一個event queue的設計來保存touch event,這會稍稍復雜一點,因為涉及到線程同步。

7. AIDL的全稱是什么?如何工作? 
AIDL 全稱 Android Interface Definition Language(Android 接口描述語言)是一種接口描述語言 ; 編譯器可以通過 aidl文件生成一段代碼, 通過預先定義的接口達到兩個進程內 
部通信進程跨界對象訪問的目的.AIDL 的 IPC 的機制和 COM 或 CORBA 類似 , 是基於接口的, 但它是輕量級的。 它使用代理類在客戶端和實現層間傳遞值 . 如果要使用 AIDL, 需要完成2件事情 : 
1. 引入AIDL的相關類 .; 
2. 調用 aidl產生的 class.理論上 , 參數可以傳遞基本數據類型和String, 還有就是Bundle的派生類 
當A進程要去調用B進程中的service時,並實現通信,我們通常都是通過AIDL來操作的 。 
A工程: 
首先我們在net.blogjava.mobile.aidlservice包中創建一個RemoteService.aidl文件,在里面我們自定義一個接口,含有方法get。ADT插件會在gen目錄下自動生成一個RemoteService.Java文件,該類中含有一個名為RemoteService.stub的內部類,該內部類中含有aidl文件接口的get方法。 
說明一:aidl文件的位置不固定,可以任意 
然后定義自己的MyService類,在MyService類中自定義一個內部類去繼承RemoteService.stub這個內部類,實現get方法。在onBind方法中返回這個內部類的對象,系統會自動將這個對象封裝成IBinder對象,傳遞給他的調用者。 
其次需要在AndroidManifest.xml文件中配置MyService類,代碼如下:

<!-- 注冊服務 --> <service android:name=".MyService"> <intent-filter> <!-- 指定調用AIDL服務的ID --> <action android:name="net.blogjava.mobile.aidlservice.RemoteService" /> </intent-filter> </service>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

為什么要指定調用AIDL服務的ID,就是要告訴外界MyService這個類能夠被別的進程訪問,只要別的進程知道這個ID,正是有了這個ID,B工程才能找到A工程實現通信。 
說明:AIDL並不需要權限 
B工程: 
首先我們要將A工程中生成的RemoteService.java文件拷貝到B工程中,在bindService方法中綁定aidl服務 
綁定AIDL服務就是將RemoteService的ID作為intent的action參數。 
說明:如果我們單獨將RemoteService.aidl文件放在一個包里,那個在我們將gen目錄下的該包拷貝到B工程中。如果我們將RemoteService.aidl文件和我們的其他類存放在一起,那么我們在B工程中就要建立相應的包,以保證RmoteService.java文件的報名正確,我們不能修改RemoteService.java文件 
bindService(new Inten(“net.blogjava.mobile.aidlservice.RemoteService”), serviceConnection, Context.BIND_AUTO_CREATE); 
ServiceConnection的onServiceConnected(ComponentName name, IBinder service)方法中的service參數就是A工程中MyService類中繼承了RemoteService.stub類的內部類的對象。

8.關於AndroidOOM,以及如何避免? 
Android的虛擬機是基於寄存器的Dalvik,它的最大堆大小一般是16M,有的機器為24M。因此我們所能利用的內存空間是有限的。如果我們的內存占用超過了一定的水平就會出現OutOfMemory的錯誤。 
①.為什么會出現內存不夠用的情況呢?我想原因主要有兩個:由於我們程序的失誤,長期保持某些資源(如Context)的引用,造成內存泄露,資源造成得不到釋放。保存了多個耗用內存過大的對象(如Bitmap),造成內存超出限制。 
② .如何避免優化? 
1、應該盡量避免static成員變量引用資源耗費過多的實例,比如Context。Context盡量使用Application Context,因為Application的Context的生命周期比較長,引用它不會出現內存泄露的問題。使用WeakReference代替強引用。比如可以使用WeakReference mContextRef; 
2、線程也是造成內存泄露的一個重要的源頭。線程產生內存泄露的主要原因在於線程生命周期的不可控。將線程的內部類,改為靜態內部類。3、Bitmap問題:可以說出現OutOfMemory問題的絕大多數人,都是因為Bitmap的問題。因為Bitmap占用的內存實在是太多了,它是一個“超級大胖子”,特別是分辨率大的圖片,如果要顯示多張那問題就更顯著了。 
如何解決Bitmap帶給我們的內存問題? 
及時的銷毀。  雖然,系統能夠確認Bitmap分配的內存最終會被銷毀,但是由於它占用的內存過多,所以很可能會超過java堆的限制。因此,在用完Bitmap時,要及時的recycle掉。recycle並不能確定立即就會將Bitmap釋放掉,但是會給虛擬機一個暗示:“該圖片可以釋放了”。設置一定的采樣率。  有時候,我們要顯示的區域很小,沒有必要將整個圖片都加載出來,而只需要記載一個縮小過的圖片,這時候可以設置一定的采樣率,那么就可以大大減小占用的內存。如下面的代碼: BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2;//圖片寬高都為原來的二分之一,即圖片為原來的四分之一。 
4、巧妙的運用軟引用(SoftRefrence)  有些時候,我們使用Bitmap后沒有保留對它的引用,因此就無法調用Recycle函數。這時候巧妙的運用軟引用,可以使Bitmap在內存快不足時得到有效的釋放 
5、及時釋放Cursor; 
6、盡量使用9path圖片。Adapter要使用convertView復用等等;

9. AsyncTask 的介紹 
在開發 Android 移動客戶端的時候往往要使用多線程來進行操作, 我們通常會將耗時的操作放在單獨的線程執行, 避免其占用主線程而給用戶帶來不好的用戶體驗。 但是在子線程中無法 去操作主線程(UI 線程) ,在子線程中操作 UI 線程會出現錯誤。因此 android 提供了一個類 Handler 來在子線程中來更新 UI 線程,用發消息的機制更新 UI 界面,呈現給用戶。 這樣就解決了子線程更新 UI 的問題。但是費時的任務操作總會啟動一些匿名的子線程,太多的子線程給系統帶來巨大的負擔,隨之帶來一些性能問題。因此 android 提供了一個工具類AsyncTask,顧名思義異步執行任務。這個 AsyncTask 生來就是處理一些后台的比較耗時的任務,給用戶帶來良好用戶體驗的,從編程的語法上顯得優雅了許多,不再需要子線程和Handler就可以完成異步操作並且刷新用戶界面。

10.說說mvc模式的原理,它在android中的運用 
答:android的官方建議應用程序的開發采用mvc模式。何謂mvc? 
 mvc是model,view,controller的縮寫,mvc包含三個部分: 
  l、模型(model)對象:是應用程序的主體部分,所有的業務邏輯都應該寫在該層。 
  2、視圖(view)對象:是應用程序中負責生成用戶界面的部分。也是在整個mvc架構中用戶唯一可以看到的一層,接收用戶的輸入,顯示處理結果。 
  3、控制器(control)對象:是根據用戶的輸入,控制用戶界面數據顯示及更新model對象狀態的部分,控制器更重要的一種導航功能,想用用戶出發的相關事件,交給m處理。 
 android鼓勵弱耦合和組件的重用,在android中mvc的具體體現如下: 
1)視圖層(view):一般采用xml文件進行界面的描述,使用的時候可以非常方便的引入,當然,如何你對android了解的比較的多了話,就一定 可以想到在android中也可以使用JavaScript+html等的方式作為view層,當然這里需要進行java和javascript之間的通 信,幸運的是,android提供了它們之間非常方便的通信實現。 
 2)控制層(controller):android的控制層的重 任通常落在了眾多的acitvity的肩上,這句話也就暗含了不要在acitivity中寫代碼,要通過activity交割model業務邏輯層處理, 這樣做的另外一個原因是android中的acitivity的響應時間是5s,如果耗時的操作放在這里,程序就很容易被回收掉。 
 3)模型層(model):對數據庫的操作、對網絡等的操作都應該在model里面處理,當然對業務計算等操作也是必須放在的該層的。 
  
 11.根據自己的理解描述下Android數字簽名。 
答:(1)所有的應用程序都必須有數字證書,Android系統不會安裝一個沒有數字證書的應用程序 
(2)Android程序包使用的數字證書可以是自簽名的,不需要一個權威的數字證書機構簽名認證 
(3)如果要正式發布一個Android ,必須使用一個合適的私鑰生成的數字證書來給程序簽名,而不能使用adt插件或者ant工具生成的調試證書來發布。 
(4)數字證書都是有有效期的,Android只是在應用程序安裝的時候才會檢查證書的有效期。如果程序已經安裝在系統中,即使證書過期也不會影響程序的正常功能

12. 談談對 Android NDK 的理解 
NDK 全稱:Native Development Kit。 
1、NDK 是一系列工具的集合。 * NDK 提供了一系列的工具,幫助開發者快速開發 C(或 C++)的動態庫,並能自動將 so 和 java 應用 
一起打包成 apk。這些工具對開發者的幫助是巨大的。 * NDK 集成了交叉編譯器,並提供了相應的 mk 文件隔離 CPU、平台、ABI 等差異,開發人員只需要簡單修改 mk 文件(指出“哪些文件需要編譯”、“編譯特性要求”等) ,就可以創建出 so。 * NDK 可以自動地將 
so 和 Java 應用一起打包,極大地減輕了開發人員的打包工作。 
2、NDK 提供了一份穩定、功能有限的 API 頭文件聲明。 Google 明確聲明該 API 是穩定的,在后續所有版本中都穩定支持當前發布的 API。從該版本的 NDK 中看出,這些 API 支持的功能非常有限, 
包含有:C 標准庫(libc) 、標准數學庫(libm) 、壓縮庫(libz) 、Log 庫(liblog) 。

13.ViewStub的應用 
在開發應用程序的時候,經常會遇到這樣的情況,會在運行時動態根據條件來決定顯示哪個View或某個布局。那么最通常的想法就是把可能用到的View都寫在上面,先把它們的可見性都設為View.GONE,然后在代碼中動態的更改它的可見性。這樣的做法的優點是邏輯簡單而且控制起來比較靈活。但是它的缺點就是,耗費資源。雖然把View的初始可見View.GONE但是在Inflate布局的時候View仍然會被Inflate,也就是說仍然會創建對象,會被實例化,會被設置屬性。也就是說,會耗費內存等資源。 
推薦的做法是使用android.view.ViewStub,ViewStub是一個輕量級的View,它一個看不見的,不占布局位置,占用資源非常小的控件。可以為ViewStub指定一個布局,在Inflate布局的時候,只有ViewStub會被初始化,然后當ViewStub被設置為可見的時候,或是調用了ViewStub.inflate()的時候,ViewStub所向的布局就會被Inflate和實例化,然后ViewStub的布局屬性都會傳給它所指向的布局。這樣,就可以使用ViewStub來方便的在運行時,要還是不要顯示某個布局。 
但ViewStub也不是萬能的,下面總結下ViewStub能做的事兒和什么時候該用ViewStub,什么時候該用可見性的控制。 
首先來說說ViewStub的一些特點: 
1. ViewStub只能Inflate一次,之后ViewStub對象會被置為空。按句話說,某個被ViewStub指定的布局被Inflate后,就不會夠再通過ViewStub來控制它了。 
2. ViewStub只能用來Inflate一個布局文件,而不是某個具體的View,當然也可以把View寫在某個布局文件中。 
基於以上的特點,那么可以考慮使用ViewStub的情況有: 
1. 在程序的運行期間,某個布局在Inflate后,就不會有變化,除非重新啟動。 
因為ViewStub只能Inflate一次,之后會被置空,所以無法指望后面接着使用ViewStub來控制布局。所以當需要在運行時不止一次的顯示和隱藏某個布局,那么ViewStub是做不到的。這時就只能使用View的可見性來控制了。 
2. 想要控制顯示與隱藏的是一個布局文件,而非某個View。 
因為設置給ViewStub的只能是某個布局文件的Id,所以無法讓它來控制某個View。 
所以,如果想要控制某個View(如Button或TextView)的顯示與隱藏,或者想要在運行時不斷的顯示與隱藏某個布局或View,只能使用View的可見性來控制。

 
11
2


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM