Android面試基礎知識總結(一)
Android面試基礎知識總結。
Activity
生命週期
- 啟動Activity:onCreate->onStart->onResume
- 鎖屏或被其它Activity覆蓋:onPause->onStop
- 解鎖或由被覆蓋狀態再回到前臺:onRestart->onStart->onResume
- 跳轉到其它Activity或按Home進入後臺:onPause->onStop
- 退回到此Activity:onRestart->onStart->onResume
- 退出此Activity:onPause->onStop->onDestory
- 對話方塊彈出不會執行任何生命週期(注:對話方塊如果是Activity(Theme為Dialog),還是會執行生命週期的)
- 從A跳轉到B:A-onPause->B-(onCreate->onStart->onResume)-A-onStop
- 從B返回到A:B-onPause->A-(onRestart->onStart->onResume)-B-(onStop->onDestroy)
onWindowFocusChanged方法
- 視窗焦點改變時被呼叫
- 在onResume之後獲得焦點,onPause之後失去焦點
onSaveInstanceState方法
- 用於儲存Activity的狀態儲存一些臨時資料
- Activity被覆蓋或進入後臺,由於系統資源不足被kill會被呼叫
- 使用者改變螢幕方向會被呼叫
- 跳轉到其它Activity或按Home進入後臺會被呼叫
- 會在onStop之前被呼叫,和onPause的順序不固定的
onRestoreInstanceState(Bundle savedInstanceState)方法
- 用於恢復儲存的臨時資料,此方法的Bundle引數也會傳遞到onCreate方法中,你也可以在onCreate(Bundle savedInstanceState)方法中恢復資料
- 由於系統資源不足被kill之後又回到此Activity會被呼叫
- 使用者改變螢幕方向重建Activity時會被呼叫
- 會在onStart之後被呼叫
問題:記憶體不足時,怎麼保持Activity的一些狀態,在哪個方法裡面做具體操作?
在onSaveInstanceState方法中儲存Activity的狀態,在onRestoreInstanceState或onCreate方法中恢復Activity的狀態
螢幕方向
- 豎屏:在AndroidManifest.xml中對指定的Activity設定android:screenOrientation=”portrait”或在onCreate方法中呼叫
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- 橫屏:在AndroidManifest.xml中對指定的Activity設定android:screenOrientation=”landscape”或在onCreate方法中呼叫
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
預設情況下,切換螢幕方向時Activity會銷燬、重建
- onPause->onStop->onDestroy->onCreate->onStart->onResume
配置為android:configChanges=”orientation|screenSize”時
- 只會呼叫onConfigurationChanged方法
- 注意當配置screenOrientation屬性後,此屬性無效。
啟動模式
- standard 標準模式(activity預設的): 每次呼叫startActivity, 都會把activity給建立.
- singleTop 單一頂部模式: 每次呼叫startActivity, 需要判斷當前的activity是否已經被建立過並且檢視任務棧的頂部是否是當前的 activity, 如果是, 呼叫onNewIntent方法, 如果不是, 就建立一個新的activity例項.
應用場景: 非法程式設計師, 寫的流氓程式, 一直在彈出某個頁面. - singleTask 單一任務棧模式: 如果任務棧中已經存在當前activity, 再去呼叫startActivity, 會呼叫當前任務棧的onNewIntent方法. 同時 , 會把所有以上的activity都給清除出棧.
應用場景: 如果一個介面顯示的資源非常大, 只需要初始化一次例項. - singleInstance 單一例項模式: activity會在一個新的任務棧中例項化, 並且其他的activity不會建立在新的任務棧中. 始終在整個系統中 會被初始化一次.
應用場景: 在整個系統中, 只需要初始化一次的頁面.
同一個程式不同的Activity如何放在不同的任務棧中?
- 需要為不同的activity設定不同的affinity屬性,啟動activity的Intent需要包含FLAG_ACTIVITY_NEW_TASK標記。
如何將一個Activity設定成視窗的樣式
- 給Activity設定主題為android:theme=”@android:style/Theme.Dialog”
如何退出Activity?如何安全退出已呼叫多個Activity的Application?
- 退出Activity直接finish即可。
- 拋異常強制退出,該方法通過拋異常,使程式Force Close。驗證可以,但是,需要解決的問題是,如何使程式結束掉,而不彈出Force Close的視窗。
- 記錄開啟的Activity:每開啟一個Activity,就記錄下來。在需要退出時,關閉每一個Activity即可。
- 傳送特定廣播:在需要結束應用時,傳送一個特定的廣播,每個Activity收到廣播後,關閉即可。
- 遞迴退出:在開啟新的Activity時使用startActivityForResult,然後自己加標誌,在onActivityResult中處理,遞迴關閉。
Fragment生命週期
onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume->onPause->onStop->onDestroyView->onDestroy->onDetach
Broadcast、Content Provider 和 AIDL的區別和聯絡
這3種都可以實現跨程序的通訊,那麼從效率,適用範圍,安全性等方面來比較的話他們3者之間有什麼區別?
Broadcast:用於傳送和接收廣播!實現資訊的傳送和接收!
AIDL:用於不同程式間服務的相互呼叫!實現了一個程式為另一個程式服務的功能!
Content Provider:用於將程式的資料庫人為地暴露出來!實現一個程式可以對另個程式的資料庫進行相對用的操作!
Broadcast,既然是廣播,那麼它的優點是:註冊了這個廣播接收器的應用都能夠收到廣播,範圍廣。
缺點是:速度慢點,而且必須在一定時間內把事情處理完(onReceive執行必須在幾秒之內),否則的話系統給出ANR。
AIDL,是程序間通訊用的,類似一種協議吧。優點是:速度快(系統底層直接是共享記憶體),效能穩,效率高,一般程序間通訊就用它。
Content Provider,因為只是把自己的資料庫暴露出去,其他程式都可以來獲取資料,資料本身不是實時的,不像前兩者,只是起個數據供應作用。一般是某個成熟的應用來暴露自己的資料用的。 你要是為了程序間通訊,還是別用這個了,這個又不是實時資料。
Handler機制
- andriod提供了Handler 和 Looper 來滿足執行緒間的通訊。Handler先進先出原則。Looper類用來管理特定執行緒內物件之間的訊息交換(MessageExchange)。
- Looper: 一個執行緒可以產生一個Looper物件,由它來管理此執行緒裡的MessageQueue(訊息佇列)。
- Handler: 你可以構造Handler物件來與Looper溝通,以便push新訊息到MessageQueue裡;或者接收Looper從Message Queue取出)所送來的訊息。
- Message Queue(訊息佇列):用來存放執行緒放入的訊息。
- 執行緒:UIthread 通常就是main thread,而Android啟動程式時會替它建立一個MessageQueue。
ListView卡頓原因
- Adapter的getView方法裡面convertView沒有使用setTag和getTag方式;
- 在getView方法裡面ViewHolder初始化後的賦值或者是多個控制元件的顯示狀態和背景的顯示沒有優化好,抑或是裡面含有複雜的計算和耗時操作;
- 在getView方法裡面 inflate的row 巢狀太深(佈局過於複雜)或者是佈局裡面有大圖片或者背景所致;
- Adapter多餘或者不合理的notifySetDataChanged;
- listview 被多層巢狀,多次的onMessure導致卡頓,如果多層巢狀無法避免,建議把listview的高和寬設定為fill_parent. 如果是程式碼繼承的listview,那麼也請你別忘記為你的繼承類新增上LayoutPrams,注意高和寬都是fill_parent的;
資料儲存,資料持久化的方式有哪些
- SharedPreference
- 資料庫SQLite
- 檔案
- ContentProvider內容提供者,如聯絡人
- 網路
程序優先順序
- 前臺程序
- 可視程序
- 服務程序
- 後臺程序
- 空程序
JVM 和Dalvik虛擬機器的區別
- JVM:
.java -> javac -> .class -> jar -> .jar
架構: 堆和棧的架構. - DVM:
.java -> javac -> .class -> dx.bat -> .dex
架構: 暫存器(cpu上的一塊快取記憶體)
Android中px,sp,dip,dp的區別與聯絡,將60px轉換為相應螢幕的dp,並填入下表
ldpi | mdpi | tvdpi | hdpi | xhdpi | xxhdpi | xxxhdpi |
---|---|---|---|---|---|---|
80 | 60 | 45 | 40 | 30 | 20 | 15 |
px = dip * density / 160
ldpi = 60px/0.75 = 80dp
mdpi = 60px/1 = 60dp
hdpi = 60px/1.5 = 40dp
xhdpi = 60px/2.0 = 30dp
xxhdpi = 60px/3.0 = 20dp
xxxhdpi = 60px/4.0 = 15dp
PPI = Pixels per inch,每英寸上的畫素數,即 “畫素密度”
xxxhdpi: 4.0
xxhdpi: 3.0 (10801920) ppi=480
xhdpi: 2.0 (7201280) ppi=320
hdpi: 1.5 (480800) ppi=240
mdpi: 1.0 (baseline)(320480) ppi=160
ldpi: 0.75 (240*320) ppi=120
tvdpi:ppi=213
dip: device independent pixels(裝置獨立畫素). 不同裝置有不同的顯示效果,這個和裝置硬體有關,一般我們為了支援WVGA、HVGA和QVGA 推薦使用這個,不依賴畫素。
dp: dip是一樣的
px: pixels(畫素).
pt: point,是一個標準的長度單位,1pt=1/72英寸,用於印刷業,非常簡單易用;
sp: scaled pixels(放大畫素). 主要用於字型顯示best for textsize。
in(英寸):長度單位。
mm(毫米):長度單位。
據px = dip * density / 160,則當螢幕密度為160時,px = dip
根據 google 的建議,TextView 的字號最好使用 sp 做單位,而且檢視TextView的原始碼可知Android預設使用sp作為字號單位。將dip作為其他元素的單位。
簡述Android應用程式的組成
- Activites 應用程式的表示層。
應用程式的每個介面都將是Activity類的擴充套件。Acitvities用檢視(View)構成GUI來顯示資訊、響應使用者操作。就桌面開發而言,一個活動(Activity)相當於一個窗體(Form)。 - Services 應用程式中的隱形工作者。
Service元件在後臺執行,更新你的資料來源和可見的Activities,觸發通知(Notification)。在應用程式的Activities不啟用或不可見時,用於執行依然需要繼續的長期處理。 - Content Providers 可共享的資料儲存。
Content Providers用於管理和共享應用程式資料庫。是跨應用程式邊界資料共享的優先方式。 - Intents 一個應用程式間(inter-application)的訊息傳遞框架。
使用Intents你可以在系統範圍內廣播訊息或者對一個目標Activity或Service傳送訊息,來表示你要執行一個動作。 - Widgets 可以新增到主螢幕介面(home screen)的可視應用程式元件。
作為Broadcase Receiver的特殊變種,widgets讓你可以為使用者建立可嵌入到主螢幕介面的動態的、互動的應用程式元件。
Android中的動畫有哪些,區別是什麼
兩種,一種是Tween動畫、還有一種是Frame動畫。Tween動畫,這種實現方式可以使檢視元件移動、放大、縮小以及產生透明度的變化;另一種Frame動畫,傳統的動畫方法,通過順序的播放排列好的圖片來實現,類似電影。
簡述靜默安裝的原理,如何在無需root許可權的情況下實現靜默安裝?
- 偽裝成系統應用,這就要給app打上系統應用的簽名,但是這些簽名在小米等手機上是沒用的。
- 通過把應用放在system/app的目錄下也可以實現。
假如com.google.gson 包中的類不允許混淆,並且專案中所有的Bean不允許混淆,但是由於專案是由多人開發,並不確定Bean所在的包,只知道Bean實現了序列化,請手動配置專案的混淆規則
1 2 |
-keep class com.google.gson.** { *; }
-keep class * implements java.io.Serializable {*;}
|
手動編寫gradle指令碼,將libs\arm64-v8a目錄下的so庫及libs\gson-2.5.jar配置到專案依賴中
指定JNI資料夾為libs
1 2 3 4 5 |
sourceSets{ main{ jniLibs.srcDir(['libs']) } } |
新增gson依賴
1
|
compile files('libs/gson-2.5.jar')
|
Android事件傳遞及處理機制
- dispatchTouchEvent()事件分發
- onInterceptTouchEvent()事件攔截
- onTouchEvent()
首先由父控制元件接收到事件進行分發,呼叫攔截,返回true進行消費呼叫onTouchEvent,返回false則將事件傳遞給子控制元件,若子控制元件為ViewGroup則繼續傳遞,最終為View時,事件無法向下傳遞呼叫onTouchEvent返回true消費,返回false,回傳事件,父控制元件的onTouchEvent返回true消費,返回false事件丟失
無子類的View沒有onInterceptTouchEvent()事件攔截方法
子執行緒中更新UI的方法
- 第一種:Handler+Message
-
第二種:
1 2 3 4 5 6
new Handler(context.getMainLooper()).post( new Runnable(){ public void run(){ //更新UI } });
-
第三種
1 2 3 4 5 6 7
((Activity)context)runOnUiThread( new Runnable(){ public void run(){ //更新UI } } );
postInvalidate與invalidate有什麼區別?
- 都用於重新整理介面
- postInvalidate()用在子執行緒
- invalidate()用在主執行緒
notifyDataSetChanged和notifyDataSetInvalidated的區別
- notifyDataSetInvalidated(),會重繪整個控制元件(還原到初始狀態)
- notifyDataSetChanged(),重繪當前可見區域
請介紹下Android中常用的五種佈局
- FrameLayout(框架佈局)
- LinearLayout (線性佈局)
- AbsoluteLayout(絕對佈局)
- RelativeLayout(相對佈局)
- TableLayout(表格佈局)
Serializable和Parcelable的區別
- 都能實現序列化且可用於Intent間的資料傳遞
- Serializable是Java中的序列化介面,使用簡單但開銷大,序列化和反序列化過程需要大量I/O操作。
- Parcelable更適合Android平臺,使用麻煩但效率高,主要用在記憶體序列化上。
檔案和資料庫哪個效率高
- 資料量大時使用資料庫效率高
- 資料量小時使用檔案效率高