Użycie metody getResources () w klasie niebędącej aktywnością


123

Próbuję użyć metody getResources w klasie niebędącej aktywnością. Jak uzyskać odwołanie do obiektu „resources”, aby uzyskać dostęp do pliku xml przechowywanego w folderze zasobów?

Przykład:

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

Zwykle nie jest dobrym pomysłem przekazywanie Contextobiektów w systemie Android. Może to prowadzić do wycieków pamięci. Zobacz moją odpowiedź na mniej ryzykowne rozwiązanie.
Jason Crosby

Odpowiedzi:


147

Będziesz musiał przekazać mu contextprzedmiot. Albo thisjeśli masz odniesienie do klasy w zajęciach, albogetApplicationContext()

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

Następnie możesz użyć go w konstruktorze (lub ustawić na zmienną instancji):

public class RegularClass(){
    private Context context;

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

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

Gdzie konstruktor akceptuje Contextjako parametr


7
Zwykle nie jest dobrym pomysłem przekazywanie Contextobiektów w systemie Android. Może to prowadzić do wycieków pamięci.
Jason Crosby

28
Podstawowa zasada jest pewna, ale uważam, że jest to nieco mylące. Contextobiekty są nieprzyjemne, ponieważ nie jest od razu oczywiste, czy obejmują one całą aplikację, czy działanie. Wycieki pamięci (i awarie) występują, gdy podasz niewłaściwy. Na przykład dostarczenie an Activitydo obiektu statycznego, który wymaga obiektu a, Contexta wspomniany obiekt nie jest niszczone, gdy Activityprowadzi do Activityutrwalenia po onDestroy, ponieważ nie można go GCed z powodu tego innego statycznego obiektu. Więc tak, może to być niebezpieczne, ale czuję , że wiedząc, dlaczego jest to niebezpieczne, warto tutaj wspomnieć.
Dororo,

2
^ Dororo, to jeden z najważniejszych komentarzy, jakie kiedykolwiek czytałem. Rzadko, jeśli w ogóle, omawia się właściwe użycie kontekstu. Mam wrażenie, że miałem przez to wiele niewytłumaczalnych błędów!
Jonathan Dunn

@Dororo Czy masz jakieś sugestie dotyczące ćwiczeń? Czy powinniśmy unikać przekazywania zmiennych kontekstowych? Co zatem możemy zrobić, gdy potrzebujemy interfejsu API z klasy aktywności?
Alston,

35

Przekazywanie przedmiotów nie jest dobrym pomysłem Context. To często prowadzi do wycieków pamięci. Moja sugestia jest taka, że ​​tego nie robisz. Zrobiłem wiele aplikacji na Androida bez konieczności przekazywania kontekstu klasom niezwiązanym z aktywnością w aplikacji. Lepszym pomysłem byłoby zdobycie zasobów, do których potrzebujesz dostępu, gdy jesteś w Activitylub Fragment, i trzymanie ich w innej klasie. Następnie możesz użyć tej klasy w innych klasach w aplikacji, aby uzyskać dostęp do zasobów bez konieczności przekazywania Contextobiektów.


To dobra rada, dzięki. Czy byłby to problem w SQLiteOpenHelper? W konstruktorze musisz przekazać kontekst. Nie jest już dostępny w innych metodach, ale mogłem go przechowywać w prywatnym polu.
Peter

2
@Peter Tak, istnieje kilka klas, które wymagają przekazania obiektu kontekstu. Dlatego najlepiej jest próbować używać tylko tych klas, takich jak SqLiteOpenHelper, w działaniu lub fragmencie, aby nie trzeba było przekazywać obiektu kontekstu. Jeśli jest to nieuniknione, po prostu upewnij się, że po zakończeniu ustawiłeś odwołanie do obiektu kontekstu na null, aby zmniejszyć ryzyko wycieków pamięci.
Jason Crosby

1
Przekazywanie obiektu kontekstu nie zawsze jest złe, o ile możesz monitorować cykl życia działania. Jeśli nie, lepiej użyj kontekstu aplikacji zamiast kontekstu działania za pomocą metody getApplicationContext (), aby uniknąć wycieków pamięci. Zobacz stackoverflow.com/questions/7144177/… w celu pobrania kontekstu aplikacji.
FrozenFire

14

Jest jeszcze jeden sposób bez tworzenia obiektu. Sprawdź odniesienie . Dzięki za @cristian. Poniżej dodaję kroki, które wspomniałem w powyższym odnośniku. Ja nie lubię tworzyć obiektu do tego i dostępu. Więc próbowałem uzyskać dostęp do getResources()bez tworzenia obiektu. Znalazłem ten post. Pomyślałem więc o dodaniu tego jako odpowiedzi.

Postępuj zgodnie z instrukcjami, aby uzyskać dostęp getResources()do klasy niebędącej działaniem without passing a contextza pośrednictwem obiektu.

  • Utwórz podklasę Application, na przykład public class App extends Application {. Zapoznaj się z kodem obok kroków.
  • Ustaw android:nameatrybut swojego <application>tagu w, AndroidManifest.xmlaby wskazywał na twoją nową klasę, npandroid:name=".App"
  • W onCreate()metodzie Twojej instancji aplikacji zapisz kontekst (np. this) W statycznym polu o nazwie appi utwórz statyczną metodę, która zwraca to pole, np getContext().
  • Teraz możesz użyć: App.getContext()kiedy chcesz uzyskać kontekst, a następnie możemy użyć App.getContext().getResources()do pobrania wartości z zasobów.

Tak to powinno wyglądać:

public class App extends Application{

    private static Context mContext;

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

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

5

oto moja odpowiedź:

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

}

a wezwanie może wyglądać tak:

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

3

można to zrobić za pomocą

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

Cóż, to zrobiło dla mnie magię. Dzięki @ARAsha
Kenny Dabiri

mijanie Contextprzedmiotów nie jest zdrową praktyką
Vemuri Pavan

3

Możemy użyć kontekstu Tak jak teraz, spróbuj teraz Gdzie rodzicem jest ViewGroup.

Context context = parent.getContext();

1

no cóż, nie ma potrzeby przekazywania kontekstu i robienia tego wszystkiego ... po prostu zrób to

Context context = parent.getContext();

Edycja: gdzie rodzic jest ViewGroup


3
Spodziewam się, że zostałeś odrzucony za założenie, że istnieje wygodna zmienna składowa „ViewGroup parent”. Raczej głupie założenie.
Arnt

1

To zawsze działa dla mnie:

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

}

Nie ma związku z tym pytaniem, ale przykład użycia fragmentu do uzyskania dostępu do zasobów / działań systemowych, takich jak:

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

W aplikacji przewodnika kursu Basic ANdroid Udacity wykorzystałem koncepcję fragmentów. Utknąłem na chwilę, mając trudności z dostępem do niektórych zasobów ciągu opisanych w ciągach znaków, pliku xml. Wreszcie znalazłem rozwiązanie.

To jest główna klasa aktywności

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

To jest klasa non Activity, która rozszerza 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

W prostej klasie zadeklaruj kontekst i pobierz dane z pliku z folderu 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

        }
}

W klasie aktywności zadeklaruj w ten sposób

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

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

}

0

Jestem spóźniony, ale kompletne rozwiązanie;: Przykładowa klasa, użyj kontekstu w następujący sposób: -

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

Ostrzeżenie (wycieki pamięci)

Jak to rozwiązać?

Opcja 1 : Zamiast przekazywać kontekst działania, czyli to do klasy pojedynczej, możesz przekazać applicationContext ().

Opcja 2: Jeśli naprawdę musisz użyć kontekstu działania, po zniszczeniu działania upewnij się, że kontekst przekazany do klasy pojedynczej ma wartość null.

Mam nadzieję, że to pomoże… ∆∆∆∆


0

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

ZasobyHelper:

public class ResourcesHelper {
    public static Resources resources;
}

następnie używaj go wszędzie

String s = ResourcesHelper.resources.getString(R.string.app_name);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.