dispatchTouchEvent 分發事件 onInterceptTouchEvent 攔截事件只有viewgroup纔有,view和activity沒 onTouchEvent 處理點擊事件java
Handler主要負責發送和接受消息,Looper負責不斷輪詢MessageQueue,有新的消息就交給Handler處理,若是輪詢不到新的消息,那就自身就處於阻塞狀態。 Handler簡單圖解linux
詳解單個handler原理android
圖解多個handler原理三個架構模式:面試
Mvc和mvp的最主要區別:
Mvc中model能夠直接和view交互
mvp中model 與view 的交互由presenter完成
複製代碼
mvc是指用戶觸發事件的時候,view層會發送指令到controller層,而後controller去通知model層更新數據,model層更新完數據後會直接在view層顯示結果。 對android來講 activity幾乎承擔了view層和controller層兩種角色,而且和model層耦合嚴重,在邏輯複雜的界面維護起來很麻煩。算法
mvp模式下的activity只承擔了view層的角色,controller的角色徹底由presenter負責,view層和presenter層的通訊經過接口實現,因此VP之間不存在耦合問題,view層與model也是徹底解耦了。 presenter複用度高,能夠隨意搬到任何界面。 mvp模式下還方便測試維護: 可是mvp的問題在於view層和presenter層是經過接口鏈接,在複雜的界面中,維護過多接口的成本很大。shell
Mvvm 的優勢: 1,和mvp同樣,方便進行單元測試 2,便於代碼的移植設計模式
Mvvm的缺點 1,類會增多 2,viewModel會愈來愈龐大 3,調用複雜度增長數組
圖片的三級緩存:也就是加載圖片的時候首先從內存緩存中取,若是沒有再從文件緩存中取, 若是文件緩存沒有取到,就從網絡下載圖片而且加入內存和文件緩存 LRU:Least Recently Used,最近最少使用算法。當內存緩存達到設定的最大值 時將內存緩存中近期最少使用的對象移除,有效的避免了OOM的出現。緩存
LruCache中Lru算法:經過LinkedHashMap來實現的。LinkedHashMap繼承於HashMap,它使用了一個雙向鏈表來存儲Map中的Entry順序關係,這種順序有兩種, 一種是LRU順序, 一種是插入順序, 這能夠由其構造函數安全
public LinkedHashMap(int initialCapacity,float loadFactor, boolean accessOrder)指定
複製代碼
因此,對於get、put、remove等操做,LinkedHashMap除了要作HashMap作的事情,還作些調整Entry順序鏈表的工做。 LruCache中將LinkedHashMap的順序設置爲LRU順序來實現LRU緩存,每次調用get(也就是從內存緩存中取圖片),則將該對象移到鏈表的尾端。調用put插入新的對象也是存儲在鏈表尾端,這樣當內存緩存達到設定的最大值時,將鏈表頭部的對象(近期最少用到的)移除
部分源碼解析:LruCache的初始化構造方法
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
//初始容量爲零,0.75是加載因子,
表示容量達到最大容量的75%的時候會
把內存增長一半。最後這個參數相當重要
表示訪問元素的排序方式,true表示按照
訪問順序排序,false表示按照插入的順序排序
}
複製代碼
LinkedHashMap底層數據結構由鏈表和哈希表組成。由鏈表保證元素有序。由哈希表保證元素惟一
1,按插入順序排序(默認) 2,訪問順序排序(lru是這種排序) LinkedHashMap重寫了父類HashMap的get方法,實際在調用父類getEntry()方法取得查找的元素後,再判斷當排序模式accessOrder爲true時,記錄訪問順序,將最新訪問的元素添加到雙向鏈表的表頭,並從原來的位置刪除。因爲的鏈表的增長、刪除操做是常量級的,故並不會帶來性能的損失
1,原理 HashMap的原理:hashmap本質數組加鏈表。根據key取得hash值,而後計算出數組下標,若是多個key對應到同一個下標,就用鏈表串起來,新插入的在前面 ConcurrentHashMap原理:在hashMap的基礎上,ConcurrentHashMap將數據分爲多個segment(相似HashTable),默認16個(concurrency level),而後每次操做對一個segment加鎖,避免多線程鎖得概率,提升併發效率
2,Hashmap的源碼: 構造函數,空參或者單參時都會調用兩個參數的
public HashMap(int initialCapacity, float loadFactor) {
int capacity = 1;
while (capacity < initialCapacity)
capacity <<= 1;
this.loadFactor = loadFactor;
threshold = (int)(capacity * loadFactor);
table = new Entry[capacity];
init();
}
複製代碼
有3個關鍵參數: capacity:容量,就是數組大小 loadFactor:比例,用於擴容 threshold:=capacity*loadFactor 最多容納的Entry數,若是當前元素個數多於這個就要 擴容(capacity擴大爲原來的2倍)
Get方法:根據key算hash值,再根據hash值取得數組下標,經過數組下標取出鏈表,遍歷鏈表用equals取出對應key的value
public V get(Object key) {
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e.value;
}
return null;
}
複製代碼
3,HashMap和ConcurrentHashMap,hashtable的區別
HashMap:線程不安全,效率高
ConcurrentHashMap:線程安全,效率高,默認提高16倍
Hashtable:線程安全,效率低
複製代碼
四,SparseArray原理 SparseArray是android裏爲<Interger,Object>這樣的Hashmap而專門寫的類,目的是提升內存效率,其核心是折半查找函數(binarySearch)。注意內存二字很重要,由於它僅僅提升內存效率,而不是提升執行效率 它要比 HashMap 節省內存,結構比HashMap簡單(SparseArray內部主要使用兩個一維數組來保存數據,一個用來存key,一個用來存value)不須要額外的數據結構(主要是針對HashMap中的HashMapEntry而言的)。
當全部的服務都啓動完畢後,SystemServer會打印出「Making services ready」,而後經過ActivityManager啓動Home界面,併發送「ACTION_BOOT_COMPLETED」廣播消息
app的兩種啓動方式
系統會從新建立一個新的進程分配給它,因此會先建立和初始化Application類,再建立和初始化MainActivity類(包括一系列的測量、佈局、繪製),最後顯示在界面上
進程在後臺運行,因此熱啓動就不會走Application這步了,而是直接走MainActivity(包括一系列的測量、佈局、繪製),因此熱啓動的過程只須要建立和初始化一個MainActivity就好了,而沒必要建立和初始化Application,由於一個應用重新進程的建立到進程的銷燬,Application只會初始化一次。
用戶點擊app後會通知 ActivityManagerService 啓動應用的入口 Activity, ActivityManagerService 發現這個應用還未啓動,則會通知 Zygote 進程孵化出應用進程,而後在這個應用進程裏執行 ActivityThread 的 main 方法。應用進程接下來通知 ActivityManagerService 應用進程已啓動,ActivityManagerService 保存應用進程的一個代理對象,這樣 ActivityManagerService 能夠經過這個代理對象控制應用進程,而後 ActivityManagerService 通知應用進程建立入口 Activity 的實例,並執行它的生命週期函數。
上面的啓動流程是 Android 提供的機制,咱們只能在建立入口 Activity 的實例這裏作文章,正常Main Activity 的啓動流程:
-> Application 構造函數
-> Application.attachBaseContext()
-> Application.onCreate()
-> Activity 構造函數
-> Activity.setTheme()
-> Activity.onCreate()
-> Activity.onStart
-> Activity.onResume
-> Activity.onAttachedToWindow
-> Activity.onWindowFocusChanged
複製代碼
統計app啓動時長的兩種方式
adb shell am start -w packagename/activity 輸入adb shell am start -W
com.qcl/com.qcl.MainActivity獲得下面結果
Activity: com.qcl/.MainActivity
ThisTime: 83
TotalTime: 83
WaitTime: 94
TotalTime是咱們真正的啓動時間
複製代碼
開始時間: 冷啓動在Application的attachBaseContext 熱啓動在入口activity的onRestart中 結束時間:在入口activity的onWindowFocusChanged
基於上面的啓動流程咱們儘可能作到以下幾點
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:screenOrientation">portrait</item>
<item name="android:windowBackground">>@mipmap/splash</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
</style>
複製代碼
設置透明Theme 經過把樣式設置爲透明,程序啓動後不會黑屏而是整個透明瞭,等到界面初始化完才一次性顯示出來
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:screenOrientation">portrait</item>
</style>
複製代碼
Theme1 程序啓動快,界面先顯示背景圖,而後再刷新其餘界面控件。給人刷新不一樣步感受。 Theme2 給人程序啓動慢感受,界面一次性刷出來,刷新同步
當application在Linux平臺開啓時,系統會給這個application建立一個進程(process)來運行同時分配內存資源給該application,當程序結束運行時,該進程結束系統回收內存資源。 一個Application就是一個應用,在應用啓動時,android會啓動一個linux進程和一個主線程,這個進程以應用的包名命名,在默認的狀況下,這個Application下的Activity、service、provider、receiver等組件都在這個進程中運行
1,convertView複用
2,viewholder使用
3,圖片優化
4,getView()中不要寫過多的邏輯代碼,不要建立不少的對象,邏輯代碼放在別的地方,
5,item的佈局減小層級
6,經過getItemViewType實現複雜佈局的複用
7,簡單佈局能夠將listview的scrollingCache和animateCache屬性設置false。
若是設置爲true會提升顯示效果,可是須要消耗更多內存和更長的初始化時間
複製代碼
基本解決了ListView的一些缺陷,好比:須要手動重寫ViewHolder,對於item的動畫操做也須要很複雜的邏輯去實現等等 可是也有些缺點 不能簡單的加頭和尾 2. 不能簡單的設置子item的點擊事件 因此對於一些簡單的列表仍是能夠用listview的。Recylerview能夠用於實現一些複雜的列表。
優化 1,簡化item佈局 2,圖片優化
JVM是Java Virtual Machine(Java虛擬機)的縮寫,JVM是一種用於計算設備的規範,它是一個虛構出來的計算機。 JVM在執行字節碼時,實際上最終仍是把字節碼解釋成具體平臺上的機器指令執行
(1)做用
JVM:保證Java語言跨平臺
JRE:Java程序的運行環境
JDK:Java程序的開發環境
(2)關係
JDK:JRE+工具
JRE:JVM+類庫
簡單而言:使用JDK開發完成的Java程序,交給JRE去運行,由JVM來保證跨平臺。
複製代碼
方法區有如下特色
1,方法區是線程安全的。
二、方法區的大小沒必要是固定的,JVM可根據應用須要動態調整。
三、方法區也可被垃圾收集,當某個類不在被使用(不可觸及)時,JVM將卸載這個類,進行垃圾收集
複製代碼
棧--主要存放引用和基本數據類型。
堆--用來存放 new 出來的對象實例和數組。
每一個方法被執行的時候都會同時建立一個棧幀(Stack Frame)用於存儲局部變量表、操做棧、動態連接、方法出口等信息。 每個方法被調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中從入棧到出棧的過
垃圾回收:主要是對gc堆即Young Generation(年輕代)塊和Old Generation(年老代)塊內存進行回收,YG用來放新產生的對象,通過幾回回收還沒回收掉的對象往OG中移動,對YG進行垃圾回收又叫作MinorGC,對 OG垃圾回收又叫MajorGC,兩塊內存回收互不干涉
更細的劃分爲Eden和2個survivor space(即倖存區)
Dalvik是Google公司本身設計用於Android平臺的Java虛擬機
Dalvik和jvm的區別 Dalvik是基於寄存器的,運行dex文件 JVM是基於棧的,運行java字節碼
Art:空間換時間 art模式須要在程序安裝時進行預編譯,將apk編譯解析成機器碼,運行速度相比dalvik模式快。 缺點:安裝時間稍長,因爲進行了預編譯,因此會產生機器碼,會佔用存儲空間。
通常狀況下直接使用餓漢式就行了,若是明確要求要懶加載(lazy initialization)會傾向於使用靜態內部類,若是涉及到反序列化建立對象時會試着使用枚舉的方式來實現單例。
Public class Singleton{
Private static final Singleton instance=new Singleton();
Private Singleton(){}
Public static Singleton getInstance(){
Return instance;
}
}
複製代碼
Public class Singleton{
Private static class SingletonHolder{
Private static final Singleton INSTANCE=new Singleton();
}
Private Singleton(){}
Public static final Singleton getInstance(){
Return SingletonHolder.INSTANCE;
}
}
複製代碼
Public enum Singleton{
INSTANCE;
}
複製代碼
多進程的意義? 提升CPU的使用率 多線程的意義? 提升應用程序的使用率
1,繼承Thread類,
2,實現Runnable接口(推薦,方便的實現資源的共享)
3,經過Callable和Future建立線程
複製代碼
3,start和run方法的區別 start會先啓動線程,再由jvm調用run方法 run方法只是thread的一個普通方法調用,仍是在主線程裏執行。
4,線程池 程序啓動一個新線程成本比較高,由於它涉及到要與操做系統進行交互,而使用線程池能夠很好的提升性能,尤爲是當程序要建立大量生存期很短的線程時,更應該使用線程池。 線程池裏的每個線程代碼結束後,並不會死亡,而是再次回到線程池中成爲空閒狀態,等待下一個對象來使用。 JKD5以前,咱們手動實現本身的線程池,JDK5之後,java內置支持線程池。
代碼演示 //建立一個線程池對象,控制要建立幾個線程對象
ExecutorService pool=Executors.newFixedThreadPool(2);
//能夠執行Runnable對象或者Callable對象的線程
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
//結束線程池
pool.shutdown();
複製代碼
1)Lock是一個接口,jdk5後出現,而synchronized是Java中的關鍵字,synchronized是內置的語言實現;
2)synchronized在發生異常時,會自動釋放線程佔有的鎖,所以不會致使死鎖現象發生;而Lock在發生異常時,若是沒有主動經過unLock()去釋放鎖,則極可能形成死鎖現象,所以使用Lock時須要在finally塊中釋放鎖;
3)Lock可讓等待鎖的線程響應中斷,而synchronized卻不行,使用synchronized時,等待的線程會一直等待下去,不可以響應中斷;
4)經過Lock能夠知道有沒有成功獲取鎖,而synchronized卻沒法辦到。
5)Lock能夠提升多個線程進行讀操做的效率。
複製代碼
在性能上來講,若是競爭資源不激烈,二者的性能是差很少的,而當競爭資源很是激烈時(即有大量線程同時競爭),此時Lock的性能要遠遠優於synchronized。因此說,在具體使用時要根據適當狀況選擇
6,volatile關鍵字 volatile關鍵字修飾變量,用來確保將變量的更新操做通知到其餘線程 在訪問volatile變量時不會執行加鎖操做,所以也就不會使執行線程阻塞,所以volatile變量是一種比sychronized關鍵字更輕量級的同步 一旦一個共享變量(類的成員變量、類的靜態成員變量)被volatile修飾以後,那麼就具有了兩層語義: 1)保證了不一樣線程對這個變量進行操做時的可見性,即一個線程修改了某個變量的值,這新值對其餘線程來講是當即可見的。 2)禁止進行指令重排序
7,ThreadLocal ThreadLocal類的做用:是爲每一個線程都建立一個變量副本, 每一個線程均可以修改本身所擁有的變量副本, 而不會影響其餘線程的副本. 其實這也是解決線程安全的問題的一種方法。在不少狀況下,ThreadLocal比直接使用synchronized同步機制解決線程安全問題更簡單,更方便,且結果程序擁有更高的併發性 ThreadLocal原理:在ThreadLocal類中有一個Map,用於存儲每個線程的變量副本。
8,死鎖 死鎖就是指兩個或者兩個以上的線程在執行過程當中,因爭奪資源產生的一種相互等待現象。(好比兩我的吃飯,一人一根筷子)
嵌套的代碼體現
if(x>20){
synchronized(a){
synchronized(b){...}
}
}else{
synchronized(b){
synchronized(a){...}
}
}
複製代碼
AsyncTask是對Handler與線程池的封裝,AsyncTask的本質是一個線程池,全部提交的異步任務都會在這個線程池中的工做線程內執行,當工做線程須要跟UI線程交互時,工做線程會經過向在UI線程建立的Handler傳遞消息的方式,調用相關的回調函數,從而實現UI界面的更新
1,SP是進程同步的嗎?有什麼方法作到同步? Android自己的SP能夠支持多進程,可是SP不能保證多進程間同步。由於當多個進程同時而又高頻的調用SP的commit方法時,就會致使文件被反覆覆蓋寫入,而並無被及時讀取,因此形成進程間數據的不一樣步 Android的ContentProvider是支持進程同步的,能夠利用ContentProvider進行進程的sp同步 進程間通訊的四種方式
1,Activity Activity的跨進程訪問與進程內訪問略有不一樣。雖然它們都須要Intent對象,但跨進程訪問並不須要指定Context對象和Activity的 Class對象,而須要指定的是要訪問的Activity所對應的Action(一個字符串)。有些Activity還須要指定一個Uri(經過 Intent構造方法的第2個參數指定)。 在android系統中有不少應用程序提供了能夠跨進程訪問的Activity,例如,下面的代碼能夠直接調用撥打電話的Activity。 Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:12345678" ); startActivity(callIntent);
2,Content Provider 能夠跨進程訪問其餘應用程序中的數據(以Cursor對象形式返回),固然,也能夠對其餘應用程序的數據進行增、刪、改操 做
3,廣播 能夠向android系統中全部應用程序發送廣播,而須要跨進程通信的應用程序能夠監聽這些廣播
4,AIDL Service和Content Provider相似,也能夠訪問其餘應用程序中的數據,但不一樣的是,Content Provider返回的是Cursor對象,而Service返回的是Java對象,這種能夠跨進程通信的服務叫AIDL服務
1,android 色彩模式說明:
ALPHA_8: 每一個像素佔用1byte內存。
ARGB_4444: 每一個像素佔用2byte內存
ARGB_8888: 每一個像素佔用4byte內存
RGB_565: 每一個像素佔用2byte內存
複製代碼
假設一張10241024,模式爲ARGB_8888的圖片,那麼它佔有的內存就是:10241024*4 = 4MB Android默認的色彩模式爲ARGB_8888,一般咱們優化Bitmap時,當須要作性能優化或者防止OOM(Out Of Memory),咱們一般會使用Bitmap.Config.RGB_565這個配置,由於Bitmap.Config.ALPHA_8只有透明度,顯示通常圖片沒有意義,Bitmap.Config.ARGB_4444顯示圖片不清楚,Bitmap.Config.ARGB_8888佔用內存最多
if (!bmp.isRecycle()) {
bmp.recycle(); //回收圖片所佔的內存
bitmap = null;
system.gc(); //提醒系統及時回收
}
複製代碼
雖然調用recycle()並不能保證當即釋放佔用的內存,可是能夠加速Bitmap的內存的釋放。 釋放內存之後,就不能再使用該Bitmap對象了,若是再次使用,就會拋出異常。因此必定要保證再也不使用的時候釋放。好比,若是是在某個Activity中使用Bitmap,就能夠在Activity的onStop()或者onDestroy()方法中進行回收