Frage Statische Möglichkeit, "Kontext" in Android zu erhalten?


Gibt es eine Möglichkeit, den Strom zu bekommen? Context Instanz in einer statischen Methode?

Ich suche nach diesem Weg, weil ich es hasse, die 'Kontext' -Instanz jedes Mal zu speichern, wenn sie sich ändert.


812
2018-01-04 21:15


Ursprung


Antworten:


Mach das:

Deklarieren Sie in der Android-Manifestdatei Folgendes.

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

</application>

Dann schreibe die Klasse:

public class MyApplication extends Application {

    private static Context context;

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

    public static Context getAppContext() {
        return MyApplication.context;
    }
}

Jetzt überall anrufen MyApplication.getAppContext() um Ihren Anwendungskontext statisch zu erhalten.


1144
2018-02-25 06:37



Die meisten Apps, die nach einer geeigneten Methode zum Abrufen des Anwendungskontexts suchen, erstellen ihre eigene Klasse, die erweitert wird android.app.Application.

FÜHREN

Sie können dies erreichen, indem Sie zuerst eine Klasse in Ihrem Projekt wie folgt erstellen:

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;
    }
}

Dann sollten Sie in Ihrem AndroidManifest den Namen Ihrer Klasse im Tag AndroidManifest.xml angeben:

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

Sie können den Anwendungskontext dann in jeder statischen Methode abrufen, indem Sie Folgendes verwenden:

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

WARNUNG

Bevor Sie etwas zu Ihrem Projekt hinzufügen, sollten Sie überlegen, was die Dokumentation sagt:

Normalerweise muss die Anwendung nicht von der Unterklasse getrennt werden. In den meisten Situationen   Statische Singletons können die gleiche Funktionalität in einem modularen bereitstellen   Weg. Wenn Ihr Singleton einen globalen Kontext benötigt (zum Beispiel um sich zu registrieren)   Broadcast-Empfänger), kann die Funktion zum Abrufen von a   Kontext, der intern Context.getApplicationContext () verwendet, wenn   zuerst den Singleton konstruieren.


BETRACHTUNG

Es gibt auch eine andere Möglichkeit, den Anwendungskontext durch Reflexion zu erhalten. Reflektion wird in Android oft vernachlässigt und ich persönlich denke, dass dies nicht in der Produktion verwendet werden sollte.

Um den Anwendungskontext abzurufen, müssen wir eine Methode für eine versteckte Klasse aufrufen (ActivityThread) die seit API 1 verfügbar ist:

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

Es gibt noch eine versteckte Klasse (AppGlobale), die eine Möglichkeit bietet, den Anwendungskontext auf statische Weise zu erhalten. Es bekommt den Kontext mit ActivityThread Es gibt also keinen Unterschied zwischen der folgenden Methode und der oben genannten:

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

Glückliche Kodierung!


59
2018-01-19 09:09



Nein, das glaube ich nicht. Leider steckst du nicht weiter getApplicationContext() von Activity oder eine der anderen Unterklassen von Context. Ebenfalls, Dies Frage ist etwas verwandt.


49
2018-01-05 00:46



Hier ist ein undokumentiert Weg, um einen zu bekommen Anwendung (das ist ein Kontext) von überall im UI-Thread. Es beruht auf der versteckten statischen Methode ActivityThread.currentApplication(). Es sollte zumindest auf Android 4.x funktionieren.

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
}

Beachten Sie, dass diese Methode möglicherweise null zurückgibt, z. Wenn Sie die Methode außerhalb des UI-Threads aufrufen oder die Anwendung nicht an den Thread gebunden ist.

Es ist immer noch besser zu benutzen @RohitGhatol's Lösung, wenn Sie den Anwendungscode ändern können.


35
2017-09-19 13:34



Es hängt davon ab, wofür Sie den Kontext verwenden. Ich kann mir zumindest einen Nachteil dieser Methode vorstellen:

Wenn Sie versuchen, ein AlertDialog mit AlertDialog.Builder, das Application Kontext wird nicht funktionieren. Ich glaube, Sie brauchen den Kontext für die aktuelle Activity...


31
2017-08-12 01:07



Wenn wir davon ausgehen, dass wir den Anwendungskontext bekommen, habe ich ihn wie von @Rohit Ghatol vorgeschlagen erweitert. Was dann passiert ist, ist, dass es keine Garantie gibt, dass der Kontext, der auf diese Weise abgerufen wird, immer nicht null ist. Zu dem Zeitpunkt, zu dem Sie es brauchen, ist es normalerweise, weil Sie einen Helfer initialisieren oder eine Ressource erhalten möchten, die Sie nicht rechtzeitig verzögern können; Die Behandlung des Nullfalls wird dir nicht helfen. Also habe ich verstanden, dass ich im Grunde gegen die Android - Architektur ankämpfe, wie in der Dokumente

Hinweis: In der Regel ist es nicht erforderlich, die Anwendung zu unterklassen. In den meisten Situationen können statische Singletons die gleiche Funktionalität in einer modularen Weise bereitstellen. Wenn Ihr Singleton einen globalen Kontext benötigt (z. B. zum Registrieren von Broadcast-Empfängern), schließen Sie Context.getApplicationContext () als Context-Argument ein, wenn Sie die Methode getInstance () Ihres Singletons aufrufen.

und erklärt von Dianne Hackborn

Der einzige Grund, warum die Anwendung als etwas existiert, von dem Sie ableiten können, ist, dass einer unserer Anwendungsentwickler mich während der Entwicklung vor 1.0 ständig daran hinderte, ein Anwendungsobjekt der obersten Ebene zu haben, von dem sie abgeleitet werden können "zu ihnen Anwendungsmodell, und ich gab schließlich auf.   Ich werde es für immer bereuen, dass ich auf diesen Fall gestoßen bin. :)

Sie schlägt auch die Lösung für dieses Problem vor:

Wenn Sie einen globalen Status verwenden möchten, der für verschiedene Teile Ihrer App verwendet werden kann, verwenden Sie einen Singleton. [...] Und das führt natürlicher dazu, wie Sie diese Dinge verwalten sollten - initialisieren Sie sie auf Nachfrage.

Also was ich getan habe, war loszuwerden, Anwendung zu erweitern, und übergeben Sie den Kontext direkt an die GetInstance () des Singleton-Helfers, während Sie einen Verweis auf den Anwendungskontext im privaten Konstruktor speichern:

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;
    }
}

Der Aufrufer wird dann einen lokalen Kontext an den Helper übergeben:

Helper.getInstance(myCtx).doSomething();

Also, um diese Frage richtig zu beantworten: Es gibt Möglichkeiten, statisch auf den Anwendungskontext zuzugreifen, aber alle sollten davon abgehalten werden, und Sie sollten lieber einen lokalen Kontext an das getInstance () des Singletons übergeben.


Für alle Interessierten gibt es eine detailliertere Version unter fwd Blog


28
2017-08-16 05:36



Wenn Sie für die Verwendung offen sind RoboGuiceSie können den Kontext in jede gewünschte Klasse einfügen lassen. Hier ist ein kleines Beispiel, wie man es mit RoboGuice 2.0 macht (Beta 4 zum Zeitpunkt der Erstellung)

import android.content.Context;
import android.os.Build;
import roboguice.inject.ContextSingleton;

import javax.inject.Inject;

@ContextSingleton
public class DataManager {
    @Inject
    public DataManager(Context context) {
            Properties properties = new Properties();
            properties.load(context.getResources().getAssets().open("data.properties"));
        } catch (IOException e) {
        }
    }
}

11
2018-02-29 14:46



Ich habe das irgendwann benutzt:

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

Dies ist ein gültiger Kontext, den ich verwendet habe, um Systemdienste zu erhalten und zu arbeiten.

Aber ich habe es nur in Framework / Base-Modifikationen verwendet und habe es nicht in Android-Anwendungen versucht.

EIN Warnung dass Sie wissen müssen: Wenn Sie sich für Broadcast-Empfänger in diesem Kontext registrieren, wird es nicht funktionieren und Sie erhalten:

java.lang.SecurityException: Angegebene Aufrufer-Paket android wird nicht in ProcessRecord ausgeführt


8
2018-05-08 10:22



Ich denke, du brauchst einen Körper für die getAppContext() Methode:

public static Context getAppContext()
   return MyApplication.context; 

3
2017-08-18 14:15



Sie können Folgendes verwenden:

MainActivity.this.getApplicationContext();

Hauptaktivität.java:

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

Jede andere Klasse:

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

3
2018-04-06 17:25