Question Manière statique d'obtenir le 'Contexte' dans Android?


Y at-il un moyen d'obtenir le courant Context instance à l'intérieur d'une méthode statique?

Je cherche de cette façon parce que je déteste sauvegarder l'instance 'Context' chaque fois qu'elle change.


812
2018-01-04 21:15


origine


Réponses:


Faites ceci:

Dans le fichier manifeste Android, déclarez ce qui suit.

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

</application>

Ensuite, écrivez la classe:

public class MyApplication extends Application {

    private static Context context;

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

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

Maintenant appelez partout MyApplication.getAppContext() pour obtenir le contexte de votre application de manière statique.


1144
2018-02-25 06:37



La majorité des applications qui veulent une méthode pratique pour obtenir le contexte de l'application créent leur propre classe qui étend android.app.Application.

GUIDER

Vous pouvez accomplir ceci en créant d'abord une classe dans votre projet comme suit:

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

Ensuite, dans votre AndroidManifest, vous devez spécifier le nom de votre classe dans la balise AndroidManifest.xml:

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

Vous pouvez ensuite récupérer le contexte de l'application dans n'importe quelle méthode statique en utilisant ce qui suit:

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

ATTENTION

Avant d'ajouter quelque chose comme ce qui précède à votre projet, vous devriez considérer ce que dit la documentation:

Il n'y a normalement pas besoin de sous-classe Application. Dans la plupart des cas,   singletons statiques peuvent fournir la même fonctionnalité dans un plus modulaire   façon. Si votre singleton a besoin d'un contexte global (par exemple pour vous inscrire   récepteurs de diffusion), la fonction de récupération peut être   Contexte qui utilise en interne Context.getApplicationContext () lorsque   d'abord construire le singleton.


RÉFLEXION

Il existe également une autre façon d'obtenir le contexte de l'application en utilisant la réflexion. La réflexion est souvent méprisée dans Android et je pense personnellement que cela ne devrait pas être utilisé dans la production.

Pour récupérer le contexte de l'application, nous devons invoquer une méthode sur une classe cachée (ActivityThread) disponible depuis API 1:

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

Il y a une classe cachée de plus (AppGlobals) qui fournit un moyen d'obtenir le contexte de l'application de manière statique. Il obtient le contexte en utilisant ActivityThread donc il n'y a vraiment aucune différence entre la méthode suivante et celle affichée ci-dessus:

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

Codage heureux!


59
2018-01-19 09:09



Non, je ne pense pas qu'il y en ait. Malheureusement, vous êtes coincé en train d'appeler getApplicationContext() de Activity ou l'une des autres sous-classes de Context. Aussi, ce question est un peu liée.


49
2018-01-05 00:46



Voici un sans papiers façon d'obtenir un Application (qui est un contexte) de n'importe où dans le fil de l'interface utilisateur. Il repose sur la méthode statique cachée ActivityThread.currentApplication(). Il devrait fonctionner au moins sur 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
}

Notez qu'il est possible que cette méthode renvoie null, par ex. lorsque vous appelez la méthode en dehors du thread d'interface utilisateur ou que l'application n'est pas liée au thread.

Il est toujours préférable d'utiliser @RohitGhatolla solution si vous pouvez changer le code de l'application.


35
2017-09-19 13:34



Cela dépend de ce pour quoi vous utilisez le contexte. Je peux penser à au moins un désavantage à cette méthode:

Si vous essayez de créer un AlertDialog avec AlertDialog.Builder, la Application le contexte ne fonctionnera pas. Je crois que vous avez besoin du contexte pour le courant Activity...


31
2017-08-12 01:07



En supposant que nous parlions d'obtenir le contexte d'application, je l'ai implémenté comme suggéré par @Rohit Ghatol prolongeant l'application. Ce qui s'est passé alors, c'est qu'il n'y a aucune garantie que le contexte récupéré d'une telle manière sera toujours non nul. Au moment où vous en avez besoin, c'est généralement parce que vous voulez initialiser un assistant, ou obtenir une ressource, que vous ne pouvez pas retarder dans le temps; la gestion du cas null ne vous aidera pas. J'ai donc compris que je me battais essentiellement contre l'architecture Android, comme indiqué dans le docs

Remarque: Il n'est normalement pas nécessaire de sous-classer Application. Dans la plupart des cas, les singletons statiques peuvent fournir la même fonctionnalité de manière plus modulaire. Si votre singleton a besoin d'un contexte global (par exemple pour enregistrer des récepteurs de diffusion), incluez Context.getApplicationContext () comme argument de contexte lors de l'appel de la méthode getInstance () de votre singleton.

et expliqué par Dianne Hackborn

La seule raison pour laquelle l'application existe comme quelque chose que vous pouvez dériver est parce que pendant le développement pré-1.0, un de nos développeurs d'applications m'avait continuellement mis en garde quant à la nécessité d'avoir un objet d'application de haut niveau. "leur modèle d'application, et j'ai finalement cédé.   Je regretterai toujours d'avoir cédé à celui-là. :)

Elle suggère également la solution à ce problème:

Si vous voulez un état global pouvant être partagé entre différentes parties de votre application, utilisez un singleton. [...] Et cela conduit plus naturellement à la façon dont vous devriez gérer ces choses - en les initialisant à la demande.

donc ce que j'ai fait était de se débarrasser de l'extension de l'application, et passer le contexte directement à getInstance () de l'assistant singleton, tout en sauvegardant une référence au contexte de l'application dans le constructeur privé:

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

l'appelant transmettra ensuite un contexte local à l'assistant:

Helper.getInstance(myCtx).doSomething();

Donc, pour répondre correctement à cette question: il existe des moyens d'accéder au contexte d'application de manière statique, mais ils devraient tous être déconseillés, et vous devriez préférer passer un contexte local à getInstance () du singleton.


Pour toute personne intéressée, vous pouvez lire une version plus détaillée à blog de fwd


28
2017-08-16 05:36



Si vous êtes ouvert à l'utilisation RoboGuice, vous pouvez avoir le contexte injecté dans n'importe quelle classe que vous voulez. Voici un petit exemple de comment faire avec RoboGuice 2.0 (beta 4 au moment de la rédaction de ce document)

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



J'ai utilisé ceci à un moment donné:

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

C'est un contexte valide que j'ai utilisé pour obtenir des services système et travaillé.

Mais, je l'ai utilisé uniquement dans les modifications de base / base et ne l'ai pas essayé dans les applications Android.

UNE Attention que vous devez savoir: Lorsque vous vous enregistrez pour des récepteurs de diffusion avec ce contexte, cela ne fonctionnera pas et vous obtiendrez:

java.lang.SecurityException: Le package d'appel donné android n'est pas en cours d'exécution ProcessRecord


8
2018-05-08 10:22



Je pense que vous avez besoin d'un corps pour le getAppContext() méthode:

public static Context getAppContext()
   return MyApplication.context; 

3
2017-08-18 14:15



Vous pouvez utiliser ce qui suit:

MainActivity.this.getApplicationContext();

MainActivity.java:

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

Toute autre classe:

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

3
2018-04-06 17:25



J'utilise une variation du modèle de conception de Singleton pour m'aider avec ceci.

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

J'appelle ensuite ApplicationContextSingleton.setContext( this ); dans mon activity.onCrée () et ApplicationContextSingleton.setContext( null ); dans onDestroy ();


2
2017-12-30 19:20