android程式設計師面試寶典

zhuxingchong發表於2017-12-11


    以下問題對做android的都一個自我檢測和反饋的功能,其中有很多問題

可以自我擴充套件和補充。



1.AsyncTask應用場景,優點,缺點?

AsyncTask 運用的場景就是我們需要進行一些耗時的操作,耗時操作完成後更新主執行緒,或者在操作過程中對主執行緒的UI進行更新。

缺陷:AsyncTask中維護著一個長度為128的執行緒池,同時可以執行5個工作執行緒,還有一個緩衝佇列,當執行緒池中已有128個執行緒,緩衝佇列已滿時,如果此時向執行緒提交任務,將會丟擲Reject

解決:由一個控制執行緒來處理AsyncTask的呼叫判斷執行緒池是否滿了,如果滿了則執行緒睡眠否則請求AsyncTask繼續處理。


2.activity四種啟模式

1,standard標準模式:
每次啟動一個Activity都會重新建立一個例項,即呼叫Activity建立時的生命週期方法onCreate,onStart,onResume;被啟動的Activity會自動新增到啟動它的Activity的任務棧中,因此用ApplicationContext啟動standard模式的Activity時會報錯(Context沒有所謂的任務棧)
2,singleTop棧頂複用模式:
新啟動的Activity已經位於任務棧的棧頂,那麼此Activity將不會被重建,而是會回撥其onNewIntent方法,如果新啟動的Activity不是位於棧頂,此時將重新建立新的Activity例項並新增到棧頂.
3,singleTask棧內複用模式:
這是一種簡單的單例模式,這種模式下只要被啟動的Activity位於棧內,那麼無論它是否位於棧頂都不會重新建立新的Activity例項,而是直接將其調回到棧頂並回撥其onNewIntent方法,如果在其上有其他Activity的時候會將這些Activity進行出棧處理
4,singleInstance單例項模式:
這是一種加強的singleTask模式,除了具有singleTask的特點外還加了一點,具體此模式的Activity會單獨位於一個獨立的任務棧,如ActivityA為singleInstance啟動模式,當A啟動後,系統會單獨為其建一個任務棧,A將獨自位於這個任務棧中,以後的請求均不會建立新的Activity直至這個任務棧被銷燬.

點選開啟連結


3.如何避免 OOM 異常

首先OOM是什麼?

當程式需要申請一段“大”記憶體,但是虛擬機器沒有辦法及時的給到,即使做了GC操作以後

這就會丟擲 OutOfMemoryException 也就是OOM

Android的OOM怎麼樣?

為了減少單個APP對整個系統的影響,android為每個app設定了一個記憶體上限。

public void getMemoryLimited(Activity context)

    {

        ActivityManager activityManager =(ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);

 System.out.println(activityManager.getMemoryClass());

System.out.println(activityManager.getLargeMemoryClass());  System.out.println(Runtime.getRuntime().maxMemory()/(1024*1024));

    }

通過這段程式碼程式執行我們可以獲取到當前APP的記憶體上限

如何避免OOM

減少記憶體物件的佔用

I.ArrayMap/SparseArray代替hashmap

II.避免在android裡面使用Enum

III.減少bitmap的記憶體佔用

inSampleSize:縮放比例,在把圖片載入記憶體之前,我們需要先計算出一個合適的縮放比例,避免不必要的大圖載入。

decode format:解碼格式,選擇ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,存在很大差異。

IV.減少資源圖片的大小,過大的圖片可以考慮分段載入

記憶體物件的重複利用

大多數物件的複用,都是利用物件池的技術。

I.listview/gridview/recycleview contentview的複用

II.inBitmap 屬性對於記憶體物件的複用ARGB_8888/RBG_565/ARGB_4444/ALPHA_8

這個方法在某些條件下非常有用,比如要載入上千張圖片的時候。

III.避免在ondraw方法裡面 new物件

IV.StringBuilder 代替+



4.Framework 工作方式及原理,Activity 是如何生成一個 view 的,機制是什麼


Framework是android 系統對 linux kernel,lib庫等封裝,提供WMS,AMS,bind機制,handler-message機制等方式,供app使用。

簡單來說framework就是提供app生存的環境。

1)Activity在attch方法的時候,會建立一個phonewindow(window的子類)

2)onCreate中的setContentView方法,會建立DecorView

3)DecorView 的addview方法,會把layout中的佈局載入進來。


5.記憶體溢位和記憶體洩漏有什麼區別?何時會產生記憶體洩漏?記憶體優化有哪些方法?

記憶體溢位通俗理解就是軟體(應用)執行需要的記憶體,超出了它可用的最大記憶體。

記憶體洩漏就是我們對某一記憶體空間的使用,使用完成後沒有釋放。

記憶體優化:Android中容易記憶體溢位的部分,就是圖片的載入,我們可以使用圖片的壓縮加上使用LruCache快取的目的來控制圖片所能夠使用的記憶體。

還有對於比較耗資源的物件及時的關閉,例如Database Conn , 各種感測器 , Service 等等。


6.ListView的優化方案

1、如果自定義介面卡,那麼在getView方法中要考慮方法傳進來的引數contentView是否為null,如果為null就建立contentView並返回,如果不為null則直接使用。在這個方法中儘可能少建立view。

2、給contentView設定tag(setTag()),傳入一個viewHolder物件,用於快取要顯示的資料,可以達到影象資料非同步載入的效果。

3、如果listview需要顯示的item很多,就要考慮分頁載入。比如一共要顯示100條或者更多的時候,我們可以考慮先載入20條,等使用者拉到列表底部的時候再去載入接下來的20條。


7.說說mvc模式的原理,它在android中的運用,android的官方建議應用程式的開發採用mvc模式。何謂mvc?

mvc是model,view,controller的縮寫,mvc包含三個部分:

模型(model)物件:是應用程式的主體部分,所有的業務邏輯都應該寫在該層。

檢視(view)物件:是應用程式中負責生成使用者介面的部分。也是在整個mvc架構中使用者唯一可以看到的一層,接收使用者的輸入,顯示處理結果。

控制器(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裡面處理,當然對業務計算等操作也是必須放在的該層的。



8.描述一下android的系統架構


android系統架構分從下往上為linux 核心層、執行庫、應用程式框架層、和應用程式層。

linuxkernel:負責硬體的驅動程式、網路、電源、系統安全以及記憶體管理等功能。

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

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

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

上面的四個層次,下層為上層服務,上層需要下層的支援,呼叫下層的服務,這種嚴格分層的方式帶來的極大的穩定性、靈活性和可擴充套件性,使得不同層的開發人員可以按照規範專心特定層的開發。

android應用程式使用框架的api並在框架下執行,這就帶來了程式開發的高度一致性,另一方面也告訴我們,要想寫出優質高效的程式就必須對整個 applicationframework進行非常深入的理解。精通applicationframework,你就可以真正的理解android的設計和執行機制,也就更能夠駕馭整個應用層的開發。



9.Service和Thread的區別?

servie是系統的元件,它由系統程式託管(servicemanager);它們之間的通訊類似於client和server,是一種輕量級的ipc通訊,這種通訊的載體是binder,它是在linux層交換資訊的一種ipc。而thread是由本應用程式託管。1). Thread:Thread 是程式執行的最小單元,它是分配CPU的基本單位。可以用 Thread 來執行一些非同步的操作。

2). Service:Service 是android的一種機制,當它執行的時候如果是Local Service,那麼對應的 Service 是執行在主程式的 main 執行緒上的。如:onCreate,onStart 這些函式在被系統呼叫的時候都是在主程式的 main 執行緒上執行的。如果是Remote Service,那麼對應的 Service 則是執行在獨立程式的 main 執行緒上。

既然這樣,那麼我們為什麼要用 Service 呢?其實這跟 android 的系統機制有關,我們先拿 Thread 來說。Thread 的執行是獨立於 Activity 的,也就是說當一個 Activity 被 finish 之後,如果你沒有主動停止 Thread 或者 Thread 裡的 run 方法沒有執行完畢的話,Thread 也會一直執行。因此這裡會出現一個問題:當 Activity 被 finish 之後,你不再持有該 Thread 的引用。另一方面,你沒有辦法在不同的 Activity 中對同一 Thread 進行控制。 

舉個例子:如果你的 Thread 需要不停地隔一段時間就要連線伺服器做某種同步的話,該 Thread 需要在 Activity 沒有start的時候也在執行。這個時候當你 start 一個 Activity 就沒有辦法在該 Activity 裡面控制之前建立的 Thread。因此你便需要建立並啟動一個 Service ,在 Service 裡面建立、執行並控制該 Thread,這樣便解決了該問題(因為任何 Activity 都可以控制同一 Service,而系統也只會建立一個對應 Service 的例項)。 

因此你可以把 Service 想象成一種訊息服務,而你可以在任何有 Context 的地方呼叫 Context.startService、Context.stopService、Context.bindService,Context.unbindService,來控制它,你也可以在 Service 裡註冊 BroadcastReceiver,在其他地方通過傳送 broadcast 來控制它,當然這些都是 Thread 做不到的。



10.有沒有用過自定義View?

 有用過,一般指定View都需要進行這幾個步驟,首先可以自定義一些自己的屬性,在resalues/attrs.xml裡面定義,然後在layout中使用,在View中通過context.obtainStyledAttributes(attrs,R.styleable.自定義屬性的名字)進行獲取。
然後在測量onMeasure,一般通過他的三個模式(EXACTLY,AT_MODE,,UNSPECIFIED)進行測量,呼叫setMeasuredDimension進行傳入設定的值。
接著如果是ViewGroupt 的話我們還需要設定下子View的位置,一般是通過requestLayout去觸發onLayout的方法的。
最後在onDraw裡面通過Canvas的一些方法進行繪製。
如果需要進行觸控事件的話,一般需要有實現onTouchEvent事件,注意,如果需要多點觸控,需要實現ACTION_POINTER_DOWN和ACTION_POINTER_UP進行處理。


11.使用Handler的時候一般會遇到什麼問題?

比如說子執行緒更新UI,是因為觸發了checkThread方法檢查是否在主執行緒更新UI,還有就是子執行緒中沒有Looper,這個原因是因為Handler的機制引起的,因為Handler傳送Message的時候,需要將Message放到MessageQueue裡面,而這個時候如果沒有Looper的話,就無法迴圈輸出MessageQueue了,這個時候就會報Looper為空的錯誤。


12.怎麼在主執行緒中通知子執行緒?這樣做有什麼好處?

可以利用HandlerThread進行生成一個子執行緒的Handler,並且實現handlerMessage方法,然後在主執行緒裡面也生成一個Handler,然後通過呼叫sendMessage方法進行通知子執行緒。同樣,子執行緒裡面也可以呼叫sendMessage方法進行通知主執行緒。這樣做的好處比如有些圖片的載入啊,網路的訪問啊可能會比較耗時,所以放到子執行緒裡面做是比較合適的。


13.非同步處理有幾種方式?

可以採用Handler的形式,利用官方提供的HandlerThread類進行宣告一個子執行緒的Handler,然後在Handler裡面就可以做耗時的操作了,注意,需要在子執行緒中提前準備好Looper物件,可以使用Looper.prepare方法,最後需要使用Looper.loop方法進行迴圈。還可以直接用AsyncTask進行操作,一般會建構函式有三個引數,一個是傳入引數,一個是進度,還有一個是結果,然後一般會實現一些方法,比如:execute用來用來執行一個非同步任務,就是實現的AsyncTask的類呼叫的,還有onPreExecute,就是呼叫後立即執行,doInBackground,在onPreExecute完成後立即執行,用於執行較為費時的操作,此方法將接收輸入引數和返回計算結果。onProgressUpdate,可以直接將進度資訊更新到UI介面上。onPostExecute,後臺結束時候呼叫的方法,會返回結果。注意,不能執行多次,不然會報錯,且必須在UI執行緒中呼叫,至於上面提到的方法都不要手動呼叫。doInBackground方法中不可以更新UI。

(因為Android3.0以後必須要求網路訪問在子執行緒中,不然會拋NetworkOnMainThreadException異常,嘗試ANR現象(5秒不響應現象))


14.Fragment的生命週期是怎麼樣的,跟Activity有什麼關係?

Fragment是Activity的一個元件片段,也就是說他的生命週期是依賴於Activity的,但是它比Activity多了幾個生命步驟,首先onAttach當fragment加入Activity的時候呼叫,然後是onCreate進行啟動Activity,接著是onCreateView進行繪製View,一般的View就是這裡繪製的,然後是onActivityCreated,接著跟Activity的生命週期差不多,呼叫onStart和onResume,然後是onPause,onStop,如果這個時候需要回收Fragment的時候,就會呼叫,接著是onDestoryView銷燬佈局,然後是onDestory和onDetach完成。


15.為什麼在Service中建立子執行緒而不是Activity中?

因為假如在Activity中建立子執行緒的話,當Activity銷燬的時候,這個時候重新再呼叫該Activity就會重新走新的生命週期,這個時候就無法再重新獲取到剛才的子執行緒,而且如果在一個Activity中建立子執行緒,另一個Activity也無法操作該子執行緒,但是Service就不一樣,所有的Activity都可以和Service關聯,即使是Activity被銷燬了,只要再重新建立聯絡就好了,所以,一般後臺任務都是通過Service去控制的。


16.如何解決應用被強制殺死?

如果在每一個Activity的onCreate裡判斷是否被強殺,冗餘了,封裝到Activity的父類中,如果被強殺,跳轉回主介面,如果沒有被強殺,執行Activity的初始化操作,給主介面傳遞intent引數,主介面會呼叫onNewIntent方法,在onNewIntent跳轉到歡迎頁面,重新來一遍流程。


17.Android怎麼優化啟動速度?

因為Android啟動應用程式一般分為兩種,一種是冷啟動,就是要啟動的應用程式沒有後臺程式的啟動,這個時候需要重新分配一個程式給他,所以這個時候會先初始化Application類,再建立和初始化MainAcitvity 類,最後顯示到介面上,還有一種是熱啟動,就是後臺還有該應用的程式,比如說按下的home鍵或者返回鍵,雖然表面上退出了,但是在任務棧裡面仍然還存在的,這個時候就不需要再初始化Application類了,只要重新初始化MainActivity了。因為大多數應用的啟動都是冷啟動(使用者習慣將應用程式在任務棧中刪除),所以這個時候可以採取這幾個步驟,比如儘量不在Application的構造器,attachBaseContext方法和onCreaete方法中做過多的耗時操作,將一些資料預取放在非同步執行緒中,可以採Callback的方式。優化MainActivity,儘量不要在MainActivity的onCreate,onStart和onResume等方法裡面做過多的耗時操作。


18.Android怎麼加快Activity的顯示速度?

首先因為Activiy的顯示是在這幾個生命週期之間的,onCreate,onStart,和onResume,這個時候我們需要將我們需要初始化的資料分類,比如說我們將一些只需要初始化的一次的資料放到onCreate中,儘量不要在onCreate中做耗時的操作,然後將需要載入比較長時間的資料放到onResume中,可以利用handler的機制進行更新UI,或者放到AsyncTask逐個顯示,然後可以設定一些動畫進行顯示,如果這個時候有許多資料都是一次顯示的, 那麼可以在onCreate裡面進行標記,並且在onResume裡面判斷是否需要初始化,初始化完成以後就立刻false掉,這樣就可以避免多次初始化了,也可以提升Activity的顯示速度。


19.如何理解Activity,View,Window三者之間的關係?

這個問題真的很不好回答。所以這裡先來個算是比較恰當的比喻來形容下它們的關係吧。Activity像一個工匠(控制單元),Window像窗戶(承載模型),View像窗花(顯示檢視)LayoutInflater像剪刀,Xml配置像窗花圖紙。


1:Activity構造的時候會初始化一個Window,準確的說是PhoneWindow。

2:這個PhoneWindow有一個“ViewRoot”,這個“ViewRoot”是一個View或者說ViewGroup,是最初始的根檢視。

3:“ViewRoot”通過addView方法來一個個的新增View。比如TextView,Button等

4:這些View的事件監聽,是由WindowManagerService來接受訊息,並且回撥Activity函式。比如onClickListener,onKeyDown等。


20.Touch事件的傳遞機制 

publicbooleandispatchTouchEvent(MotionEventev);  //用來分派event

publicbooleanonInterceptTouchEvent(MotionEventev);//用來攔截event

publicbooleanonTouchEvent(MotionEventev);//用來處理event


其中Activity和View控制元件(TextView)擁有分派和處理事件方法,View容器(LinearLayout)具有分派,攔截,處理事件方法。這裡也有個比喻:領導都會把任務向下分派,一旦下面的人把事情做不好,就不會再把後續的任務交給下面的人來做了,只能自己親自做,如果自己也做不了,就只能告訴上級不能完成任務,上級又會重複他的過程。另外,領導都有權利攔截任務,對下級隱瞞該任務,而直接自己去做,如果做不成,也只能向上級報告不能完成任務。



21.view如何重新整理?簡述什麼是雙緩衝?


android中實現view的重新整理有兩個方法,一個是invalidate(),另一個是postInvalidate(),其中前者是在UI執行緒自身中使用,而後者在非UI執行緒中使用。

出現螢幕閃爍是圖形程式設計的一個常見問題。當進行復雜的繪製操作時會導致呈現的影象閃爍或具有其他不可接受的外觀。雙緩衝的使用解決這些問題。雙緩衝使用記憶體緩衝區來解決由多重繪製操作造成的閃爍問題。當使用雙緩衝時,首先在記憶體緩衝區裡完成所有繪製操作,而不是在螢幕上直接進行繪圖。當所有繪製操作完成後,把記憶體緩衝區完成的影象直接複製到螢幕。因為在螢幕上只執行一個圖形操作,所以消除了由複雜繪製操作造成的影象閃爍問題。

在android中實現雙緩衝,可以使用一個後臺畫布backcanvas,先把所有繪製操作都在這上面進行。等圖畫好了,然後在把backcanvas拷貝到

與螢幕關聯的canvas上去,如下:

Canvas backcanvas = new Canvas(bitmapBase)

backcanvas.draw()...//畫圖

Canvas c = lockCanvas(null);

c.drawbitmap(bitmapBase);//把已經畫好的影象輸出到螢幕上

unlock(c)....



22.談談Android的IPC(程式間通訊)機制


IPC 是內部程式通訊的簡稱,是共享”命名管道”的資源。Android 中的 IPC 機制是為了

讓 Activity 和 Service 之間可以隨時的進行互動,故在 Android 中該機制,只適用於 Activity和 Service 之間的通訊,類似於遠端方法呼叫,類似於 C/S 模式的訪問。通過定義 AIDL 介面檔案來定義 IPC 介面。Servier 端實現 IPC 介面,Client 端呼叫 IPC 介面本地代理。



23.try catch finally的執行順序

try { //執行的程式碼,其中可能有異常。一旦發現異常,則立即跳到catch執行。否則不會執行catch裡面的內容 }

catch { //除非try裡面執行程式碼發生了異常,否則這裡的程式碼不會執行 }

finally { //不管什麼情況都會執行,包括try catch 裡面用了return ,可以理解為只要執行了try或者catch,就一定會執行 finally


24.Anr發生原則,發生原因,和避免方法?

1.發生原則

1.只有主執行緒才會產生ANR,主執行緒就是UI執行緒;

2.必須發生某些輸入事件或特定操作,比如按鍵或觸屏等輸入事件,在BroadcastReceiverService的各個生命週期呼叫函式;

3.上述事件響應超時,不同的context規定的上限時間不同

    a.主執行緒對輸入事件5秒內沒有處理完畢

    b.主執行緒在執行BroadcastReceiveronReceive()函式時10秒內沒有處理完畢

    c.主執行緒在Service的各個生命週期函式時20秒內沒有處理完畢。

那麼導致ANR的根本原因是什麼呢?

1.主執行緒執行了耗時操作,比如資料庫操作或網路程式設計

2.其他程式(就是其他程式)佔用CPU導致本程式得不到CPU時間片,比如其他程式的頻繁讀寫操作可能會導致這個問題。

2.導致ANR的原因有如下幾點:

1.耗時的網路訪問

2.大量的資料讀寫

3.資料庫操作

4.呼叫threadjoin()方法、sleep()方法、wait()方法或者等待執行緒鎖的時候

5.service binder的數量達到上限

6.system server中發生WatchDog ANR

7.service忙導致超時無響應

8.其他執行緒持有鎖,導致主執行緒等待超時

9.其它執行緒終止或崩潰導致主執行緒一直等待

3.那麼如何避免ANR的發生呢或者說ANR的解決辦法是什麼呢?

1.避免在主執行緒執行耗時操作,所有耗時操作應新開一個子執行緒完成,然後再在主執行緒更新UI



相關文章