Android 常見的問題整理 2022

Android 語音TTS 識別全鏈路過程

  • 本地錄音 =》 ASR識別 =》請求后臺語義 =》語義落域分發返回 =》 本地仲裁處理落域分發 =》 TTS播報
  • 下面是語音鏈路的一些基本思路
  1. 錄音 :Android基本錄音為48K的采樣率 語音這邊需要做降采樣處理 降采樣為16K。通過Android原生錄音將音頻給到引擎
  2. 喚醒:一般喚醒都是做本地喚醒,所有wakeup喚醒引擎。也可以通過喚醒引擎做一些免喚醒功能
  3. 語音識別,識別分為兩種:
    3.1 離線識別,走本地識別引擎,
    優點:識別快
    缺點:需要精準識別,并不能做太多泛化處理。對音頻要求比較高
    3.2 在線識別,走云端識別引擎
    優點 :可以模糊匹配,多泛化
    缺點 :網路查的情況下識別很慢
  4. 云端與離線云端技能分發
  5. TTS播報:由云端或本地接收文本進行語音音頻合成。進行播報

Android 屏幕適配相關,方案

    1. 通過dp加上自適應布局可以基本解決屏幕碎片化的問題。也是Android推薦使用的屏幕兼容性適配方案。
    1. 根據ui設計圖的寬度dp值,算出當前屏幕每dp占當前屏幕多少像素值(也就是density)。
    1. 根據ui設計圖的寬度dp值,算出當前屏幕分成ui設計圖的寬高度dp份后,每dp占當前屏幕實際多少dp,然后這個實際dp值再根dpi轉換成具體的像素值。
    1. 自定義像素適配,以美工的設計尺寸為原始尺寸,根據不同設備的密度 計算出寬和高 參考UIAdapter。如果想顯示屏幕的1/3的話就是360了寬度,是根據設計師給出來的寬度進行設置
    1. 百分比適配。這是Google 提出來的一個解決適配方案,想要使用必須添加依賴
 implementation 'com.android.support:percent:28.0.0'

主要就是兩個類
PercentRelativeLayout PercentFrameLayout

多線程,線程池 相關

  1. 線程的創建,線程創建的常用方法
  • 1.繼承Thread重寫run方法
  • 2.實現Runnable重寫run方法
  • 3.實現Callable重寫call方法
    1.3 實現Callable重寫call方法
    實現Callable和實現Runnable類似,但是功能更強大
    可以在任務結束后提供一個返回值,Runnable不行
    call方法可以拋出異常,Runnable的run方法不行
    可以通過運行Callable得到的Fulture對象監聽目標線程調用call方法的結果,得到返回值,(fulture.get(),調用后會阻塞,直到獲取到返回值)
  1. Android中的四類線程池
    1. Android中最常見的四類具有不同特性的線程池分別為FixThreadPool、CachedThreadPool、ScheduleThreadPool和SingleThreadExecutor
    1. FixThreadPool(一堆人排隊上公廁)
public static ExecutorService newFixThreadPool(int nThreads){
    return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
}
//使用
Executors.newFixThreadPool(5).execute(r);
  1. 從配置參數來看,FixThreadPool只有核心線程,并且數量固定的,也不會被回收,所有線程都活動時,因為隊列沒有限制大小,新任務會等待執行。
  2. FixThreadPool其實就像一堆人排隊上公廁一樣,可以無數多人排隊,但是廁所位置就那么多,而且沒人上時,廁所也不會被拆遷
  3. 由于線程不會回收,FixThreadPool會更快地響應外界請求,這也很容易理解,就好像有人突然想上廁所,公廁不是現用現建的
    1. SingleThreadPool(公廁里只有一個坑位)
public static ExecutorService newSingleThreadPool (int nThreads){
    return new FinalizableDelegatedExecutorService ( new ThreadPoolExecutor (1, 1, 0, TimeUnit. MILLISECONDS, new LinkedBlockingQueue<Runnable>()) );
}
//使用
Executors.newSingleThreadPool ().execute(r);
  1. 從配置參數可以看出,SingleThreadPool只有一個核心線程,確保所有任務都在同一線程中按順序完成。因此不需要處理線程同步的問題。
  2. 可以把SingleThreadPool簡單的理解為FixThreadPool的參數被手動設置為1的情況,即Executors.newFixThreadPool(1).execute(r)。所以SingleThreadPool可以理解為公廁里只有一個坑位,先來先上。為什么只有一個坑位呢,因為這個公廁是收費的,收費的大爺上年紀了,只能管理一個坑位,多了就管不過來了(線程同步問題)
    1. CachedThreadPool(一堆人去一家很大的咖啡館喝咖啡)
public static ExecutorService newCachedThreadPool(int nThreads){
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit. SECONDS, new SynchronousQueue<Runnable>());
}
//使用
Executors.newCachedThreadPool().execute(r);
  1. CachedThreadPool只有非核心線程,最大線程數非常大,所有線程都活動時,會為新任務創建新線程,否則利用空閑線程(60s空閑時間,過了就會被回收,所以線程池中有0個線程的可能)處理任務。
  2. 任務隊列SynchronousQueue相當于一個空集合,導致任何任務都會被立即執行。
  3. CachedThreadPool就像是一堆人去一個很大的咖啡館喝咖啡,里面服務員也很多,隨時去,隨時都可以喝到咖啡。但是為了響應國家的“光盤行動”,一個人喝剩下的咖啡會被保留60秒,供新來的客人使用,哈哈哈哈哈,好惡心啊。如果你運氣好,沒有剩下的咖啡,你會得到一杯新咖啡。但是以前客人剩下的咖啡超過60秒,就變質了,會被服務員回收掉。
  4. 比較適合執行大量的耗時較少的任務。喝咖啡人挺多的,喝的時間也不長
    1. ScheduledThreadPool(4個里面唯一一個有延遲執行和周期重復執行的線程池)
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize){
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize){
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedQueue ());
}
//使用,延遲1秒執行,每隔2秒執行一次Runnable r
Executors. newScheduledThreadPool (5).scheduleAtFixedRate(r, 1000, 2000, TimeUnit.MILLISECONDS);
  1. 核心線程數固定,非核心線程(閑著沒活干會被立即回收)數沒有限制。
  2. 從上面代碼也可以看出,ScheduledThreadPool主要用于執行定時任務以及有固定周期的重復任務。

Handler 介紹

  • 由于Android中主線程是不能進行耗時操作的,子線程是不能進行更新UI的。所以就有了handler,它的作用就是實現線程之間的通信。 handler整個流程中,主要有四個對象,handlerMessage,MessageQueue, Looper。當應用創建的時候,就會在主線程中創建handler對象, 我們通過要傳送的消息保存到Message中,handler.post handler通過調用sendMessage方法將Message發送到MessageQueue中,Looper對象就會不斷的調用loop()方法 不斷的從MessageQueue中取出Message交給handler進行處理。從而實現線程之間的通信

說下 handler 原理

  • Handler,Message,looper 和 MessageQueue 構成了安卓的消息機制,handler創建后可以通過 sendMessage 將消息加入消息隊列,然后 looper不斷的將消息從 MessageQueue 中取出來,回調到 Hander 的 handleMessage方法,從而實現線程的通信。
  1. 在UI線程創建Handler,此時我們不需要手動開啟looper,因為在應用啟動時,在ActivityThread的main方法中就創建了一個當前主線程的looper,并開啟了消息隊列,消息隊列是一個無限循環,為什么無限循環不會ANR ? 因為應用的整個生命周期就是運行在這個消息循環中的,安卓是由事件驅動的,Looper.loop不斷的接收處理事件,每一個點擊觸摸或者Activity每一個生命周期都是在Looper.loop的控制之下的,looper.loop一旦結束,應用程序的生命周期也就結束了。我們可以想想什么情況下會發生ANR,第一,事件沒有得到處理
  2. 事件正在處理,但是沒有及時完成,而對事件進行處理的就是looper,所以只能說事件的處理如果阻塞會導致ANR,而不能說looper的無限循環會ANR。
    另一種情況就是在子線程創建Handler,此時由于這個線程中沒有默認開啟的消息隊列,所以我們需要手動調用looper.prepare(),并通過looper.loop開啟消息
  3. 主線程Looper從消息隊列讀取消息,當讀完所有消息時,主線程阻塞。子線程往消息隊列發送消息,并且往管道文件寫數據,主線程即被喚醒,從管道文件讀取數據,主線程被喚醒只是為了讀取消息,當消息讀取完畢,再次睡眠。因此loop的循環并不會對CPU性能有過多的消耗

Activity A跳轉Activity B,再按返回鍵,生命周期執行的順序?

  • A.onPause() B.onCreate() B.onStart() B.onResume() A.onStop()
  • 另外 如果Activity B是透明的 或者Activity B 并未完全遮住Activity A,那么上述操作點擊Activity A 跳轉 Activity B 生命周期中A.onStop()是不會被調用的,因為Activity A還可見,所以Activity A不能被停止

View 的繪制流程

  • Activity、Window、DecorView之間關系
 public void setContentView(@LayoutRes int layoutResID) {
        //  將xml布局傳遞到Window當中
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }
  1. 從代碼可以看出,Activity的setContentView實質是將View傳遞到Window的setContentView()方法中,Window的setContenView會在內部調用installDecor()方法創建DecorView
  2. View的繪制是從ViewRootImpl的performTraversals()方法開始,從最頂層的View(ViewGroup)開始逐層對每個View進行繪制操作
  • measure:為測量寬高過程,如果是ViewGroup還要在onMeasure中對所有子View進行measure操作。
  • layout:用于擺放View在ViewGroup中的位置,如果是ViewGroup要在onLayout方法中對所有子View進行layout操作。
  • draw:往View上繪制圖像。
  1. View 的繪制流程是 measure -> layout -> draw

View 事件分發機制

  1. View 的事件分發機制主要涉及到以下幾個方法
  • dispatchTouchEvent ,這個方法主要是用來分發事件的
  • onInterceptTouchEvent,這個方法主要是用來攔截事件的(需要注意的是 ViewGroup 才有這個方法,View 沒有 onInterceptTouchEvent 這個方法
  • onTouchEvent 這個方法主要是用來處理事件的
  • requestDisallowInterceptTouchEvent(true),這個方法能夠影響父View是否攔截事件,true 表示父 View 不攔截事件,false 表示父 View 攔截事件
  1. 當觸摸事件發生時,首先 Activity 將 TouchEvent 傳遞給最頂層的 View,TouchEvent最先到達最頂層 view 的 dispatchTouchEvent,然后由 dispatchTouchEvent方法進行分發,

如果dispatchTouchEvent返回true 消費事件,事件終結。
如果dispatchTouchEvent返回 false ,則回傳給父View的onTouchEvent事件處理;

如果dispatchTouchEvent返回super的話,默認會調用自己的onInterceptTouchEvent方法。

默認的情況下onInterceptTouchEvent回調用super方法,super方法默認返回false,所以會交給子View的onDispatchTouchEvent方法處理
如果 interceptTouchEvent 返回 true ,也就是攔截掉了,則交給它的 onTouchEvent 來處理,
如果 interceptTouchEvent 返回 false ,那么就傳遞給子 view ,由子 view 的 dispatchTouchEvent 再來開始這個事件的分發。

Activity 四種啟動模式
  1. standard : 默認啟動模式,每開啟一個activity就在任務棧中創建一個新的實例.Top single 頂部只有一個 不允許存在兩個相同的Activity.使用場景:基本絕大多數地方都可以用。
  2. singleTop: 如果在任務的棧頂正好存有該 Activity的實例,則會通過調用 onNewIntent() 方法進行重用,否則就會同 standard 模式一樣,創建新的實例并放入棧頂。即便棧中已經存在了該 Activity 的實例,也會創建新的實例
    當且僅當啟動的 Activity 和上一個 Activity 一致的時候才會通過調用 onNewIntent()方法重用 Activity 。使用場景:資訊閱讀類 APP 的內容界面。
  3. singleTask : 在同一個任務棧中,如果要啟動的目標Activity已經在棧中,則會復用該Activity,并調用其onNewIntent()方法,并且該Activity上面的Activity會被清除,如果棧中沒有,則創建新的實例。使用場景:瀏覽器的主頁面,或者大部分 APP 的主頁面。
  4. singleInstance: 指定為singleInstance模式的活動會啟用一個新的返回棧來管理這個活動。在一個新棧中創建該 Activity 的實例,并讓多個應用共享該棧中的該 Activity 實例。一旦該模式的 Activity 實例已經存在于某個棧中,任何應用再激活該 Activity 時都會重用該棧中的實例,是的,依然是調用 onNewIntent()方法。其效果相當于多個應用共享一個應用,不管是誰激活,該 Activity 都會進入同一個應用中。但值得引起注意的是:singleInstance 不要用于中間頁面,如果用戶中間頁面,跳轉會出現很難受的問題。 這個在實際開發中我暫未遇到過, Android 系統的來電頁面,多次來電都是使用的同一個 Activity

Service啟動方式

  1. startService. startService() 啟動一個 Service。一旦啟動,Service 將一直運行在后臺,即使啟動這個 Service 的組件已經被銷毀。通常一個被 start 的 Service 會在后臺執行單獨的操作,也并不需要給啟動它的組件返回結果。只有當 Service 自己調用 stopSelf() 或者其它組件調用 stopService() 才會終止。
  2. **bindService **. bindService() 來綁定一個 Service。這種方式會讓 Service 和啟動它的組件綁定在一起,當啟動它的組件銷毀的時候,Service 也會自動進行 unBind 操作。同一個 Service 可以被多個組件綁定,只有所有綁定它的組件都進行了 unBind 操作,這個 Service 才會被銷毀
  3. Service 的生命周期
  • 當調用 startService() 去 start 一個 Service 后,仍然可以 bind 這個 Service。比如:當播放音樂的時候,需要調用 startService() 啟動指定的音樂,當需要獲取該音樂的播放進度的時候,又需要調用 bindService(),在這種情況下,除非 Service 被 unbind,此前調用 stopService() 和 stopSelf() 都不能停止該 Service

  • 完整生命周期(entire lifetime):從 onCreate() 被調用,到 onDestroy() 返回。和 Activity 類似,一般在 onCreate() 方法中做一些初始化的工作,在 onDestroy() 中做一些資源釋放的工作。如,若 Service 在后臺播放一個音樂,就需要在 onCreate() 方法中開啟一個線程啟動音樂,并在 onDestroy() 中結束線程。

  • 活動生命周期(activity lifetime):從 onStartCommand() 或 onBind() 回調開始,由相應的 startService() 或 bindService() 調用。start 方式的活動生命周期結束就意味著完整證明周期的結束,而 bind 方式,當 onUnbind() 返回后,Service 的活動生命周期結束。

  • 是 startService() 還是 bindService() 啟動 Service,onCreate() 和 onDestroy() 均會被回調

Service 的 onCreate() 可以執行耗時操作嗎?

  • Service 運行在主線程中,它并不是一個新的線程,也不是新的進程,所以并不能執行耗時操作。

如果要在 Service 中執行耗時操作,怎么做?

  1. 使用 AysncTask 或 HandlerThread 來替代 Thread 創建線程。
  2. IntentService 繼承于 Service,若 Service 不需要同時處理多個請求,那么使用 IntentService 將是最好選擇。只需要重寫 onHandleIntent() 方法,該方法接收一個回調的 Intent 參數, 在方法內進行耗時操作,因為它默認開啟了一個子線程,操作執行完成后也無需手動調用 stopSelf() 方法,onHandleIntent() 將會自動調用該方法

Service 與 IntentService區別

  1. Service 不是運行在獨立的線程,所以不建議在Service中編寫耗時的邏輯和操作,否則會引起ANR。
  2. IntentService
  • 可用于執行后臺耗時的任務,任務執行后會自動停止。
  • 具有高優先級,適合高優先級的后臺任務,且不容易被系統殺死。
  • 可以多次啟動,每個耗時操作都會以工作隊列的方式在IntentService的onHandleIntent回調方法中執行

Serializable 和Parcelable的區別

  • 平臺區別。Serializable是屬于 Java 自帶的,表示一個對象可以轉換成可存儲或者可傳輸的狀態,序列化后的對象可以在網絡上進行傳輸,也可以存儲到本地。
    Parcelable 是屬于 Android 專用。不過不同于Serializable,Parcelable實現的原理是將一個完整的對象進行分解。而分解后的每一部分都是Intent所支持的數據類型。
  • 編寫上的區別。Serializable代碼量少,寫起來方便
    Parcelable代碼多一些,略復雜
  • 選擇的原則
  1. 如果是僅僅在內存中使用,比如activity、service之間進行對象的傳遞,強烈推薦使用Parcelable,因為Parcelable比Serializable性能高很多。因為Serializable在序列化的時候會產生大量的臨時變量, 從而引起頻繁的GC。
  2. 如果是持久化操作,推薦Serializable,雖然Serializable效率比較低,但是還是要選擇它,因為在外界有變化的情況下,Parcelable不能很好的保存數據的持續性。
  • 本質的區別
  1. Serializable的本質是使用了反射,序列化的過程比較慢,這種機制在序列化的時候會創建很多臨時的對象,比引起頻繁的GC、
  2. Parcelable方式的本質是將一個完整的對象進行分解,而分解后的每一部分都是Intent所支持的類型,這樣就實現了傳遞對象的功能了

Serializable中為什么要設置UID,設置UID與不設置UID值的區別和影響 ?

  • serialVersionUID 是用來輔助序列化和反序列化的過程。 序列化后的數據中的serialVersionUID只有和當前類的serialVersionUID一致才能成功的反序列化
  • serialVersionUID 適用于java序列化機制。簡單來說,JAVA序列化的機制是通過判斷類的serialVersionUID來驗證的版本一致的。在進行反序列化時,JVM會把傳來的字節流中的serialVersionUID于本地相應實體類的serialVersionUID進行比較。如果相同說明是一致的,可以進行反序列化,否則會出現反序列化版本一致的異常,即是InvalidCastException。
  • 具體序列化的過程 :序列化操作時會把系統當前類的serialVersionUID寫入到序列化文件中,當反序列化時系統會自動檢測文件中的serialVersionUID,判斷它是否與當前類中的serialVersionUID一致。如果一致說明序列化文件的版本與當前類的版本是一樣的,可以反序列化成功,否則就失敗;
  • serialVersionUID有兩種顯示的生成方式:
  1. 默認的1L,比如:private static final long serialVersionUID = 1L;
  2. 根據包名,類名,繼承關系,非私有的方法和屬性,以及參數,返回值等諸多因子計算得出的,極度復雜生成的一個64位的哈希字段。基本上計算出來的這個值是唯一的。比如:private static final long serialVersionUID = xxxxL;
    注意:顯示聲明serialVersionUID可以避免對象不一致

內存泄漏的場景和解決辦法

  1. 非靜態內部類的靜態實例
    非靜態內部類會持有外部類的引用,如果非靜態內部類的實例是靜態的,就會長期的維持著外部類的引用,組織被系統回收,解決辦法是使用靜態內部類
  2. 多線程相關的匿名內部類和非靜態內部類
    匿名內部類同樣會持有外部類的引用,如果在線程中執行耗時操作就有可能發生內存泄漏,導致外部類無法被回收,直到耗時任務結束,解決辦法是在頁面退出時結束線程中的任務
  3. Handler內存泄漏
    Handler導致的內存泄漏也可以被歸納為非靜態內部類導致的,Handler內部message是被存儲在MessageQueue中的,有些message不能馬上被處理,存在的時間會很長,導致handler無法被回收,如果handler是非靜態的,就會導致它的外部類無法被回收,解決辦法是1.使用靜態handler,外部類引用使用弱引用處理2.在退出頁面時移除消息隊列中的消息
  4. Context導致內存泄漏
    根據場景確定使用Activity的Context還是Application的Context,因為二者生命周期不同,對于不必須使用Activity的Context的場景(Dialog),一律采用Application的Context,單例模式是最常見的發生此泄漏的場景,比如傳入一個Activity的Context被靜態類引用,導致無法回收
  5. 靜態View導致泄漏
    使用靜態View可以避免每次啟動Activity都去讀取并渲染View,但是靜態View會持有Activity的引用,導致無法回收,解決辦法是在Activity銷毀的時候將靜態View設置為null(View一旦被加載到界面中將會持有一個Context對象的引用,在這個例子中,這個context對象是我們的Activity,聲明一個靜態變量引用這個View,也就引用了activity)
  6. WebView導致的內存泄漏
    WebView只要使用一次,內存就不會被釋放,所以WebView都存在內存泄漏的問題,通常的解決辦法是為WebView單開一個進程,使用AIDL進行通信,根據業務需求在合適的時機釋放掉
  7. 資源對象未關閉導致
    如Cursor,File等,內部往往都使用了緩沖,會造成內存泄漏,一定要確保關閉它并將引用置為null
  8. 集合中的對象未清理
    集合用于保存對象,如果集合越來越大,不進行合理的清理,尤其是入股集合是靜態的
  9. Bitmap導致內存泄漏
    bitmap是比較占內存的,所以一定要在不使用的時候及時進行清理,避免靜態變量持有大的bitmap對象
  10. 監聽器未關閉
    很多需要register和unregister的系統服務要在合適的時候進行unregister,手動添加的listener也需要及時移除

EventBus原理

  1. 主要是維護了幾個數組,然后根據對應的key找到對應的注冊對象,通過放射的方式調用對應的方法。
  2. EventBus 2.x 是采用反射的方式對整個注冊的類的所有方法進行掃描來完成注冊,當然會有性能上的影響。EventBus 3.0 中EventBus提供了EventBusAnnotationProcessor注解處理器來在編譯期通過讀取@Subscribe()注解并解析、處理其中所包含的信息,然后生成java類來保存所有訂閱者關于訂閱的信息,這樣就比在運行時使用反射來獲得這些訂閱者的信息速度要快
/注冊事件
EventBus.getDefault().register(this);
//注冊方法
@Subscribe
public void event(BaseEventBusBeaan message) {
  LogUtils.d("EventBusActivity event");
}
 
//發送事件
EventBus.getDefault().post(new BaseEventBusBeaan("123", new Bundle()));
 
//反注冊
EventBus.getDefault().unregister(this);

總結一下大概的流程

  1. 通過apt在編譯期將所有被 @Subscribe注解的函數添加到MyEventBusIndex對象中。
  2. register過程中生成subscriptionsByEventType的數據。
  3. post過程中通過subscriptionsByEventType數據查找對應的函數,然后再通過反射的方式調用。

優先級的問題

這個問題也十分簡單,只需要在插入數據的時候,做下優先級判斷即可。

Android 熱更新 流程和原理

  • 一個完整的項目應該有如下分支:
    develop分支---- 這個分支中放的是線上的發布版本。
    bugfix分支---- 這個是熱更新分支,由develop中遷出。
    master分支---- 這個是開發中的分支
  • 熱更新應當按照如下步驟進行:
  1. 線上檢測到嚴重的crash
  2. 從develop中拉出一個線上的最新版,在bugfix分支上進行問題的修復
  3. jenkins構建和補丁的生成
  4. app通過推送或主動拉取補丁文件
  5. 將bugfix代碼合到master上,保證以后不會出現該問題
  • 主流熱更新框架介紹
  1. Dexposed :該框架是阿里巴巴開源的一個Android平臺下的無侵入的運行時AOP(面向方向編程)框架。基于以前開源的一個Xposed框架實現的。Dexposed框架基于Hook技術實現功能,不僅可以hook你自己的程序代碼,也可以hook你的應用程序中調用的Android框架中的函數。基于動態類加載技術,運行中的app可以加載一小段經過編譯的Java的代碼,而且在不需要重寫APP的前提下,就可以實現修改APP
  2. AndFix:該框架同樣出自阿里。與Dexposed不是同一個團隊。AndFix也是基于Xposed思想。而相比第一個,它是一個更純粹的熱修復的框架。
  3. Nuwa:它其實是基于類加載器ClassLoader加載Dex文件。如果多個Dex文件存在相同的類,那么排在前面的Dex文件就將優先被選擇。這是熱更新最主要的思想,它通過不斷地去輪詢,去遍歷Dex的一個數組,然后把我們需要修改的類的dex文件加到最前面,這樣當輪詢遍歷時就不會加載有問題的那個類。
  • 熱更新的原理
  1. Android的類加載機制 :Android的類加載器主要有這樣兩個:PathClassLoader和DexClassLoader。PathClassLoader主要用于加載系統的類和應用類,DexClassLoader主要加載Dex文件,Jar文件,apk文件等。
  2. 熱修復機制:在BaseClassLoader中會創建一個dexElements數組,然后我們會通過ClassLoader遍歷這個數組,加載這個數組中的dex文件。這樣當BaseClassLoader加載到正確的類以后,就不會去加載有Crash的那個類。因此我們就將這個有問題修復后的類放入Dex文件當中,讓這個Dex文件排在dexElements前面。這樣BaseClassLoader就不會加載到處于后面的那個Dex文件。這樣就完成了整個熱修復過程。

Android線程間通信四種方式:

    1. 通過Handler機制
      主線程中定義Handler,子線程發消息,通知Handler完成UI更新,Handler對象必須定義在主線程中,如果是多個類直接互相調用,就不是很方便,需要傳遞content對象或通過接口調用。另外Handler機制與Activity生命周期不一致的原因,容易導致內存泄漏,不推薦使用。
    1. runOnUiThread方法,用Activity對象的runOnUiThread方法更新,在子線程中通過runOnUiThread()方法更新UI,強烈推薦使用。
  • 3.View.post(Runnable r)這種方法更簡單,但需要傳遞要更新的View過去,推薦使用
    1. AsyncTask,即異步任務,是Android給我們提供的一個處理異步任務的類.通過此類,可以實現UI線程和后臺線程進行通訊,后臺線程執行異步任務,并把結果返回給UI線程

Android中有哪些進程間通信方式?

  • Binder 簡單易用 只能傳輸Bundle支持的數據類型 四大組件間的進程間通信
    文件共享 簡單易用 不適用高并發場景,并且無法做到進程間即時通信 適用于無關發的情況下,交換簡單的數據,對實時性要求不高的場景。
  • AIDL功能強大,支持一對多實時并發通信 使用稍復雜,需要處理好線程間的關系 一對多通信且有RPC需求
  • Messenger功能一般,支持一對多串行通信,支持實時通信 不能很好地處理高并發的情形,不支持RPC,由于數據通過Message傳輸,因此只能傳輸Bundle支持的數據類型 低并發的一對多實時通信,無RPC需求,或者無需要返回結果的RPC需求
    -ContentProvider支持一對多的實時并發通信,在數據源共享方面功能強大,可通過Call方法擴展其它操作 可以理解為受約束的AIDL,主要提供對數據源的CRUD操作 一對多的進程間數據共享
  • BroadcastReceiver操作簡單,對持一對多實時通信 只支持數據單向傳遞,效率低且安全性不高 一對多的低頻率單向通信
  • Socket功能強大,可通過網絡傳輸字節流,支持一對多實時并發通信 實現細節步驟稍繁瑣,不支持直接的RPC 網絡間的數據交換

websocket 和 http相關

    1. 什么是 websocket
      websocketHTML5的一種新協議,允許服務器想客戶端傳遞信息,實現瀏覽器和客戶端雙工通信。
    1. websocket特點
      (1)與http協議有良好的兼容性;
      (2)建立在TCP協議之上,和http協議同屬于應用層;
      (3)數據格式比較輕量,性能開銷小,通信高效;
      (4)可以發送文本,也可以發送二進制;
      (5)沒有同源限制,可以與任意服務器通信。
    1. httpwebsocket的區別
      3.1 http協議是短鏈接,因為請求之后,都會關閉連接,下次請求需要重新打開鏈接。
      3.2 websocket協議是一種長連接,只需要通過一次請求來初始化連接,然后所有請求和響應都是通過TCP鏈接進行通信。
    1. 特點
      最大特點就是,服務器可以主動向客戶端推送信息,客戶端也可以主動向服務器發送信息,是真正的雙向平等對話,屬于服務器推送技術的一種。
      其他特點包括:
      (1)建立在 TCP 協議之上,服務器端的實現比較容易。
      (2)與 HTTP 協議有著良好的兼容性。默認端口也是80和443,并且握手階段采用 HTTP 協議,因此握手時不容易屏蔽,能通過各種 HTTP 代理服務器。
      (3)數據格式比較輕量,性能開銷小,通信高效。
      (4)可以發送文本,也可以發送二進制數據。
      (5)沒有同源限制,客戶端可以與任意服務器通信。
      (6)協議標識符是ws(如果加密,則為wss),服務器網址就是 URL

持續更新中 ...

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
禁止轉載,如需轉載請通過簡信或評論聯系作者。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,055評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,365評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,346評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,889評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,118評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,637評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,558評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,739評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,980評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,347評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,702評論 2 370

推薦閱讀更多精彩內容