Verwenden von getResources () in einer Nichtaktivitätsklasse


123

Ich versuche, die Methode getResources in einer Klasse ohne Aktivität zu verwenden. Wie erhalte ich den Verweis auf das Objekt "resources", damit ich auf die im Ressourcenordner gespeicherte XML-Datei zugreifen kann?

Beispiel:

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

Normalerweise ist es keine gute Idee, ContextObjekte in Android weiterzugeben . Dies kann zu Speicherlecks führen. Siehe meine Antwort für eine weniger riskante Lösung.
Jason Crosby

Antworten:


147

Sie müssen ein contextObjekt daran übergeben. Entweder thiswenn Sie einen Verweis auf die Klasse in einer Aktivität haben, odergetApplicationContext()

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

Dann können Sie es im Konstruktor verwenden (oder auf eine Instanzvariable setzen):

public class RegularClass(){
    private Context context;

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

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

Wobei der Konstruktor Contextals Parameter akzeptiert


7
Normalerweise ist es keine gute Idee, ContextObjekte in Android weiterzugeben . Dies kann zu Speicherlecks führen.
Jason Crosby

28
Als Faustregel sicher, aber ich finde das etwas irreführend. ContextObjekte sind böse, weil es nicht sofort offensichtlich ist, ob sie anwendungs- oder aktivitätsweit sind. Speicherlecks (und Abstürze) treten auf, wenn Sie die falsche angeben. Zum Beispiel kann eine Zuführung Activityzu einem statischen Objekt , das eine muss ContextObjekt und der nicht zerstört wird, wenn das Activityist , führt zu dem Activitynach onDestroy persistierenden, da es nicht GCed aufgrund dieses anderen statischen Objekts sein kann. Ja, es kann gefährlich sein, aber es ist wichtig zu wissen, warum es gefährlich ist.
Dororo

2
^ Dororo, dies ist einer der wichtigsten Kommentare, die ich je gelesen habe. Die richtige Verwendung des Kontexts wird selten oder nie diskutiert. Ich habe das Gefühl, dass ich so manchen unerklärlichen Fehler hatte!
Jonathan Dunn

@ Dororo Hast du einen Übungsvorschlag? Sollten wir versuchen zu vermeiden, Kontextvariablen zu übergeben? Was können wir dann tun, wenn wir eine API aus der Aktivitätsklasse benötigen?
Alston

35

Es ist keine gute Idee, ContextGegenstände herumzugeben. Dies führt häufig zu Speicherlecks. Mein Vorschlag ist, dass Sie es nicht tun. Ich habe zahlreiche Android-Apps erstellt, ohne den Kontext an Nicht-Aktivitätsklassen in der App übergeben zu müssen. Eine bessere Idee wäre, die Ressourcen zu erhalten, auf die Sie zugreifen müssen, während Sie im Activityoder sind Fragment, und sie in einer anderen Klasse zu behalten. Sie können diese Klasse dann in allen anderen Klassen in Ihrer App verwenden, um auf die Ressourcen zuzugreifen, ohne ContextObjekte weitergeben zu müssen.


Dies ist ein guter Rat, danke. Wäre es ein Problem in einem SQLiteOpenHelper? Im Konstruktor müssen Sie einen Kontext übergeben. Es ist in den anderen Methoden nicht mehr verfügbar, aber ich könnte es in einem privaten Feld speichern.
Peter

2
@Peter Ja, es gibt einige Klassen, bei denen Sie ein Kontextobjekt übergeben müssen. Versuchen Sie daher am besten, nur Klassen wie SqLiteOpenHelper in einer Aktivität oder einem Fragment zu verwenden, damit Sie das Kontextobjekt nicht weitergeben müssen. Wenn dies unvermeidbar ist, stellen Sie einfach sicher, dass Sie Ihren Verweis auf das Kontextobjekt auf null setzen, wenn Sie fertig sind, um das Risiko von Speicherverlusten zu verringern.
Jason Crosby

1
Das Übergeben von Kontextobjekten ist nicht immer schlecht, solange Sie den Lebenszyklus der Aktivität überwachen können. Wenn nicht, verwenden Sie besser den Anwendungskontext anstelle des Aktivitätskontexts mit getApplicationContext (), um Speicherverluste zu vermeiden. Informationen zum Abrufen des Anwendungskontexts finden Sie unter stackoverflow.com/questions/7144177/… .
FrozenFire

14

Es gibt noch einen Weg, ohne auch ein Objekt zu erstellen. Überprüfen Sie die Referenz . Danke für @cristian. Unten füge ich die Schritte hinzu, die in der obigen Referenz erwähnt wurden. Für mich mag ich es nicht, ein Objekt dafür zu erstellen und darauf zuzugreifen. Also habe ich versucht, auf das zuzugreifen, getResources()ohne ein Objekt zu erstellen. Ich habe diesen Beitrag gefunden. Also dachte ich, es als Antwort hinzuzufügen.

Befolgen Sie die Schritte, um getResources()in einer Nicht-Aktivitätsklasse without passing a contextüber das Objekt zuzugreifen .

  • Erstellen Sie eine Unterklasse von Application, zum Beispiel public class App extends Application {. Lesen Sie den Code neben den Schritten.
  • Setzen Sie das android:nameAttribut Ihres <application>Tags in AndroidManifest.xml, um auf Ihre neue Klasse zu verweisen, zandroid:name=".App"
  • onCreate()Speichern Sie in der Methode Ihrer App-Instanz Ihren Kontext (z. B. this) in einem statischen Feld mit dem Namen appund erstellen Sie eine statische Methode, die dieses Feld zurückgibt, z getContext().
  • Jetzt können Sie verwenden: App.getContext()wann immer Sie einen Kontext erhalten möchten, und dann können wir verwenden App.getContext().getResources(), um Werte aus den Ressourcen abzurufen.

So sollte es aussehen:

public class App extends Application{

    private static Context mContext;

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

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

5

Hier ist meine Antwort:

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

}}

und der Anruf kann so sein:

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

3

Dies kann mit erfolgen

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

Nun, das hat die Magie für mich getan. Danke @ARAsha
Kenny Dabiri

Passieren ContextObjekte ist nicht eine gesunde Praxis
Vemuri Pavan

3

Wir können den Kontext so verwenden. Versuchen Sie es jetzt. Wo das übergeordnete Element die ViewGroup ist.

Context context = parent.getContext();

1

Nun, es ist nicht nötig, den Kontext weiterzugeben und all das zu tun ... tun Sie dies einfach

Context context = parent.getContext();

Bearbeiten: wobei übergeordnet die ViewGroup ist


3
Ich gehe davon aus, dass Sie wegen der Annahme, dass es eine praktische übergeordnete Mitgliedsvariable "ViewGroup" gibt, abgelehnt wurden. Eher dumme Annahme.
arnt

1

Das funktioniert bei mir immer:

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...

}

Nicht im Zusammenhang mit dieser Frage, aber Beispiel für die Verwendung eines Fragments für den Zugriff auf Systemressourcen / -aktivitäten wie folgt:

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

In der Reiseleiter-App von Udacitys Basic ANdroid-Kurs habe ich das Konzept der Fragmente verwendet. Ich blieb eine Weile stecken und hatte Schwierigkeiten, auf einige String-Ressourcen zuzugreifen, die in Strings, XML-Datei, beschrieben sind. Endlich eine Lösung.

Dies ist die Hauptaktivitätsklasse

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

Dies ist die Nicht-Aktivitätsklasse, die FragmentPageAdapter erweitert

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

In einer einfachen Klasse deklarieren Sie den Kontext und rufen Daten aus der Datei aus dem Ordner res ab

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

        }
}

In der Aktivitätsklasse deklarieren Sie dies so

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

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

}

0

Ich bin spät dran, aber vollständige Lösung;: Beispielklasse, Verwenden Sie den Kontext wie folgt: -

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

Warnung (Speicherlecks)

Wie kann man das lösen?

Option 1 : Anstatt den Aktivitätskontext, dh diesen, an die Singleton-Klasse zu übergeben, können Sie applicationContext () übergeben.

Option 2: Wenn Sie den Aktivitätskontext wirklich verwenden müssen, stellen Sie bei Zerstörung der Aktivität sicher, dass der Kontext, den Sie an die Singleton-Klasse übergeben haben, auf null gesetzt ist.

Hoffe es hilft..∆∆∆∆


0

in Ihrer Hauptaktivität:

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

dann benutze es überall

String s = ResourcesHelper.resources.getString(R.string.app_name);
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.