在做類似“您的賬號在異地登陸,您被迫退出”的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