阿里百度騰訊常見java和安卓面試題彙總

安卓部分

一,view的事件分發機制

dispatchTouchEvent 分發事件 onInterceptTouchEvent 攔截事件只有viewgroup纔有,view和activity沒 onTouchEvent 處理點擊事件java

  • 1,圖解ACTION_DOWN 事件分發,若是面試的時候能把下面的圖畫出來。能增分很多 dispatchTouchEvent和 onTouchEvent的框裏有個【true---->消費】的字,表示的意思是若是方法返回true,那麼表明事件就此消費,不會繼續往別的地方傳了,事件終止

  • 2,紅色的箭頭表明ACTION_DOWN 事件的流向 藍色的箭頭表明ACTION_MOVE 和 ACTION_UP 事件的流向

二,Handler原理機制

Handler主要負責發送和接受消息,Looper負責不斷輪詢MessageQueue,有新的消息就交給Handler處理,若是輪詢不到新的消息,那就自身就處於阻塞狀態。 Handler簡單圖解linux

Handler鐵三角

  • Handler android的消息機制就是指Handler機制,Handler機制的運行須要MeeageQueue和Looper的輔助。 λ MessageQueue:消息隊列,用於將全部收到的消息以隊列的形式進行排列, 並提供入隊和出隊的方法。在looper的構造函數中建立,所以一個Looper也就對應了一個MessageQueue. 經過enqueueMessage實現消息的入隊,經過next方法實現出隊
  • Looper 輪詢器 做用:與當前線程綁定,保證一個線程只會有一個Looper實例,同時一個Looper實例也只有一個- MessageQueue。Looper 經過loop()方法調用messagequeue的next方法,不斷從 MessageQueue中去取消息

詳解單個handler原理android

圖解多個handler原理

Handler的建立流程

  • 一、首先Looper.prepare()在本線程中保存一個Looper實例,而後該實例中保存一個MessageQueue對象;由於Looper.prepare()在一個線程中只能調用一次,因此MessageQueue在一個線程中只會存在一個。
  • 二、Looper.loop()會讓當前線程進入一個無限循環,不端從MessageQueue的實例中讀取消息,而後回調msg.target.dispatchMessage(msg)方法。
  • 三、Handler的構造方法,會首先獲得當前線程中保存的Looper實例,進而與Looper實例中的MessageQueue想關聯。
  • 四、Handler的sendMessage方法,會給msg的target賦值爲handler自身,而後加入MessageQueue中。
  • 五、在構造Handler實例時,咱們會重寫handleMessage方法,也就是msg.target.dispatchMessage(msg)最終調用的方法。 好了,總結完成,你們可能還會問,那麼在Activity中,咱們並無顯示的調用Looper.prepare()和Looper.loop()方法,爲啥Handler能夠成功建立呢,這是由於在Activity的啓動代碼中,已經在當前UI線程調用了Looper.prepare()和Looper.loop()方法。

四,mvc,mvp,mvvm

三個架構模式:面試

  • MVC:Model-View-Controller,經典模式,很容易理解,主要缺點有兩個: 1,View對Model的依賴,會致使View也包含了業務邏輯; 2,Controller會變得很厚很複雜。
  • MVP:Model-View-Presenter,MVC的一個演變模式,將Controller換成了Presenter, 主要爲了解決上述第一個缺點,將View和Model解耦, 不過第二個缺點依然沒有解決。
  • MVVM:Model-View-ViewModel,是對MVP的一個優化模式, 採用了雙向綁定:View的變更,自動反映在ViewModel,反之亦然。 MVC, MVP, MMVM用來解決業務邏輯和視圖之間的耦合
Mvc和mvp的最主要區別:
Mvc中model能夠直接和view交互
mvp中model	與view	的交互由presenter完成
複製代碼

Mvc,mvp,mvvm的優缺點

  • 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,調用複雜度增長數組

一,LRUCache原理和部分源碼解析

圖片的三級緩存:也就是加載圖片的時候首先從內存緩存中取,若是沒有再從文件緩存中取, 若是文件緩存沒有取到,就從網絡下載圖片而且加入內存和文件緩存 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詳解

LinkedHashMap底層數據結構由鏈表和哈希表組成。由鏈表保證元素有序。由哈希表保證元素惟一

LinkedHashMap的兩種排序

1,按插入順序排序(默認) 2,訪問順序排序(lru是這種排序) LinkedHashMap重寫了父類HashMap的get方法,實際在調用父類getEntry()方法取得查找的元素後,再判斷當排序模式accessOrder爲true時,記錄訪問順序,將最新訪問的元素添加到雙向鏈表的表頭,並從原來的位置刪除。因爲的鏈表的增長、刪除操做是常量級的,故並不會帶來性能的損失

三,HashMap和ConcurrentHashMap的原理

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而言的)。

五,系統啓動流程

Zygote進程 –> SystemServer進程 –> 各類系統服務 –> 應用進程

當全部的服務都啓動完畢後,SystemServer會打印出「Making services ready」,而後經過ActivityManager啓動Home界面,併發送「ACTION_BOOT_COMPLETED」廣播消息

六,App啓動、Application生命週期

app的兩種啓動方式

1,冷啓動

系統會從新建立一個新的進程分配給它,因此會先建立和初始化Application類,再建立和初始化MainActivity類(包括一系列的測量、佈局、繪製),最後顯示在界面上

2,熱啓動

進程在後臺運行,因此熱啓動就不會走Application這步了,而是直接走MainActivity(包括一系列的測量、佈局、繪製),因此熱啓動的過程只須要建立和初始化一個MainActivity就好了,而沒必要建立和初始化Application,由於一個應用重新進程的建立到進程的銷燬,Application只會初始化一次。

App啓動流程

用戶點擊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啓動時長的兩種方式

1,本地經過adb命令行

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是咱們真正的啓動時間
複製代碼
2,經過收集log(能夠用來獲取線上啓動時間)

開始時間: 冷啓動在Application的attachBaseContext 熱啓動在入口activity的onRestart中 結束時間:在入口activity的onWindowFocusChanged

app的啓動優化:

基於上面的啓動流程咱們儘可能作到以下幾點

  • 1.Application的建立過程當中儘可能少的進行耗時操做
  • 2.若是用到SharePreference,儘可能在異步線程中操做
  • 3.減小布局的層次,而且生命週期回調的方法中儘可能減小耗時的操做
app啓動碰見黑屏或者白屏問題
  • 1,產生緣由  其實顯示黑屏或者白屏實屬正常,這是由於還沒加載到佈局文件,就已經顯示了window窗口背景,黑屏白屏就是window窗口背景
  • 2,解決辦法 經過設置設置Style  (1)設置背景圖Theme  經過設置一張背景圖。 當程序啓動時,首先顯示這張背景圖,避免出現黑屏
<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和Process進程

當application在Linux平臺開啓時,系統會給這個application建立一個進程(process)來運行同時分配內存資源給該application,當程序結束運行時,該進程結束系統回收內存資源。 一個Application就是一個應用,在應用啓動時,android會啓動一個linux進程和一個主線程,這個進程以應用的包名命名,在默認的狀況下,這個Application下的Activity、service、provider、receiver等組件都在這個進程中運行

Application的生命週期

  • 一、onCreate() 在建立應用程序時建立
  • 二、onTerminate() 在模擬環境下執行。當終止應用程序對象時調用,不保證必定被調用,當程序是被內核終止以便爲其餘應用程序釋放資源,那麼將不會提醒,而且不調用應用程序的對象的onTerminate方法而直接終止進程。
  • 三、onLowMemory() 低內存時執行。好的應用程序通常會在這個方法裏面釋放一些沒必要要的資源來應付當後臺程序已經終止,前臺應用程序內存還不夠時的狀況。 四、onConfigurationChanged(Configuration newConfig) 配置改變時觸發這個方法。 五、onTrimMemory(int level)程序在進行內存清理時執行​

七,listview優化

1,convertView複用
2,viewholder使用
3,圖片優化
4,getView()中不要寫過多的邏輯代碼,不要建立不少的對象,邏輯代碼放在別的地方,
5,item的佈局減小層級
6,經過getItemViewType實現複雜佈局的複用
7,簡單佈局能夠將listview的scrollingCache和animateCache屬性設置false。
若是設置爲true會提升顯示效果,可是須要消耗更多內存和更長的初始化時間
複製代碼

八,RecycleView

基本解決了ListView的一些缺陷,好比:須要手動重寫ViewHolder,對於item的動畫操做也須要很複雜的邏輯去實現等等 可是也有些缺點 不能簡單的加頭和尾  2. 不能簡單的設置子item的點擊事件 因此對於一些簡單的列表仍是能夠用listview的。Recylerview能夠用於實現一些複雜的列表。

優化 1,簡化item佈局 2,圖片優化

九,JVM內存模型

1,什麼是jvm

JVM是Java Virtual Machine(Java虛擬機)的縮寫,JVM是一種用於計算設備的規範,它是一個虛構出來的計算機。 JVM在執行字節碼時,實際上最終仍是把字節碼解釋成具體平臺上的機器指令執行

2,JDK,JRE,JVM的做用及關係

(1)做用
	JVM:保證Java語言跨平臺
	JRE:Java程序的運行環境
	JDK:Java程序的開發環境
(2)關係
	JDK:JRE+工具
	JRE:JVM+類庫
簡單而言:使用JDK開發完成的Java程序,交給JRE去運行,由JVM來保證跨平臺。
複製代碼

3,java代碼具體執行過程以下圖

4,jvm內存結構圖(即運行時數據區)

  • 程序計數器:是一塊較小的內存空間,能夠看做是當前線程所執行的字節碼的 行號指示器。爲了可以使得每一個線程都在線程切換後可以恢復在切換以前 的程序執行位置,每一個線程都須要有本身獨立的程序計數器,而且不能互相 被幹擾,獨立存儲。 若是正在執行的是一個java方法,記錄的是正在執行的虛擬機字節碼指令的地址 若是正在執行的是個native方法,這個計數器的值爲空。
  • 虛擬機棧:爲虛擬機執行java方法(字節碼)服務。 這裏咱們用的比較多的是局部變量表 局部變量表所需的內存空間在編譯期間完成分配。當進入一個方法時,這個方法須要在幀中分配多大的局部變量空間是徹底肯定的。在方法運行期間不會改變局部變量表的大小。
  • 本地方法棧:爲虛擬機執行本地方法服務。 本地方法棧與虛擬機棧發揮的做用很是類似。區別以下 虛擬機棧:爲虛擬機執行java方法(字節碼)服務 本地方法棧:爲虛擬機使用到的native方法服務
  • 堆:是用來存儲對象自己的以及數組(數組引用是存放在Java棧中的)。堆是被全部 線程共享的,在JVM中只有一個堆。是java虛擬機管理的內存最大的一塊。 在虛擬機啓動時建立,
  • 方法區:和堆同樣,是各個線程共享的內存區域,用於存儲已被虛擬機加載的類信息, 常量,靜態變量和即時編譯器編譯後的代碼數據等。這個區域的內存回收主要是針對 常量池的回收和對類型的卸載。
方法區有如下特色 
1,方法區是線程安全的。
二、方法區的大小沒必要是固定的,JVM可根據應用須要動態調整。
三、方法區也可被垃圾收集,當某個類不在被使用(不可觸及)時,JVM將卸載這個類,進行垃圾收集
複製代碼

堆和棧的主要區別:

棧--主要存放引用和基本數據類型。

堆--用來存放 new 出來的對象實例和數組。

線程和jvm

每一個方法被執行的時候都會同時建立一個棧幀(Stack Frame)用於存儲局部變量表、操做棧、動態連接、方法出口等信息。 每個方法被調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中從入棧到出棧的過

5,JVM執行程序的過程

  1. 加載.class文件
  2. 管理並分配內存
  3. 執行垃圾收集

6,jvm的生命週期

  • a) 啓動。啓動一個Java程序時,一個JVM實例就產生了,任何一個擁有public static void main(String[] args)函數的class均可以做爲JVM實例運行的起點
  • b) 運行。main()做爲該程序初始線程的起點,任何其餘線程均由該線程啓動。JVM內部有兩種線程:守護線程和非守護線程,main()屬於非守護線程,守護線程一般由JVM本身使用,java程序也能夠代表本身建立的線程是守護線程
  • c) 消亡。當程序中的全部非守護線程都終止時,JVM才退出;若安全管理器容許,程序也可使用Runtime類或者System.exit()來退出

十,GC的回收策略(垃圾回收策略機制)

垃圾回收:主要是對gc堆即Young Generation(年輕代)塊和Old Generation(年老代)塊內存進行回收,YG用來放新產生的對象,通過幾回回收還沒回收掉的對象往OG中移動,對YG進行垃圾回收又叫作MinorGC,對 OG垃圾回收又叫MajorGC,兩塊內存回收互不干涉

更細的劃分爲Eden和2個survivor space(即倖存區)

  • 1.eden空間: 大部分新對象在這裏分配,有些大對象直接在年老區分配,這個區域進行回收後不少狀況下會變空。
    1. two survivor 空間:即from survivor和to survivor。當eden區滿時會將仍然存活的對象複製至其中一個survivor區,當這個區又滿時將複製至另一個survivor區,以下圖:

十一,畫出 Android 的大致架構圖

十二,Dalvik,ART和jvm

Dalvik是Google公司本身設計用於Android平臺的Java虛擬機

Dalvik和jvm的區別 Dalvik是基於寄存器的,運行dex文件 JVM是基於棧的,運行java字節碼

Art:空間換時間 art模式須要在程序安裝時進行預編譯,將apk編譯解析成機器碼,運行速度相比dalvik模式快。 缺點:安裝時間稍長,因爲進行了預編譯,因此會產生機器碼,會佔用存儲空間。

十三,阿里面試手寫單例模式

通常狀況下直接使用餓漢式就行了,若是明確要求要懶加載(lazy initialization)會傾向於使用靜態內部類,若是涉及到反序列化建立對象時會試着使用枚舉的方式來實現單例。

  • 1,餓漢式 會在加載類後一開始就被初始化,即便客戶端沒有調用 getInstance()方法。餓漢式的建立方式在一些場景中將沒法使用:譬如 Singleton 實例的建立是依賴參數或者配置文件的
Public class Singleton{
Private static final Singleton instance=new Singleton();
Private Singleton(){}
Public static Singleton getInstance(){
Return instance;
}
}
複製代碼
  • 2,靜態內部類 這種寫法仍然使用JVM自己機制保證了線程安全問題;因爲 SingletonHolder 是私有的,除了 getInstance() 以外沒有辦法訪問它,所以它是懶漢式的;同時讀取實例的時候不會進行同步,沒有性能缺陷;也不依賴 JDK 版本
Public class Singleton{
Private static class SingletonHolder{
Private static final Singleton INSTANCE=new Singleton();
}
Private Singleton(){}
Public static final Singleton getInstance(){
Return SingletonHolder.INSTANCE;
}
}
複製代碼
  • 3,枚舉Enum 咱們能夠經過EasySingleton.INSTANCE來訪問實例,這比調用getInstance()方法簡單多了。建立枚舉默認就是線程安全的,因此不須要擔憂double checked locking,並且還能防止反序列化致使從新建立新的對象
Public enum Singleton{
INSTANCE;
}
複製代碼

十四,安卓源碼中用到的設計模式

  • 1,單例模式 保證在應用程序中,一個類Class只有一個實例存在 軟鍵盤管理的 InputMethodManager和安卓系統級別的服務一般用的單例模 式,如WindowsManagerService、ActivityManagerService,更經常使用的是一個 LayoutInflater的類
  • 2,責任鏈模式---View事件分發機制 它使多個對象都有機會處理請求,從而避免了請求的發送者和接受者之間的 耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有對象 處理它爲止 具體體如今View的onTouchEvent方法中返回值的設置, 若是返回false,那麼意味着當前的View不會是該次的責任人,將不會對其 持有;若是返回true,此時View會持有該事件並再也不向外傳遞
  • 3,適配器模式----listview的BaseAdapter 將一個類的接口轉換成客戶但願的另一個接口 以筆記本電源適配器爲例,電源適配器將220V的電壓轉換到5v。
  • 4,觀察者模式---將被觀察者和觀察者解耦 觀察者模式是一種行爲類模式,它定義對象間一種一對多的依賴關係,使得每當一個對 象改變狀態,則全部依賴於它的對象都會獲得通知並被自動更新 DataSetObserver就是一個觀察者,它一旦發現BaseAdapter內部數據有變量,就會經過 回調方法DataSetObserver.onChanged和DataSetObserver.onInvalidated來通知 DataSetObserver的實現類。 好比安卓開源項目EventBus和rxjava的核心就是觀察者模式
  • 5,工廠模式----BitmapFactory 靜態工廠方法在Android中比較明顯的例子應該就是BitmapFactory了,經過各類decodeXXX()就能夠從不一樣渠道得到Bitmap對象
  • 6,建造者模式----AlertDialog.Builder 若是一個類的構造須要不少參數,並且這些參數並不都是必須的,那麼這種狀況下就比較適合Builder模式。好比構建一個AlertDialog,標題、內容、取消按鈕、肯定按鈕、中立按鈕,你可能只須要單獨設置幾個屬性便可
  • 7,策略模式----動畫的插值器 策略模式就至關於一個影碟機,你往裏面插什麼碟子,就能放出什麼電影 以動畫爲例,設置不一樣的插值器對象,就能夠獲得不一樣的變化曲線

十五,多線程相關

  • 1,進程和線程的區別 進程:表示一個運行的程序 線程:進程(程序)的執行單元,執行路徑

多進程的意義? 提升CPU的使用率 多線程的意義? 提升應用程序的使用率

  • 2,多線程的三種實現方式
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();
複製代碼
  • 5,synchronized與Lock的區別 synchronized關鍵字是防止多個線程同時執行一段代碼,那麼就會很影響程序執行效率 Lock和synchronized有如下幾點不一樣:
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的底層實現

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服務

十八,即時通信和推送的3種實現方案

  • 1,經過輪詢:太low,還消耗性能,消耗流量
  • 2,長鏈接:這個方案能夠解決由輪詢帶來的性能問題,可是仍是會消耗手機的電池 而且咱們本地的服務很容易被安卓系統在低內存時殺死。長鏈接須要依賴心跳機制
  • 3,採用MQTT協議實現Android推送:耗電量小 MQTT協議較之XMPP更爲輕量級,其鏈接的創建與傳輸的開銷都很是小,很是精簡,很是適合大量節點在弱網絡環境的場景,發佈/訂閱的模式也比較易於擴展 XMPP是PC時代的產物,其底層通信的數據格式的XML,數據冗餘性過高(約70%),比較耗流量,而且在複雜的移動網絡環境下會遇到各類各樣的問題。

十九,Bitmap相關

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佔用內存最多

  • 2,使用Bitmap時的一些注意事項 不用的Bitmap及時釋放
if (!bmp.isRecycle()) {
    bmp.recycle();   //回收圖片所佔的內存
    bitmap = null;
    system.gc();  //提醒系統及時回收
}
複製代碼

雖然調用recycle()並不能保證當即釋放佔用的內存,可是能夠加速Bitmap的內存的釋放。 釋放內存之後,就不能再使用該Bitmap對象了,若是再次使用,就會拋出異常。因此必定要保證再也不使用的時候釋放。好比,若是是在某個Activity中使用Bitmap,就能夠在Activity的onStop()或者onDestroy()方法中進行回收

  • 3,圓形bitmap的實現原理 主要靠paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));這行代碼實現圓形圖片 SRC_IN這種模式,取兩個繪製的效果疊加後的交集,第一個繪製的是個圓形,第二個繪製的是個Bitmap,因而交集爲圓形,展示的是BItmap,就實現了圓形圖片效果
相關文章
相關標籤/搜索