Utilizzo di getResources () nella classe di non attività


123

Sto cercando di utilizzare il metodo getResources in una classe di non attività. Come ottengo il riferimento all'oggetto "risorse" in modo da poter accedere al file xml archiviato nella cartella delle risorse?

Esempio:

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

Normalmente non è una buona idea passare gli Contextoggetti in Android. Può portare a perdite di memoria. Vedi la mia risposta per una soluzione meno rischiosa.
Jason Crosby

Risposte:


147

Dovrai passargli un contextoggetto. O thisse hai un riferimento alla classe in un'attività, ogetApplicationContext()

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

Quindi puoi usarlo nel costruttore (o impostarlo su una variabile di istanza):

public class RegularClass(){
    private Context context;

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

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

Dove il costruttore accetta Contextcome parametro


7
Normalmente non è una buona idea passare Contextoggetti in Android. Può portare a perdite di memoria.
Jason Crosby

28
Come regola pratica di base, certo, ma ritengo che questo sia in qualche modo fuorviante. Contextgli oggetti sono fastidiosi perché non è immediatamente ovvio se è a livello di applicazione o di attività. Perdite di memoria (e arresti anomali) si verificano quando si fornisce quello sbagliato. Ad esempio, fornire un Activitya un oggetto statico che necessita di un Contextoggetto e detto oggetto non viene distrutto quando Activityis porta alla Activitypersistenza dopo onDestroy, poiché non può essere GCed a causa di questo altro oggetto statico. Quindi sì, può essere pericoloso, ma sapendo perché è pericoloso credo sia importante menzionarlo qui.
Dororo

2
^ Dororo, questo è uno dei commenti più importanti che abbia mai letto. L'uso corretto del contesto è raramente, se non mai, discusso. Ho la sensazione di aver avuto molti bug inspiegabili a causa di ciò!
Jonathan Dunn

@Dororo Quindi hai qualche suggerimento pratico? Dovremmo cercare di evitare di passare variabili di contesto? Allora cosa possiamo fare quando abbiamo bisogno di alcune API dalla classe di attività?
Alston

35

Non è una buona idea passare Contextoggetti in giro. Questo spesso porterà a perdite di memoria. Il mio suggerimento è di non farlo. Ho creato numerose app Android senza dover passare il contesto a classi non di attività nell'app. Un'idea migliore sarebbe quella di ottenere le risorse a cui hai bisogno di accedere mentre sei in ActivityoFragment , e mantenerle in un'altra classe. Puoi quindi usare quella classe in qualsiasi altra classe nella tua app per accedere alle risorse, senza dover passare gli Contextoggetti.


Questo è un buon consiglio, grazie. Sarebbe un problema in un SQLiteOpenHelper? Nel costruttore, devi passare un contesto. Non è più disponibile negli altri metodi ma potrei memorizzarlo in un campo privato.
Peter,

2
@ Peter Sì, ci sono alcune classi che richiedono di passare un oggetto di contesto. Quindi è meglio provare a utilizzare solo quelle classi come SqLiteOpenHelper in un'attività o in un frammento in modo da non dover passare l'oggetto contesto. Se è inevitabile, assicurati di impostare il riferimento all'oggetto contesto su null quando hai finito per ridurre il rischio di perdite di memoria.
Jason Crosby

1
Il passaggio di un oggetto contesto non è sempre negativo, purché sia ​​possibile monitorare il ciclo di vita dell'attività. In caso contrario, utilizzare meglio il contesto dell'applicazione invece del contesto dell'attività utilizzando getApplicationContext () per evitare perdite di memoria. Vedere stackoverflow.com/questions/7144177/… per recuperare il contesto dell'applicazione.
FrozenFire

14

C'è anche un altro modo senza creare un oggetto. Controlla il riferimento . Grazie per @cristian. Di seguito aggiungo i passaggi menzionati nel riferimento precedente. Per me non mi piace creare un oggetto per questo e per l'accesso. Quindi ho provato ad accedere al getResources()senza creare un oggetto. Ho trovato questo post. Quindi ho pensato di aggiungerlo come risposta.

Segui i passaggi per accedere getResources()a una classe non di attività without passing a contexttramite l'oggetto.

  • Crea una sottoclasse di Application, ad esempio public class App extends Application {. Fare riferimento al codice accanto ai passaggi.
  • Imposta l' android:nameattributo del tuo <application>tag nel fileAndroidManifest.xml per puntare alla tua nuova classe, ad esandroid:name=".App"
  • Nel onCreate()metodo dell'istanza della tua app, salva il tuo contesto (ad es. this) In un campo statico denominato appe crea un metodo statico che restituisca questo campo, ad es.getContext() .
  • Ora puoi usare: App.getContext()ogni volta che vuoi ottenere un contesto, e poi possiamo usare App.getContext().getResources()per ottenere valori dalle risorse.

Ecco come dovrebbe apparire:

public class App extends Application{

    private static Context mContext;

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

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

5

ecco la mia risposta:

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

}

e la chiamata può essere così:

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

3

questo può essere fatto usando

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

Bene, questo ha fatto la magia per me. Grazie @ARAsha
Kenny Dabiri

passare Contextoggetti non è una pratica salutare
Vemuri Pavan

3

Possiamo usare il contesto In questo modo, prova ora Dove il genitore è il ViewGroup.

Context context = parent.getContext();

1

beh, non c'è bisogno di passare il contesto e fare tutto questo ... fallo semplicemente

Context context = parent.getContext();

Modifica: dove genitore è il ViewGroup


3
Mi aspetto che tu sia stato downvoted per aver assunto che esiste una comoda variabile membro "ViewGroup parent". Assunzione piuttosto stupida.
arnt

1

Questo funziona sempre per me:

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

}

Non correlato a questa domanda, ma ad esempio utilizzando un frammento per accedere a risorse / attività di sistema come questa:

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

Nell'app della guida turistica del corso Basic ANdroid di Udacity ho utilizzato il concetto di frammenti. Sono rimasto bloccato per un po 'riscontrando difficoltà ad accedere ad alcune risorse di stringa descritte in stringhe, file xml. Finalmente ho una soluzione.

Questa è la principale classe di attività

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

Questa è la classe non Activity che estende 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

Nella classe semplice dichiara il contesto e recupera i dati dal file dalla cartella 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

        }
}

Nella classe di attività dichiarare in questo modo

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

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

}

0

Sono in ritardo ma soluzione completa ;: Classe di esempio, Usa contesto in questo modo: -

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

Avviso (perdite di memoria)

Come risolverlo?

Opzione 1 : invece di passare il contesto dell'attività, cioè questo alla classe singleton, puoi passare applicationContext ().

Opzione 2: se devi davvero usare il contesto dell'attività, quando l'attività viene distrutta, assicurati che il contesto passato alla classe singleton sia impostato su null.

Spero che aiuti..∆∆∆∆


0

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

RisorseHelper:

public class ResourcesHelper {
    public static Resources resources;
}

quindi usalo ovunque

String s = ResourcesHelper.resources.getString(R.string.app_name);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.