Использование 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, поскольку он не может быть собран из-за этого другого статического объекта. Так что да, это может быть опасно, но я считаю важным упомянуть , зная, почему это опасно.
Дороро

2
^ Dororo, это один из самых важных комментариев, которые я когда-либо читал. Правильное использование контекста редко обсуждается, если вообще обсуждается. Такое ощущение, что из-за этого у меня было много необъяснимых ошибок!
Джонатан Данн,

@Dororo Так есть ли у вас предложения по практике? Следует ли нам избегать передачи контекстных переменных? Тогда что мы можем сделать, когда нам понадобится некоторый api из класса активности?
Alston

35

Не рекомендуется передавать Contextпредметы вокруг. Это часто приводит к утечкам памяти. Я предлагаю вам не делать этого. Я создал множество приложений для Android без необходимости передавать контекст неактивным классам в приложении. Лучшей идеей было бы получить ресурсы, к которым вам нужен доступ, пока вы находитесь в Activityили Fragment, и удержать их в другом классе. Затем вы можете использовать этот класс в любых других классах вашего приложения для доступа к ресурсам без необходимости передавать Contextобъекты.


Это хороший совет, спасибо. Будет ли проблема в SQLiteOpenHelper? В конструкторе вам нужно передать контекст. Он больше не доступен в других методах, но я мог бы сохранить его в частном поле.
Питер

2
@Peter Да, есть классы, которым требуется передать объект контекста. Поэтому лучше всего попытаться использовать только такие классы, как SqLiteOpenHelper, в действии или фрагменте, чтобы вам не приходилось передавать объект контекста. Если это неизбежно, просто убедитесь, что вы установили для своей ссылки на объект контекста значение null, когда закончите, чтобы снизить риск утечки памяти.
Джейсон Кросби

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
Кенни

передача 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 я использовал концепцию фрагментов. Я застрял на некоторое время, испытывая трудности с доступом к некоторым строковым ресурсам, описанным в strings, 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 
}
}

Это не класс Activity, который расширяет 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: если вам действительно нужно использовать контекст активности, то при уничтожении активности убедитесь, что для контекста, который вы передали в одноэлементный класс, установлено значение null.

Надеюсь, это поможет .. ∆∆∆∆


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

Ресурсы

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.