Classloader執(zhí)行流程
1.線程和協(xié)程的區(qū)別
線程(Thread):
線程是操作系統(tǒng)能夠進行運算調度的最小單位踱卵。它被包含在進程之中,是進程中的實際運作單位郑临。
每個線程可以獨立執(zhí)行栖博,有自己的調用堆棧和局部變量。
線程間的切換由操作系統(tǒng)內(nèi)核管理厢洞,涉及到上下文切換的成本仇让,包括保存和加載不同線程的狀態(tài)。
線程適用于執(zhí)行長時間的計算密集型任務犀变。
協(xié)程(Coroutine):
協(xié)程是一種輕量級的線程妹孙。它們通過協(xié)作而非搶占式的方式進行切換,即協(xié)程需要顯式地進行切換获枝。
協(xié)程運行在單個線程中蠢正,因此不需要多線程的同步機制,如鎖省店,這減少了開銷嚣崭。
協(xié)程提供了非常有效的異步編程模型笨触,可以在等待操作(如 I/O)完成時掛起,這樣可以處理大量并發(fā)的操作而不占用多個線程雹舀。
區(qū)別
1. 調度方式
線程:由操作系統(tǒng)內(nèi)核進行調度和管理芦劣,線程的切換需要內(nèi)核介入,開銷較大说榆。
協(xié)程:由用戶態(tài)的調度器進行調度虚吟,協(xié)程的切換在用戶態(tài)完成,開銷較小签财。
2. 資源消耗
線程:每個線程都需要獨立的棿浚空間和內(nèi)核資源,線程數(shù)量受到系統(tǒng)限制唱蒸。
協(xié)程:協(xié)程共享線程的棸铞辏空間,資源消耗較小神汹,可以在一個線程中運行成千上萬個協(xié)程庆捺。
3. 編程模型
線程:編程模型相對復雜,需要處理線程同步屁魏、死鎖等問題滔以。
協(xié)程:編程模型簡單,通過掛起和恢復操作實現(xiàn)協(xié)作式多任務處理蚁堤,避免了復雜的同步問題醉者。
4. 并發(fā)性
線程:真正的并行執(zhí)行,適合計算密集型任務披诗,CPU密集型任務撬即。
協(xié)程:協(xié)作式并發(fā),適合I/O密集型任務呈队,通過主動讓出CPU實現(xiàn)并發(fā)剥槐。
5. 控制權
線程:操作系統(tǒng)控制線程的執(zhí)行和調度。
協(xié)程:程序員控制協(xié)程的執(zhí)行流程宪摧,通過顯式的掛起和恢復操作進行調度粒竖。
2.kotlin和Java的對比
(1)代碼量:kotlin比Java代碼量少很多。kotlin通過使用簡潔的語法和函數(shù)式編程的概念來簡化java代碼几于,減少代碼的復雜性蕊苗。
(2)空指針安全:kotlin 通過引入空指針安全機制來避免空指針異常,而Java需要手動檢查null值沿彭。
(3)擴展函數(shù):kotlin中有一個強大的功能叫擴展函數(shù)朽砰,它允許用戶將一個已存在的類進行擴展
(4)函數(shù)式編程概念:kotlin 支持更多的函數(shù)式編程概念,比如lambda表達式、高階函數(shù)等
(5)數(shù)據(jù)類:kotlin 中引入了數(shù)據(jù)類瞧柔,它允許程序員快速創(chuàng)建簡單的數(shù)據(jù)類漆弄,這些數(shù)據(jù)類型可以自動生成一些有用的方法,如equals造锅、hashCode撼唾、toString等。這使得開發(fā)人員可以更快地創(chuàng)建和使用自定義數(shù)據(jù)類型哥蔚。倒谷。相比之下Java需要編寫大量的樣板代碼
(6)類型推斷
類型推斷是Kotlin的一個核心概念,它允許開發(fā)人員在聲明變量時不需要指定變量的類型糙箍,而是由編譯器根據(jù)變量的值自動推斷出變量的類型恨锚。這使得Kotlin的代碼更簡潔,更易于閱讀和維護倍靡。
總的來說kotlin 相對于Java擁有更簡潔的語法,更多的功能和更高的生產(chǎn)效率课舍,但是Java擁有更成熟的生態(tài)塌西,更廣泛的支持和更好的跨平臺支持。
(7)委托
委托是Kotlin的一個核心概念筝尾,它允許開發(fā)人員在一個類型上委托給另一個類型的屬性和方法捡需。這使得開發(fā)人員可以在不修改原始類型的情況下,為其添加新的功能筹淫。
擴展函數(shù)示例:
在 Kotlin 中站辉,擴展函數(shù)是一種非常有用的特性,它允許你為不屬于自己的類添加新的方法损姜。這在很多情況下非常有用饰剥,例如為標準庫中的類(如 String、List 等)添加額外的功能摧阅,或者給第三方庫的類添加功能汰蓉。
定義擴展函數(shù)
要定義一個擴展函數(shù),你需要使用 fun 關鍵字棒卷,后面跟著接收者類型(即你想要擴展的類)顾孽,然后是這個類型后面的點(.),接著是函數(shù)名和參數(shù)列表比规。
1若厚、示例:為 String 類添加一個擴展函數(shù)
fun String.capitalizeFirstLetter(): String {
? ? return this.substring(0, 1).toUpperCase() + this.substring(1)
}
在這個例子中,capitalizeFirstLetter 是為 String 類型添加的擴展函數(shù)蜒什。你可以像調用普通成員函數(shù)一樣調用它
val myString = "hello"
println(myString.capitalizeFirstLetter())? // 輸出 "Hello"
擴展函數(shù)與成員函數(shù)的區(qū)別
調用方式:擴展函數(shù)使用點符號(.)調用测秸,而成員函數(shù)直接通過對象調用。
可見性:擴展函數(shù)不能訪問接收者的私有成員框仔。成員函數(shù)可以訪問類的私有成員咳榜。
靜態(tài)分發(fā):擴展函數(shù)是靜態(tài)分派的,而成員函數(shù)是動態(tài)分派的(在運行時根據(jù)對象實際類型調用方法)实抡。
示例:為 List 添加擴展函數(shù)來計算總和
fun <T> List<T>.sumByInt(selector: (T) -> Int): Int {
? ? var sum = 0
? ? for (item in this) {
? ? ? ? sum += selector(item)
? ? }
? ? return sum
}
在這個例子中肃晚,sumByInt 是一個泛型擴展函數(shù)锚贱,用于對列表中的元素應用一個轉換函數(shù),并返回所有轉換結果的總和关串。
val numbers = listOf(1, 2, 3, 4)
println(numbers.sumByInt { it })? // 輸出 10
注意事項
命名沖突:如果你定義了一個與已有類的成員函數(shù)同名的擴展函數(shù)拧廊,那么在調用時將調用擴展函數(shù)而不是成員函數(shù)〗蓿可以通過使用導入限定符(如 String.capitalizeFirstLetter())來明確指定使用哪個函數(shù)吧碾。
性能考慮:雖然擴展函數(shù)很有用,但它們是通過代理對象實現(xiàn)的墓卦,這可能會帶來一些性能開銷倦春。在性能敏感的代碼中,應謹慎使用落剪。
擴展函數(shù)是 Kotlin 中一個強大且靈活的特性睁本,可以極大地增加代碼的可讀性和復用性。
數(shù)據(jù)類
數(shù)據(jù)類的一個例子是下面的代碼:
data class Person(val name:String,val age:Int)
fun main(args:Array<String>){
val person1=Person("Alice",30)
val person2=Person("Bob",25)
println(person1==person2)// false
println(person1.hashCode())// 123
println(person1.toString())// Person(name=Alice, age=30)}
在這個例子中忠怖,Person是一個數(shù)據(jù)類呢堰,它有兩個屬性:name和age。由于Person是一個數(shù)據(jù)類凡泣,編譯器會自動生成一些有用的方法枉疼,如equals、hashCode和toString鞋拟。我們可以直接在Person類型上調用這些方法骂维,而無需手動實現(xiàn)它們。
委托的一個例子:
class DelegatingClass(private val delegate):Any{
operatorfunget(property:KProperty<*>)=delegate.get(property)
operatorfunset(property:KProperty<*>,value:Any)=delegate.set(property,value)
}
fun main(args:Array<String>){
val delegate=object: Any(){
val name="Alice"
val age=30
}
val delegatingClass=DelegatingClass(delegate)
println(delegatingClass.name)// Alice
println(delegatingClass.age)// 30
}
在這個例子中贺纲,DelegatingClass是一個委托類席舍,它在構造函數(shù)中接受一個delegate參數(shù)。DelegatingClass實現(xiàn)了get和set操作符哮笆,這使得它可以委托給delegate的屬性和方法来颤。我們可以直接在DelegatingClass類型上調用name和age屬性,而無需手動實現(xiàn)它們稠肘。
3.多線程訪問修改list怎么保證數(shù)據(jù)安全
Android 中l(wèi)ist是線程不安全的福铅,意味著在多線程中同時訪問和修改list時,可能會導致不確定的結果和數(shù)據(jù)不一致性项阴。為了確保list的線程安全滑黔,可以采用以下方式
(1)使用同步集合類
? ? ? ? ? ? 在多線程環(huán)境下笆包,使用同步集合類保證list的線程安全性,Android 提供了Collections.synchronizedList()方法
? ? ? ? ? ? 例如:LIst<String> list = new ArrayList();
? ? ? ? ? ? List<String> synchronizedList = Collections.synchronizedList(list);
操作時還是需要手動進行同步
synchronized(list) {
}
(2) 使用并發(fā)集合類
? ? CopyOnWriteArrayList<String> concurrentList = new CopyOnWriteArrayList();
(3) 使用鎖機制 來保證list的線程安全性略荡, 可以使用 ReentrantLock 或者synchronized關鍵字來實現(xiàn)互斥訪問庵佣。
使用 synchronized 關鍵字
List<String> list = new ArrayList<>();
public void addElement(String element) {
? ? synchronized (list) {
? ? ? ? list.add(element);
? ? }
}
public String getElement(int index) {
? ? synchronized (list) {
? ? ? ? return list.get(index);
? ? }
}
使用 ReentrantLock
List<String> list = new ArrayList<>();
private final ReentrantLock lock = new ReentrantLock();
public void addElement(String element) {
? ? lock.lock();
? ? try {
? ? ? ? list.add(element);
? ? } finally {
? ? ? ? lock.unlock();
? ? }
}
public String getElement(int index) {
? ? lock.lock();
? ? try {
? ? ? ? return list.get(index);
? ? } finally {
? ? ? ? lock.unlock();
? ? }
}
4.okhttp攔截器
addInterceptor和addNetworkInterceptor
選擇使用 addInterceptor 還是 addNetworkInterceptor 時,取決于你希望攔截的網(wǎng)絡層級汛兜。
addInterceptor
方法用于攔截應用層級的請求和響應巴粪。這意味著它可以訪問應用程序發(fā)送的請求和服務器返回的響應,但不能訪問底層的網(wǎng)絡傳輸細節(jié)粥谬。通常情況下肛根,這足以滿足大多數(shù)的需求,比如添加身份驗證漏策、修改請求頭等派哲。
addNetworkInterceptor
方法用于攔截網(wǎng)絡層級的請求和響應。這意味著它可以訪問底層的網(wǎng)絡傳輸細節(jié)掺喻,包括請求和響應的字節(jié)流芭届。它可以用于監(jiān)視網(wǎng)絡流量、修改網(wǎng)絡傳輸行為或進行緩存控制感耙。但要注意喉脖,addNetworkInterceptor 方法不會攔截從緩存中提供的響應。
根據(jù)你的需求抑月,選擇適合的攔截器方法。如果你只需要訪問應用層級的請求和響應舆蝴,一般情況下使用 addInterceptor 就足夠了谦絮。如果你需要對網(wǎng)絡層級進行更深入的控制,可以使用 addNetworkInterceptor洁仗。需要注意的是层皱,在使用 addNetworkInterceptor 時,要謹慎處理請求和響應的字節(jié)流赠潦,以免引起潛在的問題叫胖。
時機
addInterceptor 和 addNetworkInterceptor 方法添加的攔截器在 OkHttp 中的調用時機略有不同:
addInterceptor 方法添加的攔截器在應用層級的調用時機是在請求發(fā)出后、服務器響應之前她奥。它會被應用于所有的網(wǎng)絡請求瓮增,包括重定向和重試的請求。在請求鏈中哩俭,每個攔截器的 intercept 方法會按照添加的順序依次被調用绷跑。
addNetworkInterceptor 方法添加的攔截器在網(wǎng)絡層級的調用時機是在請求發(fā)出后、服務器響應之前凡资,并且只會被調用一次砸捏。它可以訪問到底層的網(wǎng)絡傳輸細節(jié),如請求和響應的字節(jié)流。然而垦藏,addNetworkInterceptor 方法不會攔截從緩存中提供的響應梆暖。
5.點擊按鈕的事件分發(fā)
Android 的事件分發(fā)機制主要包括以下幾個步驟:
事件生成:用戶在設備上進行觸摸、滑動等操作時掂骏,系統(tǒng)會生成相應的事件轰驳,如觸摸事件(MotionEvent)。
事件發(fā)送:生成的事件會被發(fā)送到當前活動(Activity)或視圖(View)樹的根節(jié)點芭挽。
事件分發(fā):
Activity:首先滑废,事件會被傳遞給活動的 dispatchTouchEvent() 方法。這個方法決定如何將事件進一步分發(fā)袜爪。
ViewGroup:如果當前活動包含 ViewGroup(如 LinearLayout蠕趁、RelativeLayout 等),dispatchTouchEvent() 會先調用 ViewGroup 的 onInterceptTouchEvent() 方法辛馆。如果返回 true俺陋,則 ViewGroup 會處理事件;如果返回 false昙篙,則將事件傳遞給子視圖腊状。
View:對于普通的視圖(View),會調用其 onTouchEvent() 方法來處理事件苔可。
事件處理:
onTouchEvent():當視圖接收到事件后缴挖,會根據(jù)事件的類型(如按下、移動焚辅、抬起等)在此方法中處理相應的邏輯映屋。
事件處理過程可能涉及多個視圖,尤其是在有嵌套的視圖結構中同蜻。
事件消費:如果某個視圖處理了事件(返回 true)棚点,后續(xù)的視圖將不會再接收到這個事件。如果沒有視圖消費事件湾蔓,事件將向上傳遞瘫析,直到達到活動。
最終結果:處理完成后默责,結果可能會影響用戶界面的狀態(tài)或行為贬循。
注意事項:
onInterceptTouchEvent():在 ViewGroup 中使用,決定是否攔截子視圖的事件桃序。
事件的傳遞順序:從上到下(Activity → ViewGroup → View)甘有,處理順序是從下到上(View → ViewGroup → Activity)。
事件傳遞的對象:
事件在 Android 中主要在 Activity葡缰、ViewGroup 和 View 之間傳遞亏掀。
Activity 作為應用的入口忱反,首先接收事件;ViewGroup 可能根據(jù)需要攔截事件滤愕,而具體的 View 則負責執(zhí)行實際的事件處理温算。這種多層次的傳遞機制保證了事件處理的靈活性和精確性。
事件分發(fā)順序
Activity:當用戶觸摸屏幕時间影,事件首先被發(fā)送到當前的 Activity注竿。Activity 會調用其 dispatchTouchEvent() 方法,決定事件的后續(xù)處理魂贬。
ViewGroup:如果 Activity 的 dispatchTouchEvent() 方法未攔截事件巩割,事件將傳遞到 ViewGroup。ViewGroup 會執(zhí)行 onInterceptTouchEvent() 方法付燥,判斷是否攔截該事件宣谈。如果返回 true,則事件會在 ViewGroup 中處理键科;如果返回 false闻丑,事件會繼續(xù)傳遞到子視圖。
View:最終勋颖,事件將傳遞到具體的 View嗦嗡,在 View 中調用 onTouchEvent() 方法來處理事件。視圖可以根據(jù)事件的類型(如點擊饭玲、滑動等)執(zhí)行相應的邏輯侥祭。
事件分發(fā)過程中的方法
dispatchTouchEvent():
作用:負責分發(fā)觸摸事件。
調用時刻:當 Activity 或 ViewGroup 收到觸摸事件時首先調用茄厘。它決定事件是否繼續(xù)傳遞給子視圖或直接處理矮冬。
onInterceptTouchEvent():
作用:用于判斷 ViewGroup 是否攔截事件。
調用時刻:在 ViewGroup 的 dispatchTouchEvent() 內(nèi)部調用蚕断。通常用于處理復雜的觸摸交互,比如滑動或拖動入挣。
onTouchEvent():
作用:處理具體的觸摸事件亿乳。
調用時刻:在 dispatchTouchEvent() 內(nèi)部調用。用于執(zhí)行視圖的響應邏輯径筏,比如狀態(tài)更新葛假、動畫觸發(fā)等。
6滋恬、線程鎖
在Android應用程序中聊训,線程鎖是用于實現(xiàn)多線程同步和防止競爭條件(race condition)的重要工具。線程鎖通常用于確保在多個線程之間對共享資源的訪問進行協(xié)調恢氯,以避免并發(fā)問題带斑。
以下是Android中線程鎖的一些常見形式:
1.同步塊(Synchronized Blocks):
使用 synchronized 關鍵字可以創(chuàng)建同步塊鼓寺,確保只有一個線程可以進入同步塊內(nèi)部的代碼段。這通常用于保護共享資源勋磕,以防止多個線程同時訪問妈候。
例如:
synchronized(lockObject){// 同步的代碼塊}
2.同步方法(Synchronized Methods):
在方法聲明中使用 synchronized 關鍵字,將整個方法標記為同步挂滓。這使得只有一個線程可以同時訪問這個方法苦银。
例如:
publicsynchronizedvoidmySynchronizedMethod(){// 同步的方法體}
3.ReentrantLock:
ReentrantLock 是Java中的一個高級鎖機制,允許更靈活的鎖控制赶站。與 synchronized 不同幔虏,ReentrantLock 允許可中斷的鎖、超時的鎖等贝椿。
例如:
Locklock=newReentrantLock();lock.lock();// 獲得鎖try{// 同步的代碼塊}finally{lock.unlock();// 釋放鎖}
4.Condition:
Condition 是與 ReentrantLock 一起使用的想括,用于線程等待和通知。它可以用于創(chuàng)建更復雜的線程同步方案团秽,如生產(chǎn)者-消費者問題主胧。
例如:
Locklock=newReentrantLock();
Conditioncondition=lock.newCondition();
// 等待條件
condition.await();
// 通知條件
condition.signal();