關
1.靜態內部類、內部類、匿名內部類,爲什麼內部類會持有外部類的引用?持有的引用是this?還是其它?
-
靜態內部類:使用static修飾的內部類
-
內部類:就是在某個類的內部又定義了一個類,內部類所嵌入的類稱爲外部類
-
匿名內部類:使用new生成的內部類
-
因爲內部類的產生依賴於外部類,持有的引用是類名.this
2.Java中try catch finally的執行順序
先執行try中代碼,如果發生異常執行catch中代碼,最後一定會執行finally中代碼
3.equals與==的區別:
==是判斷兩個變量或實例是不是指向同一個內存空間 equals是判斷兩個變量或實例所指向的內存空間的值是不是相
4.Object有哪些公用方法?
-
方法equals測試的是兩個對象是否相等
-
方法clone進行對象拷貝
-
方法getClass返回和當前對象相關的Class對象
-
方法notify,notifyall,wait都是用來對給定對象進行線程同步的
5.String、StringBuffer與StringBuilder的區別
-
String 類型和 StringBuffer 類型的主要性能區別其實在於 String 是不可變的對象
-
StringBuffer和StringBuilder底層是 char[]數組實現的
-
StringBuffer是線程安全的,而StringBuilder是線程不安全的
6.Java的四種引用的區別
-
強引用:如果一個對象具有強引用,它就不會被垃圾回收器回收。即使當前內存空間不足,JVM 也不會回收它,而是拋出 OutOfMemoryError 錯誤,使程序異常終止。如果想中斷強引用和某個對象之間的關聯,可以顯式地將引用賦值爲null,這樣一來的話,JVM在合適的時間就會回收該對象
-
軟引用:在使用軟引用時,如果內存的空間足夠,軟引用就能繼續被使用,而不會被垃圾回收器回收,只有在內存不足時,軟引用纔會被垃圾回收器回收。
-
弱引用:具有弱引用的對象擁有的生命週期更短暫。因爲當 JVM 進行垃圾回收,一旦發現弱引用對象,無論當前內存空間是否充足,都會將弱引用回收。不過由於垃圾回收器是一個優先級較低的線程,所以並不一定能迅速發現弱引用對象
-
虛引用:顧名思義,就是形同虛設,如果一個對象僅持有虛引用,那麼它相當於沒有引用,在任何時候都可能被垃圾回收器回收。
7.介紹垃圾回收機制
-
標記回收法:遍歷對象圖並且記錄可到達的對象,以便刪除不可到達的對象,一般使用單線程工作並且可能產生內存碎片
-
標記-壓縮回收法:前期與第一種方法相同,只是多了一步,將所有的存活對象壓縮到內存的一端,這樣內存碎片就可以合成一大塊可再利用的內存區域,提高了內存利用率
-
複製回收法:把現有內存空間分成兩部分,gc運行時,它把可到達對象複製到另一半空間,再清空正在使用的空間的全部對象。這種方法適用於短生存期的對象,持續複製長生存期的對象則導致效率降低。
-
分代回收發:把內存空間分爲兩個或者多個域,如年輕代和老年代,年輕代的特點是對象會很快被回收,因此在年輕代使用效率比較高的算法。當一個對象經過幾次回收後依然存活,對象就會被放入稱爲老年的內存空間,老年代則採取標記-壓縮算法
集合、數據結構相關
1.你用過哪些集合類
數據結構中用於存儲數據的有哪些
-
數組
數組存儲區間是連續的,佔用內存嚴重,故空間複雜的很大。但數組的二分查找時間複雜度小,爲O(1);數組的特點是:尋址容易,插入和刪除困難;
-
鏈表
鏈表存儲區間離散,佔用內存比較寬鬆,故空間複雜度很小,但時間複雜度很大,達O(N)。鏈表的特點是:尋址困難,插入和刪除容易。
2.說說hashMap是怎樣實現的
哈希表:由數組+鏈表組成的
當我們往HashMap中put元素的時候,先根據key的hashCode重新計算hash值,根據hash值得到這個元素在數組中的位置(即下標)
如果數組該位置上已經存放有其他元素了,那麼在這個位置上的元素將以鏈表的形式存放,新加入的放在鏈頭,最先加入的放在鏈尾。
如果數組該位置上沒有元素,就直接將該元素放到此數組中的該位置上。
3.ArrayList,LinkedList的區別
-
ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構。
-
對於隨機訪問get和set,ArrayList覺得優於LinkedList,因爲LinkedList要移動指針。
-
對於新增和刪除操作add和remove,LinedList比較佔優勢,因爲ArrayList要移動數據。
4.ArrayList和Vector的主要區別是什麼?
ArrayList 和Vector底層是採用數組方式存儲數據
-
Vector:
-
線程同步
-
當Vector中的元素超過它的初始大小時,Vector會將它的容量翻倍,
-
-
ArrayList:
-
線程不同步,但性能很好
-
當ArrayList中的元素超過它的初始大小時,ArrayList只增加50%的大小
-
5.HashMap和 HashTable 的區別:
-
HashTable比較老,是基於Dictionary 類實現的,HashTable 則是基於 Map接口實現的
-
HashTable 是線程安全的, HashMap 則是線程不安全的
-
HashMap可以讓你將空值作爲一個表的條目的key或value
算法相關
1.排序算法和穩定性,快排什麼時候情況最壞?
2.給最外層的rootview,把這個根視圖下的全部button背景設置成紅色,手寫代碼,不許用遞歸
算法原理:
-
Android的view視圖是按樹形結構分佈,所以按樹形結構遍歷
-
循環判斷每一層的ViewGroup元素,將其入棧;否則判斷當前view是否是Button類實例,是則改寫背景色
-
當前ViewGroup檢查childView完成後,判斷棧是否非空,取出棧頂元素ViewGroup重複步驟2直至棧爲空。
Thread、AsynTask相關
1.wait()和sleep()的區別
-
sleep來自Thread類,和wait來自Object類
-
調用sleep()方法的過程中,線程不會釋放對象鎖。而 調用 wait 方法線程會釋放對象鎖
-
sleep睡眠後不出讓系統資源,wait讓出系統資源其他線程可以佔用CPU
-
sleep(milliseconds)需要指定一個睡眠時間,時間一到會自動喚醒
2.若Activity已經銷燬,此時AsynTask執行完並且返回結果,會報異常嗎?
-
當一個App旋轉時,整個Activity會被銷燬和重建。當Activity重啓時,AsyncTask中對該Activity的引用是無效的,因此onPostExecute()就不會起作用,若AsynTask正在執行,折會報 view not attached to window manager 異常
-
同樣也是生命週期的問題,在 Activity 的onDestory()方法中調用Asyntask.cancal方法,讓二者的生命週期同步
3.Activity銷燬但Task如果沒有銷燬掉,當Activity重啓時這個AsyncTask該如何解決?
還是屏幕旋轉這個例子,在重建Activity的時候,會回掉Activity.onRetainNonConfigurationInstance()重新傳遞一個新的對象給AsyncTask,完成引用的更新
4.Android 線程間通信有哪幾種方式(重要)
-
共享內存(變量);
-
文件,數據庫;
-
Handler;
-
Java 裏的 wait(),notify(),notifyAll()
5.請介紹下 AsyncTask的內部實現,適用的場景是
-
AsyncTask 內部也是 Handler 機制來完成的,只不過 Android 提供了執行框架來提供線程池來
-
執行相應地任務,因爲線程池的大小問題,所以 AsyncTask 只應該用來執行耗時時間較短的任務,
-
比如 HTTP 請求,大規模的下載和數據庫的更改不適用於 AsyncTask,因爲會導致線程池堵塞,沒有
-
線程來執行其他的任務,導致的情形是會發生 AsyncTask 根本執行不了的問題。
網絡相關
1.TCP三次握手
2.爲什麼TCP是可靠的,UDP早不可靠的?爲什麼UDP比TCP快?
-
TCP/IP協議高,因爲其擁有三次握手雙向機制,這一機制保證校驗了數據,保證了他的可靠性。
-
UDP就沒有了,udp信息發出後,不驗證是否到達對方,所以不可靠。
-
但是就速度來說,還是UDP協議更高,畢竟其無需重複返回驗證,只是一次性的
3.http協議瞭解多少,說說裏面的協議頭部有哪些字段?
-
http(超文本傳輸協議)是一個基於請求與響應模式的、無狀態的、應用層的協議;http請求由三部分組成,分別是:請求行、消息報頭、請求正文。
-
HTTP消息報頭包括普通報頭、請求報頭、響應報頭、實體報頭
4.https瞭解多少
HTTPS(全稱:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全爲目標的HTTP通道,簡單講是HTTP的安全版。即HTTP下加入SSL層,HTTPS的安全基礎是SSL,因此加密的詳細內容就需要SSL。
5.談談 HTTP 中Get 和 Post 方法的區別
-
GET - 從指定的服務器中獲取數據,明文發送內容
-
POST - 提交數據給指定的服務器處理
-
POST請求不能被緩存下來
-
POST請求不會保存在瀏覽器瀏覽記錄中
-
以POST請求的URL無法保存爲瀏覽器書籤
-
POST請求沒有長度限制
6.推送心跳包是TCP包還是UDP包或者HTTP包
心跳包的實現是調用了socket.sendUrgentData(0xFF)這句代碼實現的,所以,當然是TCP包。
7.如何實現文件斷點上傳
在 Android 中上傳文件可以採用 HTTP 方式,也可以採用 Socket 方式,但是 HTTP 方式不能上傳
大文件,這裏介紹一種通過 Socket 方式來進行斷點續傳的方式,服務端會記錄下文件的上傳進度,
當某一次上傳過程意外終止後,下一次可以繼續上傳,這裏用到的其實還是 J2SE 裏的知識。
這個上傳程序的原理是:客戶端第一次上傳時向服務端發送
“Content-Length=35;filename=WinRAR_3.90_SC.exe;sourceid=“這種格式的字符串,服務端 收到後會查找該文件是否有上傳記錄,如果有就返回已經上傳的位置,否則返回新生成的 sourceid 以及 position 爲 0,類似 sourceid=2324838389;position=0“這樣的字符串,客戶端收到返回後 的字符串後再從指定的位置開始上傳文件。
Fragment相關
1.Fragment 如何實現類似 Activity 棧的壓棧和出棧效果的?
Fragment 的事物管理器內部維持了一個雙向鏈表結構,該結構可以記錄我們每次 add 的
Fragment 和 replace 的 Fragment,然後當我們點擊 back 按鈕的時候會自動幫我們實現退棧操作。
2.Fragment 在你們項目中的使用
-
Fragment 是 android3.0 以後引入的的概念,做局部內容更新更方便,原來爲了到達這一點要
-
把多個佈局放到一個 activity 裏面,現在可以用多 Fragment 來代替,只有在需要的時候才加載
-
Fragment,提高性能。
Fragment 的好處:
-
Fragment 可以使你能夠將 activity 分離成多個可重用的組件,每個都有它自己的生命週期和UI。
-
Fragment 可以輕鬆得創建動態靈活的 UI 設計,可以適應於不同的屏幕尺寸。從手機到平板電腦。
-
Fragment 是一個獨立的模塊,緊緊地與 activity 綁定在一起。可以運行中動態地移除、加入、交換等。
-
Fragment 提供一個新的方式讓你在不同的安卓設備上統一你的 UI。
-
Fragment 解決 Activity 間的切換不流暢,輕量切換。
-
Fragment 替代 TabActivity 做導航,性能更好。
-
Fragment 在 4.2.版本中新增嵌套 fragment 使用方法,能夠生成更好的界面效果
3.如何切換 fragement,不重新實例化
正確的切換方式是 add(),切換時 hide(),add()另一個 Fragment;再次切換時,只需 hide()當前, show()另一個
四大組件相關
1.Activity和Fragment生命週期有哪些?
Activity——onCreate->onStart->onResume->onPause->onStop->onDestroy
Fragment——onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume->onPause->onStop->onDestroyView->onDestroy->onDetach
2.廣播的兩種註冊方式及有什麼區別
3.內存不足時,怎麼保持Activity的一些狀態,在哪個方法裏面做具體操作?
Activity的 onSaveInstanceState() 和 onRestoreInstanceState()並不是生命週期方法,它們不同於 onCreate()、onPause()等生命週期方法,它們並不一定會被觸發。當應用遇到意外情況(如:內存不足、用戶直接按Home鍵)由系統銷燬一個Activity,onSaveInstanceState() 會被調用。但是當用戶主動去銷燬一個Activity時,例如在應用中按返回鍵,onSaveInstanceState()就不會被調用。除非該activity是被用戶主動銷燬的,通常onSaveInstanceState()只適合用於保存一些臨時性的狀態,而onPause()適合用於數據的持久化保存。
4.啓動service的兩種方法?有什麼區別?
一種是startService(),另一種是bindService()。這兩者的區別是第一種方式調用者開啓了服務,即會與服務失去聯繫,兩者沒有關聯。即使訪問者退出了,服務仍在運行。如需解除服務必須顯式的調用stopService方法。主要用於調用者與服務沒有交互的情況下,也就是調用者不需要獲取服務裏的業務方法。比如電話錄音。而後者調用者與服務綁定在一起的。當調用者退出的時候,服務也隨之退出。用於需要與服務交互。
5.Android中的Context, Activity,Appliction有什麼區別?
相同:Activity和Application都是Context的子類。
Context從字面上理解就是上下文的意思,在實際應用中它也確實是起到了管理上下文環境中各個參數和變量的總用,方便我們可以簡單的訪問到各種資源。
不同:維護的生命週期不同。 Context維護的是當前的Activity的生命週期,Application維護的是整個項目的生命週期。
使用context的時候,小心內存泄露,防止內存泄露,注意一下幾個方面:
不要讓生命週期長的對象引用activity context,即保證引用activity的對象要與activity本身生命週期是一樣的。
對於生命週期長的對象,可以使用application,context。
避免非靜態的內部類,儘量使用靜態類,避免生命週期問題,注意內部類對外部對象引用導致的生命週期變化。
6.Context是什麼?
它描述的是一個應用程序環境的信息,即上下文。
該類是一個抽象(abstract class)類,Android提供了該抽象類的具體實現類(ContextIml)。
通過它我們可以獲取應用程序的資源和類,也包括一些應用級別操作,例如:啓動一個Activity,發送廣播,接受Intent,信息,等。
7.Service 是否在 main thread 中執行, service 裏面是否能執行耗時的操作?
默認情況,如果沒有顯示的指 servic 所運行的進程, Service 和 activity 是運行在當前 app 所在進
程的 main thread(UI 主線程)裏面。
service 裏面不能執行耗時的操作(網絡請求,拷貝數據庫,大文件 )
特殊情況 ,可以在清單文件配置 service 執行所在的進程 ,讓 service 在另外的進程中執行 ? 1 2 3 4 5
8.Activity 怎麼和 Service 綁定,怎麼在 Activity 中啓動自己對應的Service?
Activity 通過 bindService(Intent service, ServiceConnection conn, int flags)跟 Service 進行綁定,當綁定成功的時候 Service 會將代理對象通過回調的形式傳給 conn,這樣我們就拿到了Service 提供的服務代理對象。
在 Activity 中可以通過 startService 和 bindService 方法啓動 Service。一般情況下如果想獲取Service 的服務對象那麼肯定需要通過 bindService()方法,比如音樂播放器,第三方支付等。如果僅僅只是爲了開啓一個後臺任務那麼可以使用 startService()方法。
9.說說 Activity、Intent、Service 是什麼關係
他們都是 Android 開發中使用頻率最高的類。其中 Activity 和 Service 都是 Android 四大組件之一。他倆都是 Context 類的子類 ContextWrapper 的子類,因此他倆可以算是兄弟關係吧。不過兄弟倆各有各自的本領,Activity 負責用戶界面的顯示和交互,Service 負責後臺任務的處理。Activity和 Service 之間可以通過 Intent 傳遞數據,因此可以把 Intent 看作是通信使者。
10.請描述一下 BroadcastReceiver
BroadCastReceiver 是 Android 四大組件之一,主要用於接收系統或者 app 發送的廣播事件。
廣播分兩種:有序廣播和無序廣播。
內部通信實現機制:通過 Android 系統的 Binder 機制實現通信。
無序廣播:完全異步,邏輯上可以被任何廣播接收者接收到。優點是效率較高。缺點是一個接收者不
能將處理結果傳遞給下一個接收者,並無法終止廣播 intent 的傳播。
有序廣播:按照被接收者的優先級順序,在被接收者中依次傳播。比如有三個廣播接收者 A,B,C,
優先級是 A > B > C。那這個消息先傳給 A,再傳給 B,最後傳給 C。每個接收者有權終止廣播,比如 B 終止廣播,C 就無法接收到。此外 A 接收到廣播後可以對結果對象進行操作,當廣播傳給 B 時,B 可以從結果對象中取得 A 存入的數據。
在通過 Context.sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler,initialCode, initialData, initialExtras)時我們可以指定 resultReceiver 廣播接收者,這個接收者我們可以認爲是最終接收者,通常情況下如果比他優先級更高的接收者如果沒有終止廣播,那麼他的onReceive 會被執行兩次,第一次是正常的按照優先級順序執行,第二次是作爲最終接收者接收。
如果比他優先級高的接收者終止了廣播,那麼他依然能接收到廣播
11.爲什麼要用 ContentProvider?它和 sql 的實現上有什麼差別?
ContentProvider 屏蔽了數據存儲的細節,內部實現對用戶完全透明,用戶只需要關心操作數據的uri 就可以了,ContentProvider 可以實現不同 app 之間共享。
Sql 也有增刪改查的方法,但是 sql 只能查詢本應用下的數據庫。而 ContentProvider 還可以去增刪改查本地文件. xml 文件的讀取等。
12.說說 ContentProvider、ContentResolver、ContentObserver 之間的關係
-
ContentProvider 內容提供者,用於對外提供數據
-
ContentResolver.notifyChange(uri)發出消息
-
ContentResolver 內容解析者,用於獲取內容提供者提供的數據
-
ContentObserver 內容監聽器,可以監聽數據的改變狀態
-
ContentResolver.registerContentObserver()監聽消息。
View 相關
1.onInterceptTouchEvent()和onTouchEvent()的區別
onInterceptTouchEvent()用於攔截觸摸事件
onTouchEvent()用於處理觸摸事件
2.RemoteView在哪些功能中使用
APPwidget和Notification中SurfaceView和View的區別是什麼?
SurfaceView中採用了雙緩存技術,在單獨的線程中更新界面View在UI線程中更新界面
4.View的繪製過程
一個View要顯示在界面上,需要經歷一個View樹的遍歷過程,這個過程又可以分爲三個過程,也就是自定義View中的三要素:大小,位置,畫什麼,即onMesure(),onLayout(),onDraw()。
1.onMesure()確定一個View的大小;
2.onLayout()確定View在父節點上的位置;
3.onDraw()繪製View 的內容;
5.如何自定義ViewGroup
1.指定的LayoutParams
2.onMeasure中計算所有childView的寬和高,然後根據childView的寬和高,計算自己的寬和高。(當然,如果不是wrap_content,直接使用父ViewGroup傳入的計算值即可)
3.onLayout中對所有的childView進行佈局。
6.View中onTouch,onTouchEvent,onClick的執行順序
dispatchTouchEvent—->onTouch—->onTouchEvent—–>onClick。在所有ACTION_UP事件之後才觸發onClick點擊事件。
性能優化相關
1.ListView卡頓的原因與性能優化,越多越好
重用converView: 通過複用converview來減少不必要的view的創建,另外Infalte操作會把xml文件實例化成相應的View實例,屬於IO操作,是耗時操作。
減少findViewById()操作: 將xml文件中的元素封裝成viewholder靜態類,通過converview的setTag和getTag方法將view與相應的holder對象綁定在一起,避免不必要的findviewbyid操作
避免在 getView 方法中做耗時的操作: 例如加載本地 Image 需要載入內存以及解析 Bitmap ,都是比較耗時的操作,如果用戶快速滑動listview,會因爲getview邏輯過於複雜耗時而造成滑動卡頓現象。用戶滑動時候不要加載圖片,待滑動完成再加載,可以使用這個第三方庫glideItem的佈局層次結構儘量簡單,避免佈局太深或者不必要的重繪
儘量能保證 Adapter 的 hasStableIds() 返回 true 這樣在 notifyDataSetChanged() 的時候,如果item內容並沒有變化,ListView 將不會重新繪製這個 View,達到優化的目的
在一些場景中,ScollView內會包含多個ListView,可以把listview的高度寫死固定下來。 由於ScollView在快速滑動過程中需要大量計算每一個listview的高度,阻塞了UI線程導致卡頓現象出現,如果我們每一個item的高度都是均勻的,可以通過計算把listview的高度確定下來,避免卡頓現象出現
使用 RecycleView 代替listview: 每個item內容的變動,listview都需要去調用notifyDataSetChanged來更新全部的item,太浪費性能了。RecycleView可以實現當個item的局部刷新,並且引入了增加和刪除的動態效果,在性能上和定製上都有很大的改善
ListView 中元素避免半透明: 半透明繪製需要大量乘法計算,在滑動時不停重繪會造成大量的計算,在比較差的機子上會比較卡。 在設計上能不半透明就不不半透明。實在要弄就把在滑動的時候把半透明設置成不透明,滑動完再重新設置成半透明。
儘量開啓硬件加速: 硬件加速提升巨大,避免使用一些不支持的函數導致含淚關閉某個地方的硬件加速。當然這一條不只是對 ListView。
2.如何避免 OOM 問題的出現
使用更加輕量的數據結構 例如,我們可以考慮使用ArrayMap/SparseArray而不是HashMap等傳統數據結構。通常的HashMap的實現方式更加消耗內存,因爲它需要一個額外的實例對象來記錄Mapping操作。另外,SparseArray更加高效,在於他們避免了對key與value的自動裝箱(autoboxing),並且避免了裝箱後的解箱。
避免在Android裏面使用Enum Android官方培訓課程提到過“Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.”,具體原理請參考《Android性能優化典範(三)》,所以請避免在Android裏面使用到枚舉。
減小Bitmap對象的內存佔用 Bitmap是一個極容易消耗內存的大胖子,減小創建出來的Bitmap的內存佔用可謂是重中之重,,通常來說有以下2個措施: inSampleSize:縮放比例,在把圖片載入內存之前,我們需要先計算出一個合適的縮放比例,避免不必要的大圖載入。 decode format:解碼格式,選擇ARGB_6666/RBG_545/ARGB_4444/ALPHA_6,存在很大差異
Bitmap對象的複用 縮小Bitmap的同時,也需要提高BitMap對象的複用率,避免頻繁創建BitMap對象,複用的方法有以下2個措施 LRUCache : “最近最少使用算法”在Android中有極其普遍的應用。ListView與GridView等顯示大量圖片的控件裏,就是使用LRU的機制來緩存處理好的Bitmap,把近期最少使用的數據從緩存中移除,保留使用最頻繁的數據, inBitMap高級特性:利用inBitmap的高級特性提高Android系統在Bitmap分配與釋放執行效率。使用inBitmap屬性可以告知Bitmap解碼器去嘗試使用已經存在的內存區域,新解碼的Bitmap會嘗試去使用之前那張Bitmap在Heap中所佔據的pixel data內存區域,而不是去問內存重新申請一塊區域來存放Bitmap。利用這種特性,即使是上千張的圖片,也只會僅僅只需要佔用屏幕所能夠顯示的圖片數量的內存大小
使用更小的圖片 在涉及給到資源圖片時,我們需要特別留意這張圖片是否存在可以壓縮的空間,是否可以使用更小的圖片。儘量使用更小的圖片不僅可以減少內存的使用,還能避免出現大量的InflationException。假設有一張很大的圖片被XML文件直接引用,很有可能在初始化視圖時會因爲內存不足而發生InflationException,這個問題的根本原因其實是發生了OOM。
StringBuilder 在有些時候,代碼中會需要使用到大量的字符串拼接的操作,這種時候有必要考慮使用StringBuilder來替代頻繁的“+”。
避免在onDraw方法裏面執行對象的創建 類似onDraw等頻繁調用的方法,一定需要注意避免在這裏做創建對象的操作,因爲他會迅速增加內存的使用,而且很容易引起頻繁的gc,甚至是內存抖動。
避免對象的內存泄露
3.三級緩存的原理
從緩存中加載。
從本地文件中加載(數據庫,SD)
從網絡加載。
a.加載 bitmap 的時候無需考慮 bitmap 加載過程中出現的 oom(內存溢出)和 android 容器快速
滑動的時候出現的圖片錯位等現象。(16M)
-
支持加載網絡圖片和本地圖片。
-
內存管理使用的 lru 算法(移除裏面是有頻率最少的對象),更好的管理 bitmap 的內存
Android其他
1.講一下android中進程的優先級?
-
前臺進程
-
可見進程
-
服務進程
-
後臺進程
-
空進程
2.介紹Handle的機制
Handler通過調用sendmessage方法把消息放在消息隊列MessageQueue中,Looper負責把消息從消息隊列中取出來,重新再交給Handler進行處理,三者形成一個循環
通過構建一個消息隊列,把所有的Message進行統一的管理,當Message不用了,並不作爲垃圾回收,而是放入消息隊列中,供下次handler創建消息時候使用,提高了消息對象的複用,減少系統垃圾回收的次數
每一個線程,都會單獨對應的一個looper,這個looper通過ThreadLocal來創建,保證每個線程只創建一個looper,looper初始化後就會調用looper.loop創建一個MessageQueue,這個方法在UI線程初始化的時候就會完成,我們不需要手動創建
3.Dalvik虛擬機與JVM有什麼區別
Dalvik 基於寄存器,而 JVM 基於棧。基於寄存器的虛擬機對於更大的程序來說,在它們編譯的時候,花費的時間更短。
Dalvik執行.dex格式的字節碼,而JVM執行.class格式的字節碼。
4.每個應用程序對應多少個Dalvik虛擬機
每一個Android應用在底層都會對應一個獨立的Dalvik虛擬機實例,其代碼在虛擬機的解釋下得以執行 ,而所有的Android應用的線程都對應一個Linux線程
5.應用常駐後臺,避免被第三方殺掉的方法
Service設置成START_STICKY kill 後會被重啓(等待5秒左右),重傳Intent,保持與重啓前一樣
通過 startForeground將進程設置爲前臺進程, 做前臺服務,優先級和前臺應用一個級別,除非在系統內存非常缺,否則此進程不會被 kill
雙進程Service: 讓2個進程互相保護對方,其中一個Service被清理後,另外沒被清理的進程可以立即重啓進程
用C編寫守護進程(即子進程) : Android系統中當前進程(Process)fork出來的子進程,被系統認爲是兩個不同的進程。當父進程被殺死的時候,子進程仍然可以存活,並不受影響(Android5.0以上的版本不可行
聯繫廠商,加入白名單
6.根據自己的理解描述下Android數字簽名。
所有的應用程序都必須有數字證書,Android系統不會安裝一個沒有數字證書的應用程序
Android程序包使用的數字證書可以是自簽名的,不需要一個權威的數字證書機構簽名認證
如果要正式發佈一個Android程序,必須使用一個合適的私鑰生成的數字證書來給程序簽名,而不能使用adt插件或者ant工具生成的調試證書來發布。
數字證書都是有有效期的,Android只是在應用程序安裝的時候纔會檢查證書的有效期。如果程序已經安裝在系統中,即使證書過期也不會影響程序的正常功能。
7.Dalvik基於JVM的改進
幾個class變爲一個dex,constant pool,省內存
Zygote,copy-on-write shared,省內存,省cpu,省電
基於寄存器的bytecode,省指令,省cpu,省電
Trace-based JIT,省cpu,省電,省內存
8.ARGB_8888佔用內存大小
本題的答案,是4byte,即ARGB各佔用8個比特來描述。
9.apk安裝卸載的原理
安裝過程:複製apk安裝包到data/app目錄下,解壓並掃描安裝包,把dex文件(dalvik字節碼)保存到dalvik-cache目錄,並data/data目錄下創建對應的應用數據目錄。
卸載過程:刪除安裝過程中在上述三個目錄下創建的文件及目錄。
10.通過Intent傳遞一些二進制數據的方法有哪些?
使用Serializable接口實現序列化,這是Java常用的方法。
實現Parcelable接口,這裏Android的部分類比如Bitmap類就已經實現了,同時Parcelable在Android AIDL中交換數據也很常見的。
11.橫豎屏切換時Activity的生命週期
此時的生命週期跟清單文件裏的配置有關係。
不設置Activity的android:configChanges時,切屏會重新調用各個生命週期默認首先銷燬當前activity,然後重新加載。
設置Activity android:configChanges=”orientation|keyboardHidden|screenSize”時,切屏不會重新調用各個生命週期,只會執行onConfigurationChanged方法
12.Serializable 和 Parcelable 的區別
在使用內存的時候,Parcelable 類比 Serializable 性能高,所以推薦使用 Parcelable 類。
Serializable 在序列化的時候會產生大量的臨時變量,從而引起頻繁的 GC。
Parcelable 不能使用在要將數據存儲在磁盤上的情況。儘管 Serializable 效率低點,但在這
種情況下,還是建議你用 Serializable 。
13.Android 中如何捕獲未捕獲的異常
自 定 義 一 個 Application , 比 如 叫 MyApplication 繼 承 Application 實 現
UncaughtExceptionHandler。
覆寫 UncaughtExceptionHandler 的 onCreate 和 uncaughtException 方法。
14.Android 的權限規則
Android 中的 apk 必須簽名
基於 UserID 的進程級別的安全機制
默認 apk 生成的數據對外是不可見的
AndroidManifest.xml 中的顯式權限聲明
15.多線程間通信和多進程之間通信有什麼不同,分別怎麼實現?
一、進程間的通信方式
管道( pipe ):管道是一種半雙工的通信方式,數據只能單向流動,而且只能在具有親緣關係的進程間使用。進程的親緣關係通常是指父子進程關係。
有名管道 (namedpipe): 有名管道也是半雙工的通信方式,但是它允許無親緣關係進程間的通信。
信號量(semophore ): 信號量是一個計數器,可以用來控制多個進程對共享資源的訪問。它常作爲一種鎖機制,防止某進程正在訪問共享資源時,其他進程也訪問該資源。因此,主要作爲進程間以及同一進程內不同線程之間的同步手段。
消息隊列( messagequeue ): 消息隊列是由消息的鏈表,存放在內核中並由消息隊列標識符標識。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩衝區大小受限等缺點。
信號 (sinal ): 信號是一種比較複雜的通信方式,用於通知接收進程某個事件已經發生。
共享內存(shared memory ) :共享內存就是映射一段能被其他進程所訪問的內存,這段共享內存由一個進程創建,但多個進程都可以訪問。共享內存是最快的 IPC 方式,它是針對其他進程間通信方式運行效率低而專門設計的。它往往與其他通信機制,如信號兩,配合使用,來實現進程間的同步和通信。
套接字(socket ) : 套解口也是一種進程間通信機制,與其他通信機制不同的是,它可用於不同及其間的進程通信。
二、線程間的通信方式
1. 鎖機制:包括互斥鎖、條件變量、讀寫鎖
互斥鎖提供了以排他方式防止數據結構被併發修改的方法。
讀寫鎖允許多個線程同時讀共享數據,而對寫操作是互斥的。
條件變量可以以原子的方式阻塞進程,直到某個特定條件爲真爲止。對條件的測試是在互斥鎖
的保護下進行的。條件變量始終與互斥鎖一起使用。
2. 信號量機制(Semaphore):包括無名線程信號量和命名線程信號量
3. 信號機制(Signal):類似進程間的信號處理
線程間的通信目的主要是用於線程同步,所以線程沒有像進程通信中的用於數據交換的通信機制。
16.說說 LruCache 底層原理
LruCache 使用一個 LinkedHashMap 簡單的實現內存的緩存,沒有軟引用,都是強引用。如果添加的數據大於設置的最大值,就刪除最先緩存的數據來調整內存。
maxSize 是通過構造方法初始化的值,他表示這個緩存能緩存的最大值是多少。
size 在添加和移除緩存都被更新值,他通過 safeSizeOf 這個方法更新值。safeSizeOf 默認返回 1,但一般我們會根據 maxSize 重寫這個方法,比如認爲 maxSize 代表是 KB 的話,那麼就以 KB 爲單位返回該項所佔的內存大小。
除異常外首先會判斷 size 是否超過 maxSize,如果超過了就取出最先插入的緩存,如果不爲空就 刪掉,並把 size 減去該項所佔的大小。這個操作將一直循環下去,直到 size 比 maxSize 小或者緩存 空。
文末:
最後我想說:有些東西你不僅要懂,而且要能夠很好地表達出來,能夠讓面試官認可你的理解,例如Handler機制,這個是面試必問之題。有些晦澀的點,或許它只活在面試當中,實際工作當中你壓根不會用到它,但是你要知道它是什麼東西。