1. 程式人生 > >ContentProvider淺析---寫點你平時沒注意到的~~

ContentProvider淺析---寫點你平時沒注意到的~~

(一) 前言
ContentProvider是android元件之一,可以提供資料的跨應用程式訪問,提供資料的跨程序無縫隙訪問,所以是非常重要的東東。使用方法一般是
複製內容到剪貼簿
程式碼:
getContentResolver().query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder); 那麼下面來提幾個問題:
1. 在應用程式A裡面怎麼跨程序拿到ContentProvider的物件呢?
2. ContentProvider例項物件是儲存在哪裡呢?
3. ContentProvider的方法實現要注意執行緒安全嗎?


如果你能很清晰的回答這幾個問題,那麼下面的你就不需要繼續看了,如果還有疑問,咱們一起往下面學習吧~

(二) 怎麼跨程序拿到ContentProvider的物件
1. 我們來看ContentResolver.query方法是怎麼實現的
a. 首先它會去找ContentProvider物件,是這樣寫的
複製內容到剪貼簿
程式碼:
IContentProvider unstableProvider = acquireUnstableProvider(uri); b. 然後acquireUnstableProvider(uri)方法是這樣的: 複製內容到剪貼簿
程式碼:
public final IContentProvider acquireUnstableProvider(Uri uri) {
        if (!SCHEME_CONTENT.equals(uri.getScheme())) {
            return null;
        }
        String auth = uri.getAuthority();//取得ContentProvider名字,拿這個名字去尋找對應的ContentProvider
        if (auth != null) {
            return acquireUnstableProvider(mContext, uri.getAuthority());
        }
        return null;
    }
在這段程式碼裡面,關鍵地方在這裡 String auth = uri.getAuthority();這裡取得的auth就是我們在AndroidManifes.xml檔案中配置的ContentProvider的android:authorities的值
如:
複製內容到剪貼簿
程式碼:
<provider android:name=".TestProvider"
                android:authorities="com.android.test"></provider>
所以,這個android:authorities屬性配置的就是該ContentProvider的名字,是它在Android系統中的名字,我們是通過這個名字去找對應的ContentProvider物件的。


c. ok..既然現在我們拿到ContentProvider的名字了,我們就來看看acquireUnstableProvider方法怎麼通過名字來找到ContentProvider物件的。
這個acquireUnstableProvider方法會呼叫到ActivityThread的acquireProvider方法,這個方法的實現是:
複製內容到剪貼簿
程式碼:
public final IContentProvider acquireProvider(Context c, String name, boolean stable) {
        IContentProvider provider = acquireExistingProvider(c, name, stable);
        if (provider != null) {
            return provider;
        }

        // There is a possible race here.  Another thread may try to acquire
        // the same provider at the same time.  When this happens, we want to ensure
        // that the first one wins.
        // Note that we cannot hold the lock while acquiring and installing the
        // provider since it might take a long time to run and it could also potentially
        // be re-entrant in the case where the provider is in the same process.
        IActivityManager.ContentProviderHolder holder = null;
        try {
            holder = ActivityManagerNative.getDefault().getContentProvider(
                    getApplicationThread(), name, stable);
        } catch (RemoteException ex) {
        }
        if (holder == null) {
            Slog.e(TAG, "Failed to find provider info for " + name);
            return null;
        }

        // Install provider will increment the reference count for us, and break
        // any ties in the race.
        holder = installProvider(c, holder, holder.info,
                true /*noisy*/, holder.noReleaseNeeded, stable);
        return holder.provider;
    }
這裡就是查詢ContentProvider實現的精髓所在了。。
首先,它去找acquireExistingProvider方法,這個方法其實就是根據我們傳過來的名稱在一個map裡面找,如:
ProviderClientRecord pr = mProviderMap.get(name);
由於我們的ActivityThread和我們的應用程式還在一個程序裡面,所以這個步驟我們可以理解為:在本地快取中尋找ContentProvider物件
ok...在本地找了之後,如果找到了,就直接返回。
if (provider != null) {
            return provider;
        }
如果沒有找到,就繼續往下面走:
holder = ActivityManagerNative.getDefault().getContentProvider(
                    getApplicationThread(), name, stable);
這個方法就是呼叫到ActivityManagerService的getContentProvider方法去尋找ContentProvider.這裡是一個跨程序呼叫,因為ActivityThread和ActivityManagerService不在一個程序裡面。
至於ActivityThread和ActivityManagerService的關係,可以參考我以前的這篇帖子:
http://bbs.51cto.com/thread-1008812-1.html

而ActivityManagerService會把所有的ContentProvider都例項化出來,並且快取在一個map裡面,所以我們就可以通過
複製內容到剪貼簿
程式碼:
holder = ActivityManagerNative.getDefault().getContentProvider(
                    getApplicationThread(), name, stable);
從ActivityManagerService遠端得到一個ContentProvider物件。那麼這一步,我們可以理解為:從遠端服務中尋找ContentProvider物件
ok..從遠端ActivityManagerService得到ContentProvider物件之後,我們繼續往下面走。
複製內容到剪貼簿
程式碼:
holder = installProvider(c, holder, holder.info,
                true /*noisy*/, holder.noReleaseNeeded, stable);
        return holder.provider;
首先,會呼叫installProvider方法,這個方法其實就是往本地的ContentProvider map快取中新增一條快取記錄。
ok...那麼這整個過程,我們就可以理解為這樣:
i.  第一步,它從ActivityThread裡面本地快取尋找ContentProvider物件,所以找到了,就一切ok..
ii. 第二步,如果第一步沒有找到,那麼就去ActivityManagerService遠端服務中尋找ContentProvider物件。
iii.第三步,從遠端服務中找到ContentProvider物件之後,就把這個物件快取在本地,那麼下次找的話,直接就可以從本地快取中查找了。
那麼,它為什麼要有這個機制呢?個人猜測:因為跨程序呼叫是需要時間和資源消耗的,所以,它才有了本地快取這麼個東東。

(三) ContentProvider例項物件是儲存在哪裡
那麼如果大家看完了上面一篇長篇大論,這個問題就很好回答了。
它儲存在兩個位置:
1. ActivityThread的本地map快取中
2. ActivityManagerService的遠端服務map快取中

(四) ContentProvider的方法實現要注意執行緒安全嗎
從上面一段描述來看,我們可以發現一個問題,ContentProvider在某種程度上是單例的,比如我們第一次從本地map快取裡面得到ContentProvider物件,第二次我們在同一個應用程式請求的時候,拿到的肯定是同一個快取物件。
所以,ContentProvider只能配置程序之間是否是單例,同一個程序裡面是不能配置是否是單例的,因為它在同一個程序裡面肯定是單例。
配置程序之間是否是單例:
複製內容到剪貼簿
程式碼:
android:multiprocess="true" 所以我們的ContentProvider的程式碼,比如查詢,更新,刪除等等,必須注意執行緒安全的問題。
那麼單例下,我們怎麼注意執行緒安全問題呢?
1. ContentProvider儘量少用成員變數,因為我們用的是單例,所以成員變數是共享的。
2. 所以真的用到了共享資源,建議用synchronized或者TheadLocal來解決。至於synchronized和TheadLocal的區別,這篇文章就不討論了,下次有機會再寫吧。。

一點點小小分析,僅供參考~~

相關推薦

ContentProvider淺析---平時注意到的

(一) 前言 ContentProvider是android元件之一,可以提供資料的跨應用程式訪問,提供資料的跨程序無縫隙訪問,所以是非常重要的東東。使用方法一般是 複製內容到剪貼簿 程式碼: getContentResolver().query(Uri uri, Stri

ContentProvider淺析---平時注意到的 ...

(一) 前言 ContentProvider是android元件之一,可以提供資料的跨應用程式訪問,提供資料的跨程序無縫隙訪問,所以是非常重要的東東。使用方法一般是 複製內容到剪貼簿 程式碼: getContentResolver().query(Uri uri, Stri

大論文的一些注意事項(續):我是如何找到創新的?

  轉載來源:作者QQ(微信):245924426。 https://blog.csdn.net/zhouzxi/article/details/6891966        寫大論文最關鍵的就是要找到創新點,而最傷腦筋的

5個平時注意的Excel技巧,3分鐘幫完成1小時工作!

Excel是我們職場辦公中最常用的工具,但有時候很簡單的工作大家卻要忙會了半天才能夠完成,令人感到十分頭痛,那麼今天小編在這裡為大家整理了5個平時不注意的Excel技巧,一定能夠幫到經常使用Excel的辦公人群! 職場辦公經常能夠用到的Excel技巧: 1、 Excel瞬間全選! 大家在

日記俠:母親節朋友圈文案究竟該啥?

又是一年母親節,朋友圈刷屏了!你的母親節朋友圈文案寫的啥?你好,我是王剛,行走於網路江湖的“日記俠”。每天分享我的思考和經驗,希望身邊的人可以和我一樣天天寫日記,今天是王剛日記第541天。/ 1 /自從微信朋友圈火了之後,每到節假日,各種祝福雞湯讓人覺得反胃。雖然每個人都有孝

其實可以少if else和switch

就是 有變 做的 關註 調用 業務需求 val 定義 狀態 前言 作為搬磚在第一線的底層工人,業務場景從來是沒有做不到只有想不到的復雜。 不過他強任他強,if-else全搞定,搬就完了。但是隨著業務叠代或者項目交接,自己在看自己或者別人的if代碼的時候,心情就不再表述了,各

接手前端新專案?這裡有些注意可能需要留意一下

前段時間加入公司內一個新開業務線的前端組,由於是新開的業務線,做的也是小程式這一塊,所以幾乎沒有任何歷史包袱,組內成員都是專案程式碼第一手產出者 我加入的時機較晚,沒有經歷過最開始的初創階段,不太清楚一開始的狀況,不過聽說是蠻折磨人的,需要踩坑無數,經常需要加班

RestTemplate使用過程中可能需要注意

RestTemplate在get請求設定引數時,url中後跟的引數一定不要是encode之後的param值,因為他會再次encode 一個url可以多次encode,每次結果不一 附上:原生jack

Android hdpi,xhdpi,xxhdpi一些注意到的事

一、drawable-dpi資料夾圖片尺寸比例 我們都知道安卓系統會根據不同的手機的解析度去取不同資料夾裡的圖片,但是具體這些資料夾裡放什麼尺寸比例的圖片,怕是不少人都沒有關注過吧。可能有人會說,這是UI部門該瞭解的事,那如果UI部門的同學也不知道呢,那該怎麼辦。這種情況我

關於ArrayList.remove()的一些注意的細節

這是我在程式設計中遇到的問題,當時以為是BUG,後來才發現原來是ArrayList.remove(int index)方法的一些小細節 廢話不多說,先上程式碼 <pre name="code" class="java">ArrayList<Integer&

Java IO流讀檔案的幾個注意

  平時寫IO相關程式碼機會挺少的,但卻都知道使用BufferedXXXX來讀寫效率高,沒想到裡面還有這麼多陷阱,這兩天突然被其中一個陷阱折騰一下:讀一個檔案,然後寫到另外一個檔案,前後兩個檔案居然不一樣?      解決這個問題之後,總結了幾個注意點。 注意點一:Rea

給自己:程式需要注意的幾!(新人注意

1.需要小心除錯。特別是當有一些程式除錯時可能會影響到客戶/資料的,更需要小心。 2.要保證質量。時間要保證,但可以放寬,但是質量不可以放寬!在注意測試,非常重要。不能埋頭測試,需要大家幫忙測試,請專門的測試,站在客戶的角度測試,不能以開發者的觀點去測試 3.注重效率。一個公

安卓開發,關於程式碼安全的注意,平常開發中有沒有注意!!!

發揚分享精神,做一個快樂的開發者! 看CSDN有好長時間了,感謝那些善於分享的開發者,感謝你們 ,閱讀你們的文章,我感覺有很快的進步,我一直也想寫部落格,把自己的見解和大家分享,只是苦於不知道寫些什麼,現在機會來了,我要把我研究的一些關於程式碼安全的試題給大家

程式的時候需要注意的幾問題

1:在寫程式碼的時候 對於一個庫如(delay.h), 需要建立兩個檔案即 一個.C一個.h 檔案 。.c 的檔案中需要寫的是 功能函式,簡單的說就是 檔案的執行過程 操作過程。.h檔案中寫入對.C的檔案宣告函式還有包含函式的定義,開闢新記憶體的操作。 2:在

不懂資料庫索引的底層原理?那是因為心裡b樹

本文在個人技術部落格不同步釋出,詳情可用力戳 亦可掃描螢幕右側二維碼關注個人公眾號,公眾號內有個人聯絡方式,等你來撩...   前幾天下班回到家後正在處理一個白天沒解決的bug,廁所突然傳來物件的聲音:   物件:xx,你有《時間簡史》嗎?   我:我去!妹子,你這啥癖好啊,我有時間也不會去撿屎啊!   

HashMap原理。圖文並茂式解讀。這些注意一定還不瞭解

目錄 概述 屬性詳解 table entrySet size modCount threshold、loadFactor 原始

我的“男神”6.18“炫父”

父親節 父親 父親是什麽? 他是那個無論風雨多大,永遠會去接你下學的人。 他是那個在你生病時,第一時間出現在你眼前的人。 他是那個每當你過生日,永遠會記得打電話給你的。 他是那個不管多困難,永遠都是默

PDF閱讀器還有那麽多強大的編輯功能,想到吧~

pdf閱讀器 安卓pdf閱讀器 小編自己用的是一部苦逼的安卓手機,每次收到老板發來的PDF文件,都只能用軟件的內置瀏覽器打開文件——壓縮了圖片質量不說,重點是無法直接編輯文件,很是讓人崩潰啊!為了方便閱讀跟編輯,小編在多番功課之後下載了一個體積小於10M的PDF閱讀器,如下圖所示——看起來是不是很厲害

是時候什麽了

deep 我不 困難 ref href 進不去 下載 美的 res 夜深了,我知道,可我已經習慣了,我試著早點睡,可是睡不著,腦袋會想起很多亂七八糟 的事,很活躍,眨眨眼睛絲毫沒有倦意,我也試過早起,可那樣又渾身沒勁,不想吃飯,沒法運動,更無心學習了,甚至連打遊戲都很糟。啊

draw9patch在SDK->tools找不到,在Android Studio擊圖片找到draw9patch

color tools androi and 一個 span ogl ack tool draw9patch在SDK->tools找不到,在Android Studio點擊圖片沒找到draw9patch 第一個問題: Google把draw9patch集成在And