Utilisation de getResources () dans une classe sans activité


123

J'essaye d'utiliser la méthode getResources dans une classe de non-activité. Comment puis-je obtenir la référence à l'objet «ressources» pour pouvoir accéder au fichier xml stocké dans le dossier des ressources?

Exemple:

XmlPullParser xpp = getResources().getXml(R.xml.samplexml);

Ce n'est normalement pas une bonne idée de faire circuler des Contextobjets dans Android. Cela peut entraîner des fuites de mémoire. Voir ma réponse pour une solution moins risquée.
Jason Crosby

Réponses:


147

Vous devrez lui passer un contextobjet. Soit thissi vous avez une référence à la classe dans une activité, soitgetApplicationContext()

public class MyActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        RegularClass regularClass = new RegularClass(this);
    }
}

Ensuite, vous pouvez l'utiliser dans le constructeur (ou le définir sur une variable d'instance):

public class RegularClass(){
    private Context context;

    public RegularClass(Context current){
        this.context = current;
    }

    public findResource(){
        context.getResources().getXml(R.xml.samplexml);
    }
}

Où le constructeur accepte Contextcomme paramètre


7
Ce n'est normalement pas une bonne idée de faire circuler des Contextobjets dans Android. Cela peut entraîner des fuites de mémoire.
Jason Crosby

28
En règle générale, bien sûr, mais je pense que c'est quelque peu trompeur. Contextles objets sont désagréables car il n'est pas immédiatement évident s'ils concernent l'ensemble de l'application ou de l'activité. Des fuites de mémoire (et des plantages) se produisent lorsque vous fournissez le mauvais. Par exemple, fournir un Activityà un objet statique qui a besoin d'un Contextet ledit objet n'est pas détruit lorsque le Activityest conduit à la Activitypersistance après onDestroy, car il ne peut pas être GC en raison de cet autre objet statique. Alors oui, cela peut être dangereux, mais sachant pourquoi c'est dangereux, je pense qu'il est important de le mentionner ici.
Dororo le

2
^ Dororo, c'est l'un des commentaires les plus importants que j'ai jamais lus. La bonne utilisation du contexte est rarement, voire jamais, discutée. J'ai le sentiment que j'ai eu beaucoup de bogues inexplicables à cause de cela!
Jonathan Dunn

@Dororo Alors, avez-vous des suggestions de pratique? Doit-on essayer d'éviter de passer des variables de contexte? Alors que pouvons-nous faire lorsque nous avons besoin d'une API de la classe d'activité?
Alston

35

Ce n'est pas une bonne idée de faire Contextcirculer des objets. Cela conduira souvent à des fuites de mémoire. Ma suggestion est que vous ne le faites pas. J'ai créé de nombreuses applications Android sans avoir à passer de contexte à des classes non liées à l'activité dans l'application. Une meilleure idée serait d'obtenir les ressources auxquelles vous avez besoin d'accéder pendant que vous êtes dans le Activityou Fragmentet de les conserver dans une autre classe. Vous pouvez ensuite utiliser cette classe dans toutes les autres classes de votre application pour accéder aux ressources, sans avoir à passer d' Contextobjets.


C'est un bon conseil merci. Serait-ce un problème dans un SQLiteOpenHelper? Dans le constructeur, vous devez passer un contexte. Il n'est plus disponible dans les autres méthodes mais je pourrais le stocker dans un champ privé.
Peter

2
@Peter Oui, certaines classes nécessitent que vous passiez un objet de contexte. Il est donc préférable d'essayer de n'utiliser que ces classes comme SqLiteOpenHelper dans une activité ou un fragment afin de ne pas avoir à transmettre un objet de contexte. Si cela est inévitable, assurez-vous de définir votre référence à l'objet de contexte sur null lorsque vous avez terminé pour réduire le risque de fuites de mémoire.
Jason Crosby

1
Passer un objet de contexte n'est pas toujours mauvais, tant que vous pouvez surveiller le cycle de vie de l'activité. Sinon, mieux vaut utiliser le contexte d'application au lieu du contexte d'activité en utilisant getApplicationContext () pour éviter les fuites de mémoire. Voir stackoverflow.com/questions/7144177/… pour récupérer le contexte de l'application.
FrozenFire

14

Il existe un autre moyen sans créer d'objet également. Vérifiez la référence . Merci pour @cristian. Ci-dessous, j'ajoute les étapes mentionnées dans la référence ci-dessus. Pour moi, je n'aime pas créer un objet pour cela et y accéder. J'ai donc essayé d'accéder au getResources()sans créer d'objet. J'ai trouvé ce post. J'ai donc pensé à l'ajouter comme réponse.

Suivez les étapes pour accéder getResources()à une classe sans activité without passing a contextvia l'objet.

  • Créez une sous-classe de Application, par exemple public class App extends Application {. Reportez-vous au code à côté des étapes.
  • Définissez l' android:nameattribut de votre <application>balise dans AndroidManifest.xmlpour pointer vers votre nouvelle classe, par exempleandroid:name=".App"
  • Dans la onCreate()méthode de votre instance d'application, enregistrez votre contexte (par exemple this) dans un champ statique nommé appet créez une méthode statique qui renvoie ce champ, par exemple getContext().
  • Vous pouvez maintenant utiliser: App.getContext()chaque fois que vous souhaitez obtenir un contexte, puis nous pouvons utiliser App.getContext().getResources()pour obtenir des valeurs à partir des ressources.

Voici à quoi cela devrait ressembler:

public class App extends Application{

    private static Context mContext;

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

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

5

voici ma réponse:

public class WigetControl {
private Resources res;

public WigetControl(Resources res) 
{
    this.res = res;
}

public void setButtonDisable(Button mButton)
{
    mButton.setBackgroundColor(res.getColor(R.color.loginbutton_unclickable));
    mButton.setEnabled(false);
}

}

et l'appel peut être comme ceci:

        WigetControl control = new WigetControl(getResources());
        control.setButtonDisable(btNext);

3

cela peut être fait en utilisant

context.getResources().getXml(R.xml.samplexml);

Eh bien, cela a fait la magie pour moi. Merci @ARAsha
Kenny Dabiri

passer des Contextobjets n'est pas une pratique saine
Vemuri Pavan

3

Nous pouvons utiliser le contexte comme celui-ci, essayez maintenant Où le parent est le ViewGroup.

Context context = parent.getContext();

1

bon pas besoin de passer le contexte et de faire tout ça ... faites simplement ceci

Context context = parent.getContext();

Edit: où le parent est le ViewGroup


3
Je suppose que vous avez été critiqué pour avoir supposé qu'il existe une variable membre 'ViewGroup parent' pratique. Hypothèse plutôt stupide.
arnt

1

Ça fonctionne toujours pour moi:

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

public class yourClass {

 Context ctx;

 public yourClass (Handler handler, Context context) {
 super(handler);
    ctx = context;
 }

 //Use context (ctx) in your code like this:
 XmlPullParser xpp = ctx.getResources().getXml(R.xml.samplexml);
 //OR
 final Intent intent = new Intent(ctx, MainActivity.class);
 //OR
 NotificationManager notificationManager = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
 //ETC...

}

Pas lié à cette question mais exemple d'utilisation d'un fragment pour accéder aux ressources / activités du système comme ceci:

public boolean onQueryTextChange(String newText) {
 Activity activity = getActivity();
 Context context = activity.getApplicationContext();
 returnSomething(newText);
 return false;
}

View customerInfo = getActivity().getLayoutInflater().inflate(R.layout.main_layout_items, itemsLayout, false);
 itemsLayout.addView(customerInfo);

1

Dans l'application de guide touristique du cours Basic ANdroid d'Udacity, j'ai utilisé le concept de Fragments. Je suis resté bloqué pendant un certain temps, rencontrant des difficultés pour accéder à certaines ressources de chaîne décrites dans des chaînes, un fichier xml. J'ai enfin une solution.

Ceci est la classe d'activité principale

package com.example.android.tourguidekolkata;

import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState)
{
  //lines of code
   //lines of code
    //lines of code
    YourClass adapter = new YourClass(getSupportFragmentManager(), getApplicationContext()); 
    //lines of code
    // getApplicationContext() method passses the Context of main activity to the class TourFragmentPageAdapter 
}
}

Il s'agit de la classe non Activity qui étend FragmentPageAdapter

public class YourClass extends FragmentPagerAdapter {
private String yourStringArray[] = new String[4];
Context context;

public YourClass (FragmentManager fm, Context context)
{
    super(fm);
    this.context = context; // store the context of main activity
    // now you can use this context to access any resource 
    yourStringArray[0] = context.getResources().getString(R.string.tab1);
    yourStringArray[1] = context.getResources().getString(R.string.tab2);
    yourStringArray[2] = context.getResources().getString(R.string.tab3);
    yourStringArray[3] = context.getResources().getString(R.string.tab4);
}
@Override
public Fragment getItem(int position)
 {
 }
@Override
public int getCount() {
return 4;
}

@Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
return yourStringArras[position];
}
}

0

Dans une classe simple, déclarez le contexte et récupérez les données du fichier du dossier res

public class FileData
{
      private Context context;

        public FileData(Context current){
            this.context = current;
        }
        void  getData()
        {
        InputStream in = context.getResources().openRawResource(R.raw.file11);
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        //write stuff to get Data

        }
}

Dans la classe d'activité, déclarez comme ceci

public class MainActivity extends AppCompatActivity 
{
 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        FileData fileData=new FileData(this);
     }

}

0

Je suis une solution en retard mais complète;: Exemple de classe, utilisez le contexte comme ceci: -

public class SingletonSampleClass {

    // Your cute context
    private Context context;
    private static SingletonSampleClass instance;

  // Pass as Constructor
    private SingletonSampleClass(Context context) {
        this.context = context;
    }

    public synchronized static SingletonSampleClass getInstance(Context context) {
        if (instance == null) instance = new SingletonSampleClass(context);
        return instance;
    }

//At end, don't forgot to relase memory
    public void onDestroy() {
       if(context != null) {
          context = null; 
       }
    }
}

Avertissement (fuites de mémoire)

Comment résoudre ça?

Option 1 : Au lieu de passer le contexte d'activité, c'est-à-dire celui-ci à la classe singleton, vous pouvez passer applicationContext ().

Option 2: si vous devez vraiment utiliser le contexte d'activité, lorsque l'activité est détruite, assurez-vous que le contexte que vous avez passé à la classe singleton est défini sur null.

J'espère que ça aide..∆∆∆∆


0

dans votre MainActivity:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(ResourcesHelper.resources == null){
             ResourcesHelper.resources = getResources();
        }
    }
}

ResourcesHelper:

public class ResourcesHelper {
    public static Resources resources;
}

puis utilisez-le partout

String s = ResourcesHelper.resources.getString(R.string.app_name);
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.