Usando getResources () na classe sem atividade


123

Estou tentando usar o método getResources em uma classe sem atividade. Como obtenho a referência ao objeto "resources" para que eu possa acessar o arquivo xml armazenado na pasta resources?

Exemplo:

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

Normalmente, não é uma boa ideia passar Contextobjetos no Android. Isso pode levar a vazamentos de memória. Veja minha resposta para uma solução menos arriscada.
Jason Crosby

Respostas:


147

Você terá que passar um contextobjeto para ele. Ou thisse você tiver uma referência para a classe em um activty, ougetApplicationContext()

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

Então você pode usá-lo no construtor (ou configurá-lo como uma variável de instância):

public class RegularClass(){
    private Context context;

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

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

Onde o construtor aceita Contextcomo parâmetro


7
Normalmente, não é uma boa ideia passar Contextobjetos no Android. Isso pode levar a vazamentos de memória.
Jason Crosby

28
Como regra básica, com certeza, mas acho que isso é um pouco enganador. Contextos objetos são desagradáveis ​​porque não é imediatamente óbvio se é para todo o aplicativo ou para toda a atividade. Vazamentos de memória (e falhas) ocorrem quando você fornece o incorreto. Por exemplo, fornecer um Activityobjeto estático que precise de um Contextobjeto e não seja destruído quando o Activityis leva à Activitypersistência após onDestroy, já que não pode ser GCed devido a esse outro objeto estático. Então, sim, pode ser perigoso, mas sabendo por que é perigoso, sinto que é importante mencionar aqui.
Dororo

2
^ Dororo, este é um dos comentários mais importantes que já li. O uso adequado do contexto raramente é discutido. Sinto que tive um bug inexplicável por causa disso!
Jonathan Dunn

@Dororo Então você tem alguma sugestão de prática? Devemos tentar evitar passar variáveis ​​de contexto? Então, o que podemos fazer quando precisamos de uma API da classe de atividade?
Alston

35

Não é uma boa ideia passar Contextobjetos. Isso geralmente leva a vazamentos de memória. Minha sugestão é que você não faça isso. Criei vários aplicativos Android sem precisar passar o contexto para classes de não atividade no aplicativo. Uma idéia melhor seria obter os recursos aos quais você precisa acessar enquanto estiver no Activityou Fragment, e segurá-lo em outra classe. Você pode usar essa classe em qualquer outra classe em seu aplicativo para acessar os recursos, sem precisar passar Contextobjetos.


Este é um bom conselho, obrigado. Seria um problema em um SQLiteOpenHelper? No construtor, você precisa passar um contexto. Ele não está mais disponível nos outros métodos, mas eu poderia armazená-lo em um campo privado.
Peter

2
@ Peter Sim, existem algumas classes que exigem que você passe em um objeto de contexto. Portanto, é melhor tentar usar apenas classes como SqLiteOpenHelper em uma atividade ou fragmento para que você não precise repassar o objeto de contexto. Se for inevitável, certifique-se de definir sua referência ao objeto de contexto como nulo quando terminar, para ajudar a reduzir o risco de vazamento de memória.
Jason Crosby

1
A passagem do objeto de contexto nem sempre é ruim, desde que você possa monitorar o ciclo de vida da atividade. Caso contrário, use melhor o contexto do aplicativo em vez do contexto da atividade usando getApplicationContext () para evitar vazamentos de memória. Consulte stackoverflow.com/questions/7144177/… para recuperar o contexto do aplicativo.
FrozenFire 11/01

14

Há mais uma maneira de criar um objeto também. Verifique a referência . Obrigado por @cristian. Abaixo, adiciono as etapas mencionadas na referência acima. Para mim, não gosto de criar um objeto para isso e acessar. Então, eu tentei acessar o getResources()sem criar um objeto. Encontrei este post. Então, pensei em adicioná-lo como resposta.

Siga as etapas para acessar getResources()em uma classe sem atividade without passing a contextpor meio do objeto

  • Crie uma subclasse de Application, por exemplo public class App extends Application {. Consulte o código ao lado das etapas.
  • Defina o android:nameatributo da sua <application>tag no AndroidManifest.xmlpara apontar para sua nova classe, por exemploandroid:name=".App"
  • No onCreate()método da instância do aplicativo, salve o contexto (por exemplo this) em um campo estático chamado appe crie um método estático que retorne esse campo, por exemplo getContext().
  • Agora você pode usar: App.getContext()sempre que quiser obter um contexto e, em seguida, podemos usar App.getContext().getResources()para obter valores dos recursos.

É assim que deve parecer:

public class App extends Application{

    private static Context mContext;

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

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

5

aqui está a minha resposta:

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 a chamada pode ser assim:

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

3

isso pode ser feito usando

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

Bem, isso fez a mágica para mim. Obrigado @ARAsha #
Kenny Dabiri

passando Contextobjetos não é uma prática saudável
Vemuri Pavan

3

Podemos usar o contexto Como este, tente agora Onde o pai é o ViewGroup.

Context context = parent.getContext();

1

bem, não há necessidade de passar o contexto e fazer tudo isso ... simplesmente faça isso

Context context = parent.getContext();

Editar: onde pai é o ViewGroup


3
Espero que você tenha sido votado por supor que existe uma variável de membro conveniente 'ViewGroup parent'. Suposição bastante estúpida.
Arnt

1

Isso sempre funciona para mim:

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

}

Não relacionado a esta pergunta, mas por exemplo, usando um fragmento para acessar recursos / atividades do sistema como este:

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

No aplicativo de guia turístico do curso Básico ANdroid da Udacity, usei o conceito de Fragmentos. Fiquei preso por um tempo com dificuldade para acessar alguns recursos de string descritos em strings, arquivo xml. Finalmente consegui uma solução.

Esta é a principal classe de atividade

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

Esta é a classe non Activity que 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

Na classe simples, declare o contexto e obtenha dados do arquivo da pasta 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

        }
}

Na classe de atividade, declare assim

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

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

}

0

Estou atrasado, mas solução completa ;: Exemplo de Classe, Usar Contexto como este: -

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

Aviso (vazamentos de memória)

Como resolver isso?

Opção 1 : em vez de passar o contexto da atividade, isto é, para a classe singleton, você pode passar applicationContext ().

Opção 2: se você realmente precisar usar o contexto de atividade, quando a atividade for destruída, verifique se o contexto que você passou para a classe singleton está definido como nulo.

Espero que ajude ...


0

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

RecursosHelper:

public class ResourcesHelper {
    public static Resources resources;
}

então use-o em qualquer lugar

String s = ResourcesHelper.resources.getString(R.string.app_name);
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.