欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android利用ContentProvider初始化組件的踩坑記錄

 更新時間:2022年04月29日 10:37:33   作者:pumpkin的玄學(xué)  
做Android SDK開發(fā)的時候,一般我們會將初始化的方法封裝,然后讓調(diào)用SDK的開發(fā)者在Application的onCreate方法中進(jìn)行初始化,下面這篇文章主要給大家介紹了關(guān)于Android利用ContentProvider初始化組件的踩坑記錄,需要的朋友可以參考下

項(xiàng)目描述

先簡單描述一下遇到的問題。

項(xiàng)目比較龐大是以組件化的形式進(jìn)行構(gòu)建的,記錄崩潰日志是由專門的一個組件去做,這里且叫它c(diǎn)rash吧。而crash的核心邏輯如下:

//偽代碼
public class MyCrash implements UncaughtExceptionHandler {
    
    private static UncaughtExceptionHandler defaultUncaughtExceptionHandler;
    
    public static void init(String path) {
        ...
        //獲取到默認(rèn)的ExceptionHandler
        defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
        //設(shè)置自己的ExceptionHandler
        Thread.setDefaultUncaughtExceptionHandler(new MyCrash());
    }
    @Override    
    public void uncaughtException(Thread t, Throwable e) {
        try {
            //日志記錄邏輯
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //回調(diào)默認(rèn)的ExceptionHandler
            if (defaultUncaughtExceptionHandler != null) {
                defaultUncaughtExceptionHandler.uncaughtException(t, e);
            }
        }
    }
}

然后該組件利用ContentProvider進(jìn)行初始化,大概如下所示:

class MyContentProvider : ContentProvider() {
    override fun onCreate(): Boolean {
        //偽代碼,初始化。
        MyCrash.init("")
        return true
    }
    ......
}

問題排查

收到反饋說,部分手機(jī)不會記錄崩潰日志。這就是很奇怪了,因?yàn)槔碚撋蟻碚f,只要設(shè)置了ExceptionHandle都會捕獲到傳過來的異常呀。難道是沒有設(shè)置到ExceptionHandle?

后經(jīng)過斷點(diǎn)排查,不會上傳崩潰日志的手機(jī),在運(yùn)行階段Thread持有的defaultUncaughtExceptionHandler,不是我們設(shè)置的MyCrash,而是一個三方組件設(shè)置他們自己的CrashExceptionHandle且沒有回調(diào)我們的MyCrash,而他們也是利用ContentProvider初始化的。

所以這時候就牽扯到ContentProvider的初始化流程了,具體在ActivityThread中,下面放一下偽代碼。

ActivityThread
private void handleBindApplication(AppBindData data) {
    ...
    //1.獲取到Application
    app = data.info.makeApplication(data.restrictedBackupMode, null);
    ...
    //2.初始化ContentProvider
    installContentProviders(app, data.providers);
    ...
    //3.調(diào)用Application的onCreate
    mInstrumentation.callApplicationOnCreate(app);
    ...
}

整體順序是獲取Application->初始化ContentProvider->調(diào)用Application#onCreate。也就是說ContentProvider的初始化是要在Application之前的。其中ContentProvider的初始化就是循環(huán)便利儲存ContentProvider的集合調(diào)用它的onCreate方法。

private void installContentProviders(Context context, List<ProviderInfo> providers) {
    ...
    for (ProviderInfo cpi : providers) {
       //這里會獲取到ContentProvider,最終會調(diào)用到ContentProvider的attachInfo,在attachInfo中調(diào)用了onCreate
    }
    ...
}

那ContentProvider的初始化順序就很清晰明了了。而我們的問題是部分手機(jī)記錄不了,也就是說ContentProvider在集合中的順序是不可保證的,這樣才能解釋部分手機(jī)有問題,部分手機(jī)正常,那這個順序是怎么來的呢?

起初我想到順序是不是和合并后的AndroidManifest.xml文件里面注冊的ContentProvider節(jié)點(diǎn)順序有關(guān)系,隨后就將該想法排除,因?yàn)樯傻腁PK是一樣的,所以AndroidManifest.xml文件里面注冊的ContentProvider節(jié)點(diǎn)順序是一定的。而有問題的是部分手機(jī),所以一定不是這里的問題,沒辦法只能繼續(xù)查看源碼,看看ContentProvider究竟是如何讀到內(nèi)存中的。

經(jīng)過一番查找,發(fā)現(xiàn)ContentProvider的集合是從ComponentResolver中private final ArrayMap<ComponentName, ParsedProvider> mProviders = new ArrayMap<>();取得。由于涉及到得源碼比較多,這里就不一一列舉了,下面放上源碼大致的調(diào)用鏈

ActivityManagerService#attachApplicationLocked -> ActivityManagerService#generateApplicationProvidersLocked -> PackageManagerService#queryContentProviders -> ComponentResolver#queryProviders -> ActivityThread#bindApplication -> ActivityThread#handleBindApplication

我們注意一下重點(diǎn),ContentProvider得信息是被儲存在ArrayMap中得,而ArrayMap肯定是無法保證順序的呀。不了解ArrayMap的下面我簡單介紹一下,

ArrayMap是Google專門提供的key-value映射集合,主要為了解決HashMap浪費(fèi)控件的問題,在小數(shù)據(jù)量上性能不錯,但是它底層是用數(shù)組來著,利用二分查找,而二分查找的順序是根據(jù)hash值來的,默認(rèn)的hash值是通過System.identityHashCode(key)來進(jìn)行獲取的,而這玩意兒又和對象的地址有關(guān)系。所以不同的手機(jī)順序肯定就不一樣了。

到這里,問題就分析結(jié)束了,最終解決方案是,去除了利用ContentProvider的初始化機(jī)制,改在Application中直接進(jìn)行初始化。

總結(jié)

上面的問題雖然解決了,但是利用ContentProvider解耦初始化組件真的好嗎?直觀的有以下幾個問題。

  1. 內(nèi)存泄漏。初始化完成之后ContentProvider會被系統(tǒng)直接持有,無用,但也不刪除
  2. 無法保證組件初始化的順序。這個就是我們上面分析的問題
  3. 會拉長啟動時間。上面我們看到了,ContentProvider循環(huán)初始化完成之后,才會進(jìn)行Application#onCreate的調(diào)用,所以對于一些非必要在主線程初始化的組件,這無疑會拉長啟動時間。

不過如果非要去解耦組件初始化,可以看一看Jetpack startup組件,它也是利用ContentProvider去初始化的,但是它利用AndroidManifest.xml合并的功能最終會合并成一個ContentProvider,而且內(nèi)存維持有集合可以保證組件初始化順序。

總之一句話,不要濫用ContentProvider僅僅去做一個初始化。

到此這篇關(guān)于Android利用ContentProvider初始化組件踩坑的文章就介紹到這了,更多相關(guān)Android ContentProvider初始化組件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android使用Photoview實(shí)現(xiàn)圖片左右滑動及縮放功能

    Android使用Photoview實(shí)現(xiàn)圖片左右滑動及縮放功能

    這篇文章主要為大家詳細(xì)介紹了Android使用Photoview實(shí)現(xiàn)圖片左右滑動及縮放功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Kotlin中空判斷處理操作實(shí)例

    Kotlin中空判斷處理操作實(shí)例

    最近使用kotlin重構(gòu)項(xiàng)目,遇到了一個小問題,在Java中,可能會遇到判斷某個對象是否為空,為空執(zhí)行一段邏輯,不為空執(zhí)行另外一段邏輯,下面這篇文章主要給大家介紹了關(guān)于Kotlin中空判斷處理操作的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • 簡單實(shí)現(xiàn)Android文件上傳

    簡單實(shí)現(xiàn)Android文件上傳

    這篇文章主要為大家詳細(xì)介紹了如何簡單實(shí)現(xiàn)Android文件上傳的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • Android中給按鈕同時設(shè)置背景和圓角示例代碼

    Android中給按鈕同時設(shè)置背景和圓角示例代碼

    相信每位Android開發(fā)者們都遇到過給按鈕設(shè)置背景或者設(shè)置圓角的需求,但是如果要同時設(shè)置背景和圓角該怎么操作才是方便快捷的呢?這篇文章通過示例代碼給大家演示了Android中給按鈕同時設(shè)置背景和圓角的方法,有需要的朋友們可以參考借鑒。
    2016-10-10
  • Android實(shí)現(xiàn)閃屏及注冊和登錄界面之間的切換效果

    Android實(shí)現(xiàn)閃屏及注冊和登錄界面之間的切換效果

    這篇文章主要介紹了Android實(shí)現(xiàn)閃屏及注冊和登錄界面之間的切換效果,實(shí)現(xiàn)思路是先分別實(shí)現(xiàn)閃屏、注冊界面、登錄界面的活動,再用Intent將相關(guān)的活動連接起來,實(shí)現(xiàn)不同活動之間的跳轉(zhuǎn),對android 實(shí)現(xiàn)閃屏和界面切換感興趣的朋友一起看看吧
    2016-11-11
  • Android 圖片Bitmap的剪切的示例代碼

    Android 圖片Bitmap的剪切的示例代碼

    本篇文章主要介紹了Android 圖片Bitmap的剪切的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • Android 編程下的計(jì)時器代碼

    Android 編程下的計(jì)時器代碼

    在安卓 APP 的手機(jī)號注冊邏輯中,經(jīng)常會有將激活碼發(fā)送到手機(jī)的環(huán)節(jié),這個環(huán)節(jié)中絕大多數(shù)的應(yīng)用考慮到網(wǎng)絡(luò)延遲或服務(wù)器壓力以及短信服務(wù)商的延遲等原因,會給用戶提供一個重新獲取激活碼的按鈕
    2013-08-08
  • Android實(shí)現(xiàn)圓形純數(shù)字按鈕

    Android實(shí)現(xiàn)圓形純數(shù)字按鈕

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)圓形純數(shù)字按鈕,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-02-02
  • Mac中配置gradle環(huán)境及使用android studio打包jar包與arr包的方法

    Mac中配置gradle環(huán)境及使用android studio打包jar包與arr包的方法

    這篇文章主要給大家介紹了關(guān)于在Mac中配置gradle環(huán)境,以及使用android studio打包jar包與arr包的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-01-01
  • Android自定義Notification添加點(diǎn)擊事件

    Android自定義Notification添加點(diǎn)擊事件

    這篇文章主要為大家詳細(xì)介紹了Android自定義Notification添加點(diǎn)擊事件,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11

最新評論