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