【轉】Android 獲取棧最頂層Activity和Application Context解決方案


在做類似“您的賬號在異地登陸,您被迫退出”的dialog彈窗的功能時,不知道怎么獲取當前Activity,剛好遇到這篇博主的文章,確實好用,在此記下。
以前開發都是在別人搭完框架的情況下進行開發,今天遇到一個很頭疼的問題,想要在做一個很常見的功能,當接收到極光推送的消息,就在當前頁面顯示一個dialog通知用戶賬號在別處已經登錄,需要重新登錄。這個問題真的是難倒我了,因為極光推送過來的時候,我們並不知道用戶操作到了哪一個Activity,而Dialog初始化的時候需要一個Activity或者一個context作為實例化的參數。當我一臉懵逼的時候,還是萬能的艷芳姐給我提供了解決的思路。也讓我在一定程度上對Application有一定的認知。
Android系統會為每個程序運行時創建一個Application類的對象且僅創建一個,所以Application是單例 (singleton)模式的一個類.且application對象的生命周期是整個程序中最長的,它的生命周期就等於這個程序的生命周期。因為它是全局的單例的,所以在不同的Activity,Service中獲得的對象都是同一個對象。因此在安卓中我們可以避免使用靜態變量來存儲長久保存的值,而用Application。
這也給我們提供了解決思路,在我們需要獲取到當前Context或者Activity對象的時候,我們就可以通過重寫這個Application來保存當前的Context或者Activity。

public class BaseApp extends Application {  
    private static BaseApp mApp;  
    private static Activity sActivity;  
    @Override  
    public void onCreate() {  
        super.onCreate();  
        mApp = this;  
        this.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {  
            @Override  
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {  
                Log.d("YWK",activity+"onActivityCreated");  
            }  

            @Override  
            public void onActivityStarted(Activity activity) {  
                Log.d("YWK",activity+"onActivityStarted");  
                sActivity=activity;  

            }  

            @Override  
            public void onActivityResumed(Activity activity) {  

            }  

            @Override  
            public void onActivityPaused(Activity activity) {  

            }  

            @Override  
            public void onActivityStopped(Activity activity) {  

            }  

            @Override  
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {  

            }  

            @Override  
            public void onActivityDestroyed(Activity activity) {  

            }  
        });  
    }  

    public static Context getAppContext() {  
        return mApp;  
    }  

    public static Resources getAppResources() {  
        return mApp.getResources();  
    }  

    public static Activity getActivity(){  
        return sActivity;  
    }  
}

 

這個就是我們重新寫的Application,其實我們在做任何項目的時候,應該都會去重寫這個Application,去實現一些全局變量的保存,向上面這段代碼,我們保存了Activity對象和Context對象,然后重寫Application的Oncreate,mApp=this,這里我們保存了一個Application Context,為什么說Application Context呢?我們在下面討論。
然后我們通過Application調用registerActivityLifecycleCallbacks的方法,注冊一個監聽器,對Activity的生命周期進行監聽,這樣我們只要在一個Activity在start的時候,使sActivity=這個Activity就好了。
這樣在初始化Dialog的時候 AlertDialog.Builder dialog = new AlertDialog.Builder(BaseApp.getActivity());我們將我們Application中獲取到的最新的Activity傳進去,這樣不管用戶在哪一個界面,我們都能獲取到棧最頂層的Activity。
最后我們要給我們的應用設置上我們自定義的Application:

<application  
        android:name=".base.BaseApp"  
        android:allowBackup="true"  
        android:icon="@mipmap/ic_launcher"  
        android:label="@string/app_name"  
        android:supportsRtl="true"  
        android:largeHeap="true"  

        android:theme="@style/AppTheme">

 

我們通過設置AndroidManifest.xml文件,在application中設置name屬性就好了。

Application Context 和Activity Context的區別:
為什么我上面說是Application Context而不是說Activity Context呢?在解決上面那個功能的時候,我最開始就在初始化Dialog的時候我是這樣寫的:
AlertDialog.Builder dialog = new AlertDialog.Builder(BaseApp.getAppContext());
結果報錯,一直定位在這一行。一直不解,后來才知道Application中獲取的Context是一個全局的Application,它和Activity Context的使用場景有很大的不同。

 

 


大家注意看到有一些NO上添加了一些數字,其實這些從能力上來說是YES,但是為什么說是NO呢?下面一個一個解釋:
數字1:啟動Activity在這些類中是可以的,但是需要創建一個新的task。一般情況不推薦。
數字2:在這些類中去layout inflate是合法的,但是會使用系統默認的主題樣式,如果你自定義了某些樣式可能不會被使用。
數字3:在receiver為null時允許,在4.2或以上的版本中,用於獲取黏性廣播的當前值。(可以無視)
注:ContentProvider、BroadcastReceiver之所以在上述表格中,是因為在其內部方法中都有一個context用於使用。

好了,這里我們看下表格,重點看Activity和Application,可以看到,和UI相關的方法基本都不建議或者不可使用Application,並且,前三個操作基本不可能在Application中出現。實際上,只要把握住一點,凡是跟UI相關的,都應該使用Activity做為Context來處理;其他的一些操作,Service,Activity,Application等實例都可以,當然了,注意Context引用的持有,防止內存泄漏。 以上這段話是引用了鴻洋大神的博客,這么一看,我們也就很清楚了Application Context和Activity Context的區別。

from:http://www.voidcn.com/article/p-ztomovyy-nh.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM