Statischer Weg, um 'Kontext' in Android zu bekommen?

970

Gibt es eine Möglichkeit, die aktuelle ContextInstanz in eine statische Methode zu integrieren?

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

Andrea Baccega
quelle
57
Das Nicht-Speichern von Kontext ist eine gute Idee, nicht nur, weil es unpraktisch ist, sondern auch, weil es zu großen Speicherlecks führen kann!
Vikram Bodicherla
12
@VikramBodicherla Ja, aber die folgenden Antworten setzen voraus, dass es sich um den Anwendungskontext handelt. Speicherlecks sind also kein Problem, aber der Benutzer sollte diese Lösungen nur verwenden, wenn dies der richtige Kontext ist.
Tom
Wenn Sie eine statische Methode zum Abrufen verwenden müssen Context, gibt es möglicherweise eine bessere Methode zum Entwerfen des Codes.
Anonsage
3
In der Android-Dokumentation wird empfohlen, den Kontext an Singletons zu übergeben. developer.android.com/reference/android/app/Application.html
Marco Luglio
Um Singletons und den mit getInstance () übergebenen Kontext dem statischen Kontext vorzuziehen, werfen Sie bitte einen Blick darauf. Ich habe versucht, meine Argumentation hier zu erläutern, die mit Arbeitscode
Alessio

Antworten:

1302

Mach das:

Deklarieren Sie in der Android Manifest-Datei 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;
    }
}

Rufen MyApplication.getAppContext()Sie jetzt überall an, um Ihren Anwendungskontext statisch abzurufen.

Rohit Ghatol
quelle
81
Gibt es einen Nachteil dieser Methode? Das scheint zu schummeln. (Ein Hack?)
jjnguy
203
Der Nachteil ist, dass es keine Garantie dafür gibt, dass das nicht statische onCreate () aufgerufen wurde, bevor ein statischer Initialisierungscode versucht, Ihr Context-Objekt abzurufen. Das bedeutet, dass Ihr aufrufender Code bereit sein muss, mit Nullwerten umzugehen, was den ganzen Punkt dieser Frage zunichte macht.
Melinda Green
8
Vielleicht sollten wir diese static contextVariable auch als deklarieren volatile?
Vladimir Sorokin
14
@ Tom Dies ist kein Fall, in dem ein statisches Datenelement anfänglich statisch ist. Im angegebenen Code wird das statische Element in onCreate () nicht statisch initialisiert. Selbst statisch initialisierte Daten sind in diesem Fall nicht gut genug, da nichts sicherstellt, dass die statische Initialisierung der angegebenen Klasse erfolgt, bevor während der statischen Initialisierung einer anderen Klasse auf sie zugegriffen wird.
Melinda Green
10
@MelindaGreen Gemäß der Dokumentation für Application wird onCreate () aufgerufen, bevor Aktivitäten, Dienste oder Empfänger (mit Ausnahme von Inhaltsanbietern) erstellt wurden. Wäre diese Lösung nicht sicher, solange Sie nicht versuchen, von einem Inhaltsanbieter auf getAppContext () zuzugreifen?
Magnus W
86

Die meisten Apps, die eine bequeme Methode zum Abrufen des Anwendungskontexts wünschen, erstellen eine eigene Klasse, die erweitert wird android.app.Application.

LEITEN

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 von AndroidManifest.xml angeben:

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

Anschließend können Sie den Anwendungskontext in einer beliebigen statischen Methode wie folgt abrufen:

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

WARNUNG

Bevor Sie Ihrem Projekt etwas Ähnliches hinzufügen, sollten Sie überlegen, was in der Dokumentation steht:

Normalerweise muss die Anwendung nicht in Unterklassen unterteilt werden. In den meisten Situationen können statische Singletons dieselbe Funktionalität auf modularere Weise bereitstellen. Wenn Ihr Singleton einen globalen Kontext benötigt (zum Beispiel um Registrierungsempfänger zu registrieren), kann der Funktion zum Abrufen ein Kontext zugewiesen werden, der beim erstmaligen Erstellen des Singletons intern Context.getApplicationContext () verwendet.


BETRACHTUNG

Es gibt auch eine andere Möglichkeit, den Anwendungskontext mithilfe von Reflection abzurufen. Reflexion wird in Android oft herabgesetzt 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 ( ActivityThread ) aufrufen, 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 ( AppGlobals ), mit der der Anwendungskontext statisch abgerufen werden kann. Der Kontext wird verwendet, ActivityThreadsodass es wirklich keinen Unterschied zwischen der folgenden und der oben angegebenen Methode gibt:

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

Viel Spaß beim Codieren!

Jared Rummler
quelle
56

Angenommen, wir sprechen über das Abrufen des Anwendungskontexts, habe ich ihn implementiert, wie von @Rohit Ghatol vorgeschlagen. Was dann passiert ist, ist, dass es keine Garantie dafür gibt, dass der so abgerufene Kontext immer nicht null ist. Zu dem Zeitpunkt, an dem Sie es benötigen, können Sie normalerweise nicht verzögern, weil Sie einen Helfer initialisieren oder eine Ressource abrufen möchten. Die Behandlung des Nullfalls hilft Ihnen nicht weiter. Ich habe also verstanden, dass ich im Grunde gegen die Android-Architektur gekämpft habe, wie in den Dokumenten angegeben

Hinweis: Normalerweise muss die Anwendung nicht in Unterklassen unterteilt werden. In den meisten Situationen können statische Singletons dieselbe Funktionalität auf modularere Weise bereitstellen. Wenn Ihr Singleton einen globalen Kontext benötigt (zum Beispiel zum Registrieren von Broadcast-Empfängern), geben Sie Context.getApplicationContext () als Context-Argument an, wenn Sie die getInstance () -Methode 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 mich einer unserer Anwendungsentwickler während der Entwicklung vor 1.0 ständig daran gehindert hat, ein Anwendungsobjekt der obersten Ebene zu benötigen, von dem sie abgeleitet werden können, damit sie ein "normaleres" haben können "zu ihnen Anwendungsmodell, und ich gab schließlich nach. Ich werde es für immer bereuen, diesem nachgegeben zu haben. :) :)

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

Wenn Sie einen globalen Status wünschen, der für verschiedene Teile Ihrer App freigegeben werden kann, verwenden Sie einen Singleton. [...] Und dies führt natürlicher dazu, wie Sie diese Dinge verwalten sollten - sie bei Bedarf zu initialisieren.

Ich habe also die Erweiterung von Application entfernt und den Kontext direkt an getInstance () des Singleton-Helfers übergeben, während ich einen Verweis auf den Anwendungskontext im privaten Konstruktor gespeichert habe:

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 Anrufer übergibt dann einen lokalen Kontext an den Helfer:

Helper.getInstance(myCtx).doSomething();

Um diese Frage richtig zu beantworten: Es gibt Möglichkeiten, statisch auf den Anwendungskontext zuzugreifen, aber alle sollten entmutigt werden, und Sie sollten es vorziehen, einen lokalen Kontext an getInstance () des Singletons zu übergeben.


Für alle Interessierten können Sie eine ausführlichere Version im fwd-Blog lesen

Alessio
quelle
1
@Alessio Führt diese Methode nicht zu Speicherlecks
Phillip Kigenyi
2
@codephillip Ich verstehe nicht, wovon du sprichst. Der Singleton verweist auf den Anwendungskontext, der aus der übergebenen Aktivität abgerufen wurde, nicht auf die Hostaktivität. Das ist legitim und verursacht keinen Speicherverlust. Das ist der Hauptpunkt des Blogs, den ich geschrieben habe. Wenn Sie wirklich glauben, dass Sie Recht haben, senden Sie mir bitte einen Beispielcode, mit dem ich den Speicherverlust reproduzieren kann, von dem Sie sprechen, da dies nicht der Fall ist.
Alessio
1
Ich denke, @KigenyiPhillip ist korrekt, und dies stellt immer noch ein Ressourcenleck dar. Stellen Sie sich die Referenzkarte nach Ihrem ersten Anruf bei vor getInstance(ctx). Sie haben einen GC-Stamm instancevom Typ MyHelper, der ein privates Feld mContextvom Typ hat Context, das auf den Anwendungskontext verweist, der über den an übergebenen Kontext gesammelt wurde getInstance(). instancewird niemals ein zweites Mal festgelegt oder gelöscht, sodass GC niemals den App-Kontext abfängt, auf den verwiesen wirdinstance . Sie verlieren keine Aktivitäten, so dass es IMO kostengünstig ist.
Mark McKenna
1
@MarkMcKenna, wie Sie angeben, "das ein privates Feld mContext vom Typ Context hat, das auf den Anwendungskontext verweist", sodass Ihnen klar ist, dass mContext ein Verweis auf den Anwendungskontext und nicht auf einen Kontext ist. Im Dokumenten von getApplicationContext () lesen Sie: "Ein Kontext, dessen Lebenszyklus vom aktuellen Kontext getrennt ist und der eher an die Lebensdauer des Prozesses als an die aktuelle Komponente gebunden ist". Wie kann dies zu einem Speicherverlust führen? Der Anwendungskontext wird nur dann GC-fähig, wenn der Prozess beendet wird.
Alessio
1
@Alessio Wenn Sie akzeptieren, dass ein Verweis auf den Anwendungskontext nicht als Ressourcenleck qualifiziert ist, können Sie dies vereinfachen, indem Sie einen statischen Verweis auf thisin veröffentlichen Application.onCreate(), wodurch die akzeptierte Antwort besser wird.
Mark McKenna
49

Nein, ich glaube nicht. Leider können Sie nicht mehr getApplicationContext()von Activityoder einer der anderen Unterklassen von anrufen Context. Auch diese Frage ist etwas verwandt.

Erich Douglass
quelle
8
Der richtige Link zum Artikel: android-developers.blogspot.co.il/2009/01/…
Tal Weiss
38

Hier ist eine undokumentierte Möglichkeit, eine Anwendung (die ein Kontext ist) von einer beliebigen Stelle im UI-Thread abzurufen. Es basiert auf der versteckten statischen Methode ActivityThread.currentApplication(). Es sollte mindestens unter 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. B. wenn Sie die Methode außerhalb des UI-Threads aufrufen oder die Anwendung nicht an den Thread gebunden ist.

Es ist immer noch besser, die Lösung von @RohitGhatol zu verwenden , wenn Sie den Anwendungscode ändern können.

kennytm
quelle
1
Ich habe die obige Methode KennyTM verwendet, aber manchmal gibt die Methode null zurück. Gibt es eine andere Alternative dazu? Wenn wir hier eine Null erhalten, können wir den Kontext von einer anderen Stelle abrufen. In meinem Fall wird onCreate () von Application nicht aufgerufen. Aber die obige Methode wird vorher aufgerufen. Plzzz Hilfe
AndroidGuy
Dies funktioniert nicht immer in dem Fall, in dem GC alle aktivitätsbezogenen Dinge entfernt hat.
AlexVPerl
32

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

Wenn Sie versuchen, ein AlertDialogmit zu erstellen AlertDialog.Builder, Applicationfunktioniert der Kontext nicht. Ich glaube, Sie brauchen den Kontext für die aktuelle Activity...

Gulchrider
quelle
6
Das stimmt. Wenn Sie dafür den Anwendungskontext verwenden, wird Ihr Dialogfeld möglicherweise unter den Aktivitäten im Vordergrund ausgeblendet.
Nate
3
+1 zuallererst. Und der mögliche Fehler ist, dass die Aktivität ComponentInfo {com.samples / com.MyActivity} nicht gestartet werden kann: android.view.WindowManager $ BadTokenException: Window-Token null kann nicht hinzugefügt werden, ist nicht für eine Anwendung
Govind
15

Kotlin Weg :

Manifest:

<application android:name="MyApplication">

</application>

MyApplication.kt

class MyApplication: Application() {

    override fun onCreate() {
        super.onCreate()
        instance = this
    }

    companion object {
        lateinit var instance: MyApplication
            private set
    }
}

Sie können dann über auf die Unterkunft zugreifen MyApplication.instance

phnmnn
quelle
11

Wenn Sie RoboGuice verwenden möchten , können Sie den Kontext in jede gewünschte Klasse einfügen . Hier ist ein kleines Beispiel, wie es mit RoboGuice 2.0 (Beta 4 zum Zeitpunkt dieses Schreibens) gemacht wird.

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) {
        }
    }
}
user605331
quelle
8

Ich habe das irgendwann benutzt:

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

Dies ist ein gültiger Kontext, den ich beim Abrufen von Systemdiensten und beim Arbeiten verwendet habe.

Aber ich habe es nur in Framework- / Basismodifikationen verwendet und es nicht in Android-Anwendungen ausprobiert.

Eine Warnung , die Sie wissen müssen: Wenn Sie sich für Rundfunkempfänger in diesem Kontext registrieren, funktioniert dies nicht und Sie erhalten:

java.lang.SecurityException: Das angegebene Aufruferpaket android wird im Prozess ProcessRecord nicht ausgeführt

ungalcrys
quelle
7

Kotlin

open class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        mInstance = this
    }

    companion object {
        lateinit var mInstance: MyApp
        fun getContext(): Context? {
            return mInstance.applicationContext
        }
    }
}

und Kontext wie bekommen

MyApp.mInstance

oder

MyApp.getContext()
Khemraj
quelle
4

Sie können Folgendes verwenden:

MainActivity.this.getApplicationContext();

MainActivity.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();
barwnikk
quelle
3
Dies funktioniert nur, wenn Sie sich in einer inneren Klasse befinden, was im OP kaum der Fall ist.
Richard J. Ross III
3
Dies würde funktionieren, solange ANY_METHOD aufgerufen wird, nachdem MainActivity erstellt wurde. Wenn Sie jedoch statische Verweise auf Aktivitäten beibehalten, führt dies fast zwangsläufig zu Speicherverlusten (wie in anderen Antworten auf die Frage von OP bereits erwähnt). Wenn Sie also wirklich einen statischen Verweis behalten müssen, verwenden Sie die Anwendung nur Kontext.
Handwerk
1
Innere Klassen sind böse. Das Schlimmste ist, dass viele Leute das für AsyncTasks und ähnliche Dinge tun, weil viele Tutorials es so machen ...
Reinherd
4

Wenn Sie die Manifestdatei nicht ändern möchten, können Sie den Kontext in Ihrer anfänglichen Aktivität manuell in einer statischen Variablen speichern:

public class App {
    private static Context context;

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

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

Und legen Sie einfach den Kontext fest, wenn Ihre Aktivität (oder Aktivitäten) beginnen:

// MainActivity

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

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

    // Other stuff
}

Hinweis: Wie bei allen anderen Antworten handelt es sich um einen potenziellen Speicherverlust.

Sheharyar
quelle
1
Was genau wird es lecken, da der Kontext in diesem Fall an die Anwendung gebunden ist? Wenn die Anwendung stirbt, stirbt auch alles andere.
TheRealChx101
3

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

public static Context getAppContext()
   return MyApplication.context; 
Kognos
quelle
3

Laut dieser Quelle können Sie Ihren eigenen Kontext erhalten, indem Sie ContextWrapper erweitern

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

JavaDoc für ContextWrapper

Proxy-Implementierung von Context, die einfach alle Aufrufe an einen anderen Context delegiert. Kann in Unterklassen unterteilt werden, um das Verhalten zu ändern, ohne den ursprünglichen Kontext zu ändern.

BlueWizard
quelle
1
Das ist interessant. Gut, um mehr über ContextWrapper zu erfahren. Wenn Sie den Anwendungskontext jedoch an diesen Konstruktor übergeben müssen, müssen Sie ihn dennoch von irgendwoher abrufen.
jk7
2

Wenn Sie aus irgendeinem Grund einen Anwendungskontext in einer Klasse wünschen, nicht nur in solchen, die die Anwendung / Aktivität erweitern, möglicherweise für einige Factory- oder Hilfsklassen. Sie können Ihrer App den folgenden Singleton hinzufügen.

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

Initialisieren Sie es dann in onCreate Ihrer Anwendungsklasse mit

GlobalAppContextSingleton.getInstance().initialize(this);

Verwenden Sie es überall, indem Sie anrufen

GlobalAppContextSingleton.getInstance().getApplicationContext()

Ich empfehle diesen Ansatz jedoch nur für den Anwendungskontext. Da es zu Speicherlecks kommen kann.

Versa
quelle
Es ist nicht so, dass die Klassen- / Methodennamen in Stein gemeißelt sind, sie lang und (hoffentlich) beschreibend für Fragen und Antworten gehalten und für meinen eigenen Gebrauch verkürzt haben.
Versa
1

Ich verwende eine Variation des Singleton-Entwurfsmusters, um mir dabei zu helfen.

import android.app.Activity;
import android.content.Context;

public class ApplicationContextSingleton {
    private static Activity gContext;

    public static void setContext( Activity activity) {
        gContext = activity;
    }

    public static Activity getActivity() {
        return gContext;
    }

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

Ich rufe dann ApplicationContextSingleton.setContext( this );in meinem activity.onCreate () und ApplicationContextSingleton.setContext( null );in onDestroy () ;

Bamaco
quelle
Wenn Sie nur Kontext benötigen, können Sie activity.getApplicationContext () aufrufen. Das kann statisch festgehalten werden, ohne sich um Undichtigkeiten sorgen zu müssen.
MinceMan
2
Dies führt zu Speicherlecks
BlueWizard
1

Ich habe gerade ein von jQuery inspiriertes Framework für Android namens Vapor API veröffentlicht , das die App-Entwicklung vereinfachen soll.

Die zentrale $ Fassadenklasse verwaltet einen WeakReference(Link zu einem großartigen Java-Blog-Beitrag von Ethan Nicholas) zum aktuellen ActivityKontext, den Sie abrufen können, indem Sie Folgendes aufrufen:

$.act()

EIN WeakReference verwaltet eine Referenz, ohne zu verhindern, dass die Garbage Collection das ursprüngliche Objekt zurückfordert, sodass Sie kein Problem mit Speicherlecks haben sollten.

Der Nachteil ist natürlich, dass Sie das Risiko $.act()eingehen, null zurückzugeben. Ich bin jedoch noch nicht auf dieses Szenario gestoßen, daher ist es vielleicht nur ein minimales Risiko, das es wert ist, erwähnt zu werden.

Sie können den Kontext auch manuell festlegen, wenn Sie ihn nicht verwenden VaporActivity als ActivityKlasse verwenden:

$.act(Activity);

Auch ein Großteil der Vapor-API- Frameworks diesen gespeicherten Kontext von Natur aus, was bedeuten kann, dass Sie ihn überhaupt nicht selbst speichern müssen, wenn Sie sich für die Verwendung des Frameworks entscheiden. Schauen Sie sich die Website anWeitere Informationen und Beispiele finden .

Ich hoffe das hilft :)

Darius
quelle
1
Anscheinend wurde dies gerade herabgestimmt. Eine Erklärung wäre schön!?
Darius
1
Ich habe dies nicht abgelehnt, aber Javascript hat nichts mit der vorliegenden Frage zu tun, die eventuelle Abstimmungen erklären würde, die Sie möglicherweise hatten! Prost.
Ernani Joppert
Das wäre ziemlich unsinnig, da es von einigen Aspekten von jQuery wie einer fließenden Benutzeroberfläche und seinen Abstraktionen inspiriert ist . Dies sind Prinzipien, die für die zugrunde liegende Sprache agnostisch sind!
Darius
1
Sie stimmen also ab, weil es von der API-Semantik eines Frameworks inspiriert wurde, das sich nicht auf derselben Plattform befindet?! Ich denke, ihr verpasst den Punkt, plattformunabhängige Prinzipien anzuwenden .....................................
Darius
3
Diese Antwort hat nichts mit JavaScript zu tun. Lesen Sie die Antwort, bevor Sie abstimmen: /
BlueWizard
1

Rohits Antwort scheint richtig zu sein. Beachten Sie jedoch, dass AndroidStudios "Instant Run" meines Wissens davon abhängt, dass static ContextIhr Code keine Attribute enthält.

payne
quelle
1
Du hast recht. Und es kommt auch zu Speicherlecks!
user1506104
1

Wenn Sie in Kotlin Context / App Context in das Begleitobjekt einfügen, wird weiterhin eine Warnung ausgegeben Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run)

oder wenn Sie so etwas verwenden:

    companion object {
        lateinit var instance: MyApp
    }

Es täuscht nur die Flusen, den Speicherverlust nicht zu entdecken. Die App-Instanz kann immer noch einen Speicherverlust erzeugen, da die Anwendungsklasse und ihr Nachkomme ein Kontext sind.

Alternativ können Sie eine funktionale Schnittstelle oder funktionale Eigenschaften verwenden, um Ihren App-Kontext abzurufen.

Erstellen Sie einfach eine Objektklasse:

object CoreHelper {
    lateinit var contextGetter: () -> Context
}

oder Sie könnten es sicherer verwenden, indem Sie den Typ nullable verwenden:

object CoreHelper {
    var contextGetter: (() -> Context)? = null
}

und fügen Sie in Ihrer App-Klasse diese Zeile hinzu:


class MyApp: Application() {

    override fun onCreate() {
        super.onCreate()
        CoreHelper.contextGetter = {
            this
        }
    }
}

und deklarieren Sie in Ihrem Manifest den App-Namen zu . MyApp


    <application
            android:name=".MyApp"

Wenn Sie den Kontext erhalten möchten, rufen Sie einfach an:

CoreHelper.contextGetter()

// or if you use the nullable version
CoreHelper.contextGetter?.invoke()

Hoffe es wird helfen.

Hayi Nukman
quelle
Die Objektklasse dieses Corehelper wird initialisiert und kann zu einem späteren Zeitpunkt für alle Aktivitäten verwendet werden. Entschuldigung, ich bin neu bei kotlin
Dr. aNdRO
ja genau.
Hayi Nukman
-1

Versuchen Sie so etwas

import androidx.appcompat.app.AppCompatActivity;  
import android.content.Context; 
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    private static Context context;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        context = getApplicationContext();
    }

    public static void getContext(View view){
        Toast.makeText(context, "Got my context!",
                    Toast.LENGTH_LONG).show();    
    }
}
Chandra Shekar
quelle