新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > Android_Context詳解

        Android_Context詳解

        作者: 時間:2016-09-12 來源:網絡 收藏

        Context對象是如此常見和傳遞使用,它可能會很容易產生并不是你預期的情形。加載資源、啟動一個新的Activity、獲取系統服務、獲取內部文件路徑以及創建view(其實還遠不止這些)統統都需要Context對象來完成。我(原文作者)想做的只是給大家提供一些Context是如何工作的見解,以及讓大家在應用中更有效的使用Context的技巧。

        本文引用地址:http://www.104case.com/article/201609/304658.htm

        Context的類型

        并不是所有的context實例都是等價的。根據Android應用的組件不同,你訪問的context推向有些細微的差別。

        Application - 是一個運行在你的應用進程中的單例。在Activity或者Service中,它可以通過getApplication()函數獲得,或者人和繼承于context的對象中,通過getApplicationContext()方法獲得。不管你是通過何種方法在哪里獲得的,在一個進程內,你總是獲得到同一個實例。

        Activity/Service - 繼承于ContextWrapper,它實現了與context同樣API,但是代理這些方法調用到內部隱藏的Context實例,即我們所知道的基礎context。任何時候當系統創建一個新的Activity或者Service實例的時候,它也創建一個新的ContextImpl實例來做所有的繁重的工作。每一個Activity和Service以及其對應的基礎context,對每個實例來說都是唯一的。

        BroadcastReciver - 它本身不是context,也沒有context在它里面,但是每當一個新的廣播到達的時候,框架都傳遞一個context對象到onReceive()。這個context是一個ReceiverRestrictedContext實例,它有兩個主要函數被禁掉:registerReceiver()和bindService()。這兩個函數在BroadcastReceiver.onReceive()不允許調用。每次Receiver處理一個廣播,傳遞進來的context都是一個新的實例。

        ContentProvider - 它本身也不是一個Context,但是它可以通過getContext()函數給你一個Context對象。如果ContentProvider是在調用者的的本地(例如,在同一個應用進程),getContext()將返回的是Application單例。然而,如果調用這個ContentProvider在不同的進程的時候,它將返回一個新創建的實例代表這個Provider所運行的包。

        保存引用

        第一個我們需要解決問題是,在一個對象或者類內部保存一個context引用,而它生命周期卻超過其保存引用的對象的生命周期。例如,創建一個自定義的單例,它需要一個context來加載資源或者獲取ContentProvider,從而保存一個指向當前Activiy或者Service的引用在單例中。

        糟糕的單例

        [java]

        public class CustomManager {

        private static CustomManager sInstance;

        public static CustomManager getInstance(Context context) {

        if (sInstance == null) {

        sInstance = new CustomManager(context);

        }

        return sInstance;

        }

        private Context mContext;

        private CustomManager(Context context) {

        mContext = context;

        }

        }

        這里的問題在于,我們不知道這個context是從哪里來的,并且如果保存一個最終指向的是Activity或者Servece的引用是并不安全的。這是一個問題,是因為一個單例在類的內部維持一個唯一的靜態引用,這意味著我們的對象,以及所有其他它所引用的對象,將永遠不能被垃圾回收。假如這個Context是一個Activity,我們將保存與這個Activity相關的所有的view以及其他大的對象,從而造成內存泄漏。

        為了解決這個問題,我們修改單例永遠只是保存Application context:

        改善的單例:

        [java

        public class CustomManager {

        private static CustomManager sInstance;

        public static CustomManager getInstance(Context context) {

        if (sInstance == null) {

        //Always pass in the Application Context

        sInstance = new CustomManager(context.getApplicationContext());

        }

        return sInstance;

        }

        private Context mContext;

        private CustomManager(Context context) {

        mContext = context;

        }

        }

        現在這個例子中,我們的Context來自哪里都沒有關系,因為我們這里保存引用是安全的。Application Context 本身就是一個單例,所以我們再創建另外一個static引用,不會造成任何內存泄漏。另外一個很好的例子是,在后臺線程或者一個等待的Handler中保存Context的引用,也可以使用這樣的方法。

        為什么我們不能總是引用Application context呢?正如前面說的,引用Application context永遠不用擔心內存泄漏的問題。問題的答案,就像我在開始的介紹中說的,是因為不同context并不是等價的。

        Context的能力

        Conext能做的通用操作決定于這個context最初來源于哪里。下表所列的是,在應用中常見的會收到context對象的,以及對應的每種情況,它可以用于哪些地方:

        ApplicationActivityServiceContentProviderBroadcastReceiver
        Show a DialogNOYESNONONO
        Start an ActivityNO1YESNO1NO1NO1
        Layout InflationNO2YESNO2NO2NO2
        Start a ServiceYESYESYESYESYES
        Bind to a ServiceYESYESYESYESNO
        Send a BroadcastYESYESYESYESYES
        Register BroadcastReceiverYESYESYESYESNO3
        Load Resource ValuesYESYESYESYESYES

        上一頁 1 2 下一頁

        關鍵詞:

        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 页游| 垦利县| 定陶县| 崇明县| 贵德县| 利辛县| 田东县| 萨迦县| 师宗县| 汝阳县| 大洼县| 建湖县| 南宫市| 蛟河市| 三原县| 桓台县| 桐梓县| 栾城县| 北海市| 木里| 抚顺市| 鄱阳县| 宣汉县| 锡林郭勒盟| 巴彦淖尔市| 临沂市| 台南市| 高邑县| 乌兰浩特市| 威海市| 江门市| 大渡口区| 呼伦贝尔市| 汤原县| 伊金霍洛旗| 沁水县| 静乐县| 富平县| 鄂州市| 故城县| 黄陵县|