android - mainactivity - this context




在Android中獲取“上下文”的靜態方法? (12)

有沒有辦法在靜態方法中獲取當前的Context實例?

我正在尋找這種方式,因為我討厭每次更改時都保存“上下文”實例。


不,我認為沒有。 不幸的是,你堅持從ActivityContext的其他子類之一調用getApplicationContext() 。 另外, this問題有些相關。


假設我們正在討論獲取應用程序上下文,我按照@Rohit Ghatol擴展應用程序的建議來實現它。 然後發生了什麼事情,它不能保證以這種方式檢索的上下文始終是非空的。 當你需要它的時候,通常是因為你想要初始化一個幫手,或者獲得一個資源,以至於你無法及時推遲; 處理空情況不會幫助你。 所以我理解我基本上是在與Android架構戰鬥,正如docs中所述

注意:通常不需要子類Application。 在大多數情況下,靜態單例可以以更模塊化的方式提供相同的功能。 如果您的單例需要全局上下文(例如註冊廣播接收器),請在調用單例的getInstance()方法時將Context.getApplicationContext()作為Context參數包含在內。

並由Dianne Hackborn解釋

應用程序存在的唯一原因是可以從中派生出來的原因是因為在1.0之前的開發過程中,我們的應用程序開發人員中的一個人一直在竊聽我需要擁有一個可以從中派生出的頂級應用程序對象,因此他們可以擁有更多“正常“他們的應用模式,我最終放棄了。我會永遠後悔放棄這個。 :)

她還建議解決這個問題:

如果你想要的是一些可以在應用的不同部分共享的全局狀態,請使用單例。 [...]這更自然地引導你如何管理這些東西 - 按需要初始化它們。

所以我所做的是擺脫擴展Application,並將上下文直接傳遞給單例助手的getInstance(),同時在私有構造函數中保存對應用程序上下文的引用:

private static MyHelper instance;
private final Context mContext;    

private MyHelper(@NonNull Context context) {
    mContext = context.getApplicationContext();
}

public static MyHelper getInstance(@NonNull Context context) {
    synchronized(MyHelper.class) {
        if (instance == null) {
            instance = new MyHelper(context);
        }
        return instance;
    }
}

調用者然後將一個本地上下文傳遞給幫助者:

Helper.getInstance(myCtx).doSomething();

因此,要正確回答這個問題:有辦法靜態訪問應用程序上下文,但他們都應該不鼓勵,並且您應該更喜歡將本地上下文傳遞給單例的getInstance()。

對於任何感興趣的人,您可以在fwd博客閱讀更詳細的版本


大多數需要方便的方法來獲取應用程序上下文的應用程序都會創建自己的擴展developer.android.com/reference/android/app/Application.html的類。

指南

您可以通過首先在您的項目中創建一個類來完成此任務,如下所示:

import android.app.Application;
import android.content.Context;

public class App extends Application {

    private static Application sApplication;

    public static Application getApplication() {
        return sApplication;
    }

    public static Context getContext() {
        return getApplication().getApplicationContext();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        sApplication = this;
    }
}

然後,在您的AndroidManifest中,您應該在AndroidManifest.xml的標籤中指定您的類的名稱:

<application 
    ...
    android:name="com.example.App" >
    ...
</application>

然後,您可以使用以下方法在任何靜態方法中檢索應用程序上下文:

public static void someMethod() {
    Context context = App.getContext();
}

警告

在向您的項目中添加類似上面的內容之前,您應該考慮文檔所說的內容:

通常不需要子類化應用程序。 在大多數情況下,靜態單例可以以更模塊化的方式提供相同的功能。 如果你的單例需要一個全局上下文(例如註冊廣播接收者),那麼檢索它的函數可以被賦予一個上下文,該上下文在第一次構造單例時在內部使用Context.getApplicationContext()。

反射

還有另一種使用反射來獲取應用程序上下文的方法。 反思在Android中經常被忽視,我個人認為這不應該用於生產。

為了檢索應用程序上下文,我們必須調用一個隱藏類( ActivityThread )上的方法,該方法從API 1開始就可用:

public static Application getApplicationUsingReflection() throws Exception {
    return (Application) Class.forName("android.app.ActivityThread")
            .getMethod("currentApplication").invoke(null, (Object[]) null);
}

還有一個隱藏類( AppGlobals )提供了一種以靜態方式獲取應用程序上下文的方法。 它使用ActivityThread獲取上下文,所以下面的方法和上面發布的方法之間確實沒有區別:

public static Application getApplicationUsingReflection() throws Exception {
    return (Application) Class.forName("android.app.AppGlobals")
            .getMethod("getInitialApplication").invoke(null, (Object[]) null);
} 

快樂的編碼!


如果你出於某種原因需要任何類中的應用程序上下文,而不僅僅是那些擴展應用程序/活動的應用程序上下文,那麼可能適用於某些工廠或幫助類。 您可以將以下單例添加到您的應用程序。

public class GlobalAppContextSingleton {
    private static GlobalAppContextSingleton mInstance;
    private Context context;

    public static GlobalAppContextSingleton getInstance() {
        if (mInstance == null) mInstance = getSync();
        return mInstance;
    }

    private static synchronized GlobalAppContextSingleton getSync() {
        if (mInstance == null) mInstance = 
                new GlobalAppContextSingleton();
        return mInstance;
    }

    public void initialize(Context context) {
        this.context = context;
    }

    public Context getApplicationContext() {
        return context;
    }
}

然後在你的應用程序類的onCreate中初始化它

GlobalAppContextSingleton.getInstance().initialize(this);

通過呼叫在任何地方使用

GlobalAppContextSingleton.getInstance().getApplicationContext()

然而,我不建議這種方法適用於除應用程序上下文之外的任 因為它會導致內存洩漏。


如果您不想修改清單文件,則可以手動將上下文存儲在初始活動中的靜態變量中:

public class App {
    private static Context context;

    public static void setContext(Context cntxt) {
        context = cntxt;
    }

    public static Context getContext() {
        return context;
    }
}

只需在您的活動(或活動)開始時設置環境:

// MainActivity

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Set Context
    App.setContext(getApplicationContext());

    // Other stuff
}

注意:與所有其他答案一樣,這是潛在的內存洩漏。


您可以使用以下內容:

MainActivity.this.getApplicationContext();

MainActivity.java:

...
public class MainActivity ... {
    static MainActivity ma;
...
    public void onCreate(Bundle b) {
         super...
         ma=this;
         ...

任何其他課程:

public ...
    public ANY_METHOD... {
         Context c = MainActivity.ma.getApplicationContext();

我剛剛發布了一個名為Vapor API的 Android版jQuery靈感框架,旨在簡化應用程序開發。

中心的$ facade類維護著一個WeakReference (通過Ethan Nicholas鏈接到關於這個的很棒的Java博客文章)到當前的Activity上下文中,您可以通過調用以下方法來獲取它:

$.act()

WeakReference在不阻止垃圾收集回收原始對象的情況下維護引用,因此不應該存在內存洩漏問題。

當然,不利的$.act()是你可能會面臨$.act()可能返回null的風險。 儘管如此,我還沒有遇到這種情況,所以這可能只是一個很小的風險,值得一提。

如果您沒有將VaporActivity用作Activity類,則還可以手動設置上下文:

$.act(Activity);

此外, Vapour API框架的大部分內在使用了這個存儲上下文,這可能意味著如果您決定使用該框架,則根本不需要存儲它。 查看網站了解更多信息和样品。

我希望幫助:)


我在某個時候使用過這個:

ActivityThread at = ActivityThread.systemMain();
Context context = at.getSystemContext();

這是我在獲取系統服務和工作時使用的有效上下文。

但是,我只在框架/基礎修改中使用它,並沒有在Android應用程序中嘗試它。

您必須知道的警告 :在使用此上下文註冊廣播接收器時,該警告不起作用,您將獲得:

java.lang.SecurityException:給定調用者包android並未在ProcessRecord中運行


所以我修改了接受的答案,因為它導致了內存洩漏,這就是我想出的...

AndroidManifest.xml中

    <application android:name="com.xyz.MyApplication">
...

    </application>

MyApplication.java

public class MyBakingAppContext extends Application {
    private static Object mContext;

    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();
    }

    public static Context getAppContext() {
        return (Context)mContext;
    }
}

我實際上做的是,為對象分配一個上下文,並將該對像作為上下文返回(將其轉換為上下文)。 希望它有幫助。


根據這個源代碼,你可以通過擴展ContextWrapper來獲得你自己的Context

public class SomeClass extends ContextWrapper {

    public SomeClass(Context base) {
      super(base);
    }

    public void someMethod() {
        // notice how I can use "this" for Context
        // this works because this class has it's own Context just like an Activity or Service
        startActivity(this, SomeRealActivity.class);

        //would require context too
        File cacheDir = getCacheDir();
    }
}

用於ContextWrapper的JavaDoc

代理執行Context,將其所有調用簡單地委託給另一個Context。 可以被分類為修改行為而不更改原始上下文。


這將在AndroidManifest.xml文件中

<application
        android:name=".MyApplication">

</application>

這是MyApplication.java文件

public class MyApplication extends Application {
    private static MyApplication application;
    @Override
    public void onCreate() {
        super.onCreate();
        application = this;
    }
    public static MyApplication getContext(){
        return application;
    }
}

這是一種無證的方式從UI線程中的任何地方獲取developer.android.com/reference/android/app/Application.html (這是一個上下文)。 它依賴隱藏的靜態方法ActivityThread.currentApplication() 。 它至少應該在Android 4.x上運行。

try {
    final Class<?> activityThreadClass =
            Class.forName("android.app.ActivityThread");
    final Method method = activityThreadClass.getMethod("currentApplication");
    return (Application) method.invoke(null, (Object[]) null);
} catch (final ClassNotFoundException e) {
    // handle exception
} catch (final NoSuchMethodException e) {
    // handle exception
} catch (final IllegalArgumentException e) {
    // handle exception
} catch (final IllegalAccessException e) {
    // handle exception
} catch (final InvocationTargetException e) {
    // handle exception
}

請注意,此方法可能會返回null,例如,當您在UI線程之外調用方法時,或者應用程序未綁定到線程時。

如果您可以更改應用程序代碼,則最好使用@RohitGhatol的解決方案。





android-context