1. 程式人生 > >Android面試(一)

Android面試(一)

說明

最近由於自己換了一份工作,這時就有一些小夥伴問我Android的面試會問什麼,這次就先給大家展示一下一些簡單的Android面試題吧,以後會持續更新,希望對有需要的朋友有幫助。

面試題

sp操作apply和commit的區別:

1. apply沒有返回值而commit返回boolean表明修改是否提交成功 
2. apply是將修改資料原子提交到記憶體, 而後非同步真正提交到硬體磁碟, 
   而commit是同步的提交到硬體磁碟,因此,在多個併發的提交commit的時候,他們會等待正在處理的commit儲存到磁碟後在操作,從而降低了效率。
   而apply只是原子的提交到記憶體,後面有呼叫apply的函式的將會直接覆蓋前面的記憶體資料,這樣從一定程度上提高了很多效率。 
3. apply方法不會提示任何失敗的提示。 
   由於在一個程序中,sharedPreference是單例項,一般不會出現併發衝突,如果對提交的結果不關心的話,建議使用apply,當然需要確保提交成功且有後續操作的話,還是需要用commit的。

Activity和Fragment生命週期:
Activity: onCreate(), onStart(), onResume(), onPause(), onStop(), onDestory(),
Fragment: onAttach(), onCreate(), onCreateView(), onActivityCreated(), onStart(), onResume(), onPause(), onStop(), onDestoryView(), onDestory(), onDetach()

兩個Activity的跳轉執行的方法:
一般情況比如說有兩個activity,分別叫A,B ,當在A裡面啟用B元件的時候, A 會呼叫 onPause()方法,然後B 呼叫onCreate() ,onStart(), OnResume() ,
這個時候B覆蓋了窗體, A會呼叫onStop()方法. 如果B呢 是個透明的,或者是對話方塊的樣式, 就不會呼叫onStop()方法.

橫豎屏切換:
設定 Activity 的 android:configChanges=”orientation|keyboardHidden|screenSize”時,切屏不會重新呼叫各個生命週期,只會執行 onConfigurationChanged 方法

Activity啟動模式(singleTask, singleInstance, singleTop, standard)
Standard: 不管有沒有已存在的例項,都生成新的例項。
SingleTop:如果發現有對應的 Activity 例項正位於棧頂,則重複利用,不再生成新的例項。不是位於棧頂,於是重新生成一個例項。
SingleTask:如果發現有對應的 Activity 例項,則使此 Activity 例項之上的其他 Activity 例項統統出棧,使此 Activity 例項成為棧頂物件,顯示到幕前。
SingleInstance:它會啟用一個新的棧結構,將 Activity 放置於這個新的棧結構中,並保證不再有其他 Activity 例項進入。

一個啟動模式為 singleTop 的 activity,如果再試圖啟動會怎樣
onNewIntent()
該方法被啟動模式設定為“singleTop”的 Activity 回撥,或者當通過設定 Intent.FLAG_ACTIVITY_SINGLE_TOP
的 Intent 啟動 Activity 時被回撥。在任何情況下,只要當棧頂的 Activity 被重新啟動時沒有重新建立一個新的 Activity
例項而是依然使用該 Activity 物件,那麼 onNewIntent(Intent)方法就會被回撥。
當一個 Activity 接收到新 Intent 的時候會處於暫停狀態,因此你可以統計到 onResume()方法會被再次執行,當然這個執行是在 onNewIntent 之後的。
注意:如果我們在 Activity 中呼叫了 getIntent()方法,那麼返回的 Intent 物件還是老的 Intent(也就是第一
次啟動該 Activity 時的傳入的 Intent 物件),但是如果想讓 getIntent()返回最新的 Intent,那麼我們可以通過setIntent(Intent)方法設定。

FragmentPagerAdapter和FragmentStatePagerAdapter:
FragmentPagerAdapter:對於不再需要的fragment,選擇呼叫detach方法,僅銷燬檢視,並不會銷燬fragment例項。
FragmentStatePagerAdapter:會銷燬不再需要的fragment,噹噹前事務提交以後,會徹底的將fragmeng從當前Activity的FragmentManager中移除,state標明,
銷燬時,會將其onSaveInstanceState(Bundle outState)中的bundle資訊儲存下來,當用戶切換回來,可以通過該bundle恢復生成新的fragment,也就是說,你可以在onSaveInstanceState(Bundle outState)方法中儲存一些資料,在onCreate中進行恢復建立。
如上所說,使用FragmentStatePagerAdapter當然更省記憶體,但是銷燬新建也是需要時間的。
一般情況下,如果你是製作主頁面,就3、4個Tab,那麼可以選擇使用FragmentPagerAdapter,
如果你是用於ViewPager展示數量特別多的條目時,那麼建議使用FragmentStatePagerAdapter。

廣播的註冊?方式(靜態和動態)有什麼區別:
(1)動態註冊廣播不是常駐型廣播,也就是說廣播跟隨Activity的生命週期。注意在Activity結束前,移除廣播接收器。
靜態註冊是常駐型,也就是說當應用程式關閉後,如果有資訊廣播來,程式也會被系統呼叫自動執行。
(2)當廣播為有序廣播時:優先順序高的先接收(不分靜態和動態)。同優先順序的廣播接收器,動態優先於靜態
(3)同優先順序的同類廣播接收器,靜態:先掃描的優先於後掃描的,動態:先註冊的優先於後註冊的。
(4)當廣播為預設廣播時:無視優先順序,動態廣播接收器優先於靜態廣播接收器。同優先順序的同類廣播接收器,靜態:先掃描的優先於後掃描的,動態:先註冊的優先於後冊的。

多程序的缺點及改進方法:
缺點:1. Application多次建立 ; 2. 靜態成員,全域性變數,單例會失效 ;3. 共享檔案的問題; 4.斷點除錯問題
改進方法: 在onCreate()的時候判斷程序ID來建立;利用Intent、AIDL等來通訊; 主程訪問; 迴歸統一程序除錯在改回來。

自定義控制元件的步驟 (onLayout,onMeasure,onTouchEvent)
measure(widthMeasureSpec,heightMeasureSpec)———>onMeasure(widthMeasureSpec,heightMeasureSpec)
* MeasureSpec:父控制元件對子View的測量寬高的期望———>一個32位的數,前兩位表示測量模式——SpecModel;後30位表示測量大小SpecSize。
* SpecModel測量模式有三種:1、Exactly,精確的,有300px,match_parent。2、AtMost,最大是多少,有wrap_content。3、Unspecfide,無限大。
* 測量結束後能獲取測量的寬和測量的高,也就是widthSpecSize和heightSpecSize。通過getMeasureWidth和getMeasureHeight方法。
* 代表測量結束的方法setMeasureDimetion(widthSpecSize,heightSpecSize)。
* 自定義ViewGroup一定要重寫onMeasure方法,如果不重寫則子View獲取不到寬和高。重寫是在onMeasure方法中呼叫measureChildern()方法,遍歷出所有子View並對其進行測量。
* 自定義View如果要使用wrap_content屬性的話,則需重寫onMeasure方法。
layout(l,t,r,b)——->onLayout(l,t,r,b)。
* 該方法其實是指定控制元件擺放的位置。
* 自定義View一般不重寫onLayout方法。由父控制元件給其確定位置。
* 自定義ViewGroup需要重寫onLayout方法,要不然子控制元件不知道擺放在哪。
* layout方法中呼叫了setFram(l,t,r,b)方法。該方法內部的實現{mLeft = l;mRight = r;mTop = t;mBottom = b};該方法代表佈局完成。
* 佈局完成之後,能夠獲取getWidth()和getHeight()的值。這兩個方法的實現分別是return mRight - mLeft; return mBottom - mTop;
draw(Canvas canvas)。
* 一共有六步
* 1. 繪製背景
* 2. If necessary, save the canvas’ layers to prepare for fading
* 3. 繪製View的內容, 在onDraw(canvas)方法中完成
* 4. 繪製子View的內容 ,dispatchDraw。
* 5. If necessary, draw the fading edges and restore layers
* 6. 繪製裝飾品(如滾動條)

Handle機制
這裡面除了 Handler、Message 外還有隱藏的 Looper 和 MessageQueue 物件。
在主執行緒中 Android 預設已經呼叫了 Looper.preper()方法,呼叫該方法的目的是在 Looper 中建立
MessageQueue 成員變數並把 Looper 物件繫結到當前執行緒中。當呼叫 Handler 的 sendMessage(物件)方法的時候就將 Message 物件新增到了 Looper 建立的 MessageQueue 佇列中,
同時給 Message 指定了 target 物件,其實這個 target 物件就是 Handler 物件。主執行緒預設執行了 Looper.looper()方法,該方法從 Looper 的成員變數
MessageQueue 中取出 Message,然後呼叫 Message 的 target 物件的 handleMessage()方法。這樣就完成了整個訊息機制。

為什麼我們看不見messageQueue,Looper。
* 主執行緒給我們準備了Looper物件。
* 在Looper的建構函式裡面生成了messageQueue物件。
* 主執行緒中的Looper物件存放在哪裡?—–>ThreadLocal的values裡面。
怎麼樣來實現主執行緒向子執行緒發訊息和子執行緒之間發訊息?
* 在子執行緒new Handler然後在主執行緒發訊息,在子執行緒處理訊息。
* 會報錯,因為子執行緒沒有Looper物件,所以不能new Handler,呼叫Looper.prepare方法,生成Looper。
怎麼樣來確保傳送訊息和接收訊息的Handler是同一個handler。
* message的target屬性就是handler。

view層級優化(merge,ViewStub,include)
1:標籤在佈局優化中是使用最多的一個標籤了,它就是為了解決重複定義佈局的問題。如果想使用標籤覆蓋嵌入佈局root佈局屬性,必須同時覆蓋layout_height和layout_width屬性,否則會直接報編譯時語法錯誤
2:標籤都是與標籤組合使用的,它的作用就是可以有效減少View樹的層次來優化佈局。
對比截圖就可以發現上面的四層結構,現在已經是三層結構了。當我們使用標籤的時候,系統會自動忽略merge層級,而把TextView直接放置與平級。
標籤在使用的時候需要特別注意佈局的型別,例如我的標籤中包含的是一個LinearLayout佈局檢視,佈局中的元素是線性排列的,如果巢狀進主佈局時,include標籤父佈局時FrameLayout,這種方式巢狀肯定會出問題的,merge中元素會按照FrameLayout佈局方式顯示。所以在使用的時候,標籤雖然可以減少佈局層級,但是它的限制也不可小覷。
只能作為XML佈局的根標籤使用。當Inflate以開頭的佈局檔案時,必須指定一個父ViewGroup,並且必須設定attachToRoot為true。
View android.view.LayoutInflater.inflate(int resource, ViewGroup root, boolean attachToRoot)
root不可少,attachToRoot必須為true。
3:在開發過程中,經常會遇到這樣一種情況,有些佈局很複雜但是卻很少使用。例如條目詳情、進度條標識或者未讀訊息等,這些情況如果在一開始初始化,雖然設定可見性View.GONE,但是在Inflate的時候View仍然會被Inflate,仍然會建立物件,由於這些佈局又想到複雜,所以會很消耗系統資源。
ViewStub就是為了解決上面問題的,ViewStub是一個輕量級的View,它一個看不見的,不佔佈局位置,佔用資源非常小的控制元件。

SurfaceView
SurfaceView是View類的子類,可以直接從記憶體或者DMA等硬體介面取得影象資料,是個非常重要的繪圖檢視。它的特性是:可以在主執行緒之外的執行緒中向螢幕繪圖上。這樣可以避免畫圖任務繁重的時候造成主執行緒阻塞,從而提高了程式的反應速度。在遊戲開發中多用到SurfaceView,遊戲中的背景、人物、動畫等等儘量在畫布canvas中畫出。
繼承SurfaceView並實現SurfaceHolder.Callback介面 —-> SurfaceView.getHolder()獲得SurfaceHolder物件 —->SurfaceHolder.addCallback(callback)添加回調函式—->SurfaceHolder.lockCanvas()獲得Canvas物件並鎖定畫布—-> Canvas繪畫 —->SurfaceHolder.unlockCanvasAndPost(Canvas canvas)結束鎖定畫圖,並提交改變,將圖形顯示。

anroid提供的網路接?瞭解(HttpClient, HttpURLConnection)
在Android 2.2版本之前,HttpClient擁有較少的bug,因此使用它是最好的選擇。
而在Android 2.3版本及以後,HttpURLConnection則是最佳的選擇。
它的API簡單,體積較小,因而非常適用於Android專案。壓縮和快取機制可以有效地減少網路訪問的流量,在提升速度和省電方面也起到了較大的作用。
對於新的應用程式應該更加偏向於使用HttpURLConnection,因為在以後的工作當中我們也會將更多的時間放在優化HttpURLConnection上面。
1.HttpClient是apache的開源實現,而HttpUrlConnection是安卓標準實現,安卓SDK雖然集成了HttpClient,但官方支援的卻是HttpUrlConnection;
2.HttpUrlConnection直接支援GZIP壓縮;HttpClient也支援,但要自己寫程式碼處理;我們之前測試HttpUrlConnection的GZIP壓縮在傳大檔案分包trunk時有問題,只適合小檔案,不過這個BUG後來官方說已經修復了;
3.HttpUrlConnection直接支援系統級連線池,即開啟的連線不會直接關閉,在一段時間內所有程式可共用;HttpClient當然也能做到,但畢竟不如官方直接系統底層支援好;
4.HttpUrlConnection直接在系統層面做了快取策略處理,加快重複請求的速度。

對https支援:

AIDL:

tcp/udp了了解
連線: tcp三次握手連線,四次握手釋放連線
資源: tcp多
結構: tcp複雜 20位元組 udp8位元組
模式: tcp流結構傳輸, udp報文傳輸
可靠性: tcp可靠(停止等待、連續ARQ、滑動視窗、累積確認)慢開始、擁塞避免、快重傳、快恢復(3個連續重傳請求)

設計模式:
單例(懶漢式、餓漢式)
工廠模式:普通工廠(根據字元型別判斷) 多工廠(分別建立)、靜態工廠(靜態方法)、抽象工廠(分別實現介面)
建造者模式:
裝飾著模式:顧名思義,裝飾模式就是給一個物件增加一些新的功能,而且是動態的,要求裝飾物件和被裝飾物件實現同一個介面,裝飾物件持有被裝飾物件的例項。
觀察者模式:
介面卡模式:

第三方框架框架: Rajava,Volley, Okhttp、EventBus、Retrofit、Glide、Picasso等等

RecycleView與ListView;GridView之對比

記憶體洩漏和記憶體溢位、OOM
1、一次性載入過多內容。
* 2、記憶體洩漏。
* 1、資源未關閉。—->遊標、流、要呼叫recycle方法的。
* 2、生命週期長的物件持有了生命週期短的物件的引用。
* 靜態成員變數持有類引用。
* 非靜態內部類持有外部類的引用。
* 3、執行緒生命週期不可控。 無限迴圈動畫。

MVC和MVP模式。
* 1、MVC模式。
* 目的——->將資料和檢視分離。
* 結構。
* M——>Model層,包含網路請求資料、資料庫讀取、檔案讀寫等等。
* V——>View層,在android工程當中所代表的就是layout檔案。
* C——>Controler層,在android工程當中是Activity和Fragment。
* 缺點——>Activity不僅僅做了控制層的工作,很多時候還要做View層的工作,因為在android的MVC當中View層是寫死的,不靈活Activity和Fragment。
* 2、MVP模式。
* 目的:解決MVC中的缺陷。
* 結構。
* M——>Model層,包含網路請求資料、資料庫讀取、檔案讀寫等等。
* V——>View層,Activity和Fragment。
* P——->Presenter,自己寫的Presenter類。在這個類的建構函式中傳入Model和View的物件。將資料顯示到檢視上。 presenter物件在哪兒new——->activity中。
* 缺點。這是一個面向介面程式設計的模式,使用View層和P層的時候都會寫介面和實現類,會增加很多的檔案和類

執行緒池
* 為什麼使用執行緒池?
* 1、開啟執行緒和銷燬執行緒都有資源消耗。
* 2、開啟執行緒需要時間。雖然時間短,但蚊子腿上也有肉。
* 3、便於執行緒的管理。
* 怎麼去建立執行緒池。——>參考谷歌市場。
* 執行緒池的執行機制?
* 首先幾個重要的引數:corpalsize(核心執行緒數)、maxSize(最大執行緒數)、keepAliveTime(存活時間)。
* 當任務數小於核心執行緒數的時候?——–>建立執行緒執行任務。
* 當任務數大於核心執行緒數但是小於最大執行緒數的時候?——->放入佇列中等待。
* 如果佇列滿了?———>建立執行緒執行任務。
* 當任務數大於最大執行緒數?——->丟擲異常。

AsyncTask(三個引數,onPreExecute(第一個引數),doInBackground, onProgressUpdate(第二個引數),onPostExecute(第三個引數))
核心執行緒數 cpu + 1, 最大執行緒數2n+1, 佇列最大128 執行過程是mTask佇列offer出一個任務加到請求佇列去執行

String、StringBuilder和StringBuffer
1. String 類
  String的值是不可變的,這就導致每次對String的操作都會生成新的String物件,不僅效率低下,而且大量浪費有限的記憶體空間。
String a = “a”; //假設a指向地址0x0001
a = “b”;//重新賦值後a指向地址0x0002,但0x0001地址中儲存的”a”依舊存在,但已經不再是a所指向的,a 已經指向了其它地址。
因此String的操作都是改變賦值地址而不是改變值操作。

  1. StringBuffer是可變類,和執行緒安全的字串操作類,任何對它指向的字串的操作都不會產生新的物件。 每個StringBuffer物件都有一定的緩衝區容量,當字串大小沒有超過容量時,不會分配新的容量,當字串大小超過容量時,會自動增加容量。

    StringBuffer buf=new StringBuffer(); //分配長16位元組的字元緩衝區
    StringBuffer buf=new StringBuffer(512); //分配長512位元組的字元緩衝區
    StringBuffer buf=new StringBuffer(“this is a test”)//在緩衝區中存放了字串,並在後面預留了16位元組的空緩衝區。

3.StringBuffer
  StringBuffer和StringBuilder類功能基本相似,主要區別在於StringBuffer類的方法是多執行緒、安全的,而StringBuilder不是執行緒安全的,相比而言,StringBuilder類會略微快一點。對於經常要改變值的字串應該使用StringBuffer和StringBuilder類。

4.執行緒安全
StringBuffer 執行緒安全
StringBuilder 執行緒不安全

5.速度
一般情況下,速度從快到慢:StringBuilder>StringBuffer>String,這種比較是相對的,不是絕對的。

6.總結
(1).如果要操作少量的資料用 = String
(2).單執行緒操作字串緩衝區 下操作大量資料 = StringBuilder
(3).多執行緒操作字串緩衝區 下操作大量資料 = StringBuffer

總結

這次就先準備了這麼多,以後會持續更新的,這裡面有還幾個問題還沒有寫出來,我會在面試題二中給出答案,敬請期待。

如有錯誤,敬請批評指正,或者有更好的知識點,也可反饋給我收納,謝謝!