Використання getResources () у класі неактивності


123

Я намагаюся використовувати метод getResources в класі без активності. Як мені отримати посилання на об’єкт "ресурси", щоб я міг отримати доступ до файлу xml, що зберігається в папці ресурсів?

Приклад:

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

Зазвичай не годиться обмінювати Contextоб’єкти в Android. Це може призвести до витоку пам'яті. Дивіться мою відповідь щодо менш ризикованого рішення.
Джейсон Кросбі

Відповіді:


147

Вам доведеться передати йому contextоб’єкт. Або thisякщо у вас є посилання на клас у заході, абоgetApplicationContext()

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

Тоді ви можете використовувати його в конструкторі (або встановити його в змінну примірника):

public class RegularClass(){
    private Context context;

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

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

Де конструктор приймає Contextяк параметр


7
Зазвичай не годиться обмінювати Contextоб’єкти в Android. Це може призвести до витоку пам'яті.
Джейсон Кросбі

28
Як основне правило, але я вважаю, що це дещо вводить в оману. Contextоб'єкти неприємні, тому що це не відразу очевидно, чи це для програми, чи для діяльності. Витоки пам'яті (і збої) виникають, коли ви постачаєте неправильну. Наприклад, подача Activityстатичного об'єкта, якому потрібен Contextі зазначений об'єкт, не руйнується, коли Activityце призводить до Activityзбереження після onDestroy, оскільки він не може бути GCed завдяки цьому іншому статичному об'єкту. Так, так, це може бути небезпечно, але знаючи, чому це небезпечно, я відчуваю, тут важливо згадати.
Дороро

2
^ Дороро, Це один з найважливіших коментарів, які я коли-небудь читав. Правильне використання контексту рідко, якщо взагалі, обговорюється. Я відчуваю, що в мене було багато незрозумілих помилок через це!
Джонатан Данн

@Dororo Отже, у вас є якісь пропозиції щодо практики? Чи варто намагатися уникати передачі контекстних змінних? Тоді що ми можемо зробити, коли нам потрібні певні програми з класу активності?
Альстон

35

Це не дуже гарна ідея передавати Contextоб'єкти навколо. Це часто призводить до витоку пам'яті. Моя пропозиція, щоб ви цього не робили. Я зробив численні програми для Android, не переходячи контекст на заняття без активності в додатку. Кращою ідеєю було б отримати ресурси, до яких потрібно мати доступ, перебуваючи в Activityабо Fragment, і утримати його в іншому класі. Потім ви можете використовувати цей клас у будь-яких інших класах у вашій програмі для доступу до ресурсів, не обходячи Contextоб'єкти.


Це гарна порада дякую. Чи буде це проблема в SQLiteOpenHelper? У конструкторі ви повинні пройти контекст. Він більше не доступний для інших методів, але я можу зберігати його в приватному полі.
Пітер

2
@Peter Так, є декілька класів, які вимагають перейти в контекстний об'єкт. Тож найкраще спробувати використовувати лише такі класи, як SqLiteOpenHelper, у діяльності чи фрагменті, щоб вам не довелося обходити контекстний об’єкт. Якщо це неминуче, просто переконайтеся, що ви встановили посилання на контекстний об'єкт на нуль, коли це зроблено для зменшення ризику витоку пам'яті.
Джейсон Кросбі

1
Передача контекстного об'єкта не завжди погана, якщо ви можете відстежувати життєвий цикл діяльності. Якщо ні, то краще використовувати контекст програми замість контексту діяльності, використовуючи getApplicationContext (), щоб уникнути витоків пам'яті. Див. Stackoverflow.com/questions/7144177/… для отримання контексту програми.
FrozenFire

14

Є ще один спосіб без створення об’єкта. Перевірте посилання . Дякуємо за @cristian Нижче я додаю кроки, які були згадані у наведеній вище посилання. Для мене мені не подобається створювати для цього об’єкт і доступ. Тому я спробував отримати доступ до getResources()об'єкта без створення об'єкта. Я знайшов цю посаду. Тому я думав додати це як відповідь.

Виконайте кроки для доступу getResources()до класу без активності without passing a contextчерез об’єкт.

  • ApplicationНаприклад, створіть підклас public class App extends Application {. Подайте код поруч із кроками.
  • Встановіть android:nameатрибут вашого <application>тегу вAndroidManifest.xml точці, щоб він вказував на ваш новий клас, наприкладandroid:name=".App"
  • У onCreate()методі вашого примірника програми збережіть свій контекст (наприклад this) у статичному полі з назвою appта створіть статичний метод, який повертає це поле, наприкладgetContext() .
  • Тепер ви можете використовувати: App.getContext()коли ви хочете отримати контекст, і тоді ми можемо використовувати App.getContext().getResources()для отримання значень з ресурсів.

Ось як це має виглядати:

public class App extends Application{

    private static Context mContext;

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

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

5

ось моя відповідь:

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

}

і дзвінок може бути таким:

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

3

це можна зробити за допомогою

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

Що ж, це зробило для мене Магію. Дякуємо @ARAsha
Kenny Dabiri

передача Contextпредметів не є здоровою практикою
Вемурі Паван

3

Ми можемо використовувати контекст, як це спробуйте зараз, де батьків є ViewGroup.

Context context = parent.getContext();

1

ну не потрібно передавати контекст і робити все це ... просто зробіть це

Context context = parent.getContext();

Редагувати: де батьків є ViewGroup


3
Я сподіваюся, що вас прихильно вважають, що існує зручна змінна члена "ViewGroup parent". Досить дурне припущення.
arnt

1

Це завжди працює для мене:

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

}

Не пов’язане з цим питанням, але, наприклад, використання фрагмента для доступу до системних ресурсів / діяльності на зразок цієї:

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

У програмі екскурсовода курсу курсу ANDroid Udacity я використав концепцію Fragments. Я на деякий час застряг, маючи труднощі з доступом до деяких рядкових ресурсів, описаних у рядках, XML-файлі. Нарешті отримав рішення.

Це основний клас діяльності

пакет 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 
}
}

Це клас активності, який розширює 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

У простому класі оголосити контекст і отримати дані з файлу з папки 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

        }
}

У класі активності заявляють так

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

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

}

0

Я запізнився, але повне рішення ;: Приклад класу, використовуйте такий контекст: -

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

Попередження (витоки пам'яті)

Як це вирішити?

Варіант 1 : Замість передачі контексту діяльності, тобто це до класу синглтон, ви можете передати applicationContext ().

Варіант 2: Якщо вам дійсно потрібно використовувати контекст діяльності, тоді, коли діяльність знищується, переконайтеся, що контекст, який ви перейшли до класу синглтон, встановлений на нуль.

Сподіваюся, це допомагає..∆∆∆∆


0

у вашій 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();
        }
    }
}

РесурсиHelper:

public class ResourcesHelper {
    public static Resources resources;
}

то використовуйте його всюди

String s = ResourcesHelper.resources.getString(R.string.app_name);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.