Etkinlik dışı sınıfta getResources () kullanma


123

Aktivite dışı bir sınıfta getResources yöntemini kullanmaya çalışıyorum. Kaynaklar klasörü altında depolanan xml dosyasına erişebilmek için "kaynaklar" nesnesine başvuruyu nasıl edinebilirim?

Misal:

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

Normalde ContextAndroid'de nesnelerin etrafından dolaşmak iyi bir fikir değildir . Bellek sızıntılarına neden olabilir. Daha az riskli bir çözüm için cevabıma bakın.
Jason Crosby

Yanıtlar:


147

Ona bir contextnesne vermeniz gerekecek . Ya thisbir aktivitede sınıfa bir referansınız varsa ya dagetApplicationContext()

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

Ardından bunu yapıcıda kullanabilir (veya bir örnek değişkenine ayarlayabilirsiniz):

public class RegularClass(){
    private Context context;

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

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

Yapıcının Contextparametre olarak kabul ettiği yer


7
Normalde ContextAndroid'de nesnelerin etrafından dolaşmak iyi bir fikir değildir . Bellek sızıntılarına neden olabilir.
Jason Crosby

28
Temel bir kural olarak elbette, ama bunun biraz yanıltıcı olduğunu düşünüyorum. Contextnesneler kötüdür çünkü uygulama çapında mı yoksa etkinlik çapında mı olduğu hemen belli değildir. Yanlış olanı sağladığınızda bellek sızıntıları (ve çökmeleri) meydana gelir. Örneğin, Activitybir statik nesneye Contextve bahsedilen nesneye ihtiyaç duyan bir nesnenin sağlanması, onDestroy'dan sonra kalıcı olmaya Activityyol Activityaçtığında, bu diğer statik nesne nedeniyle GC işlemi yapılamayacağından, yok edilmez. Yani evet, tehlikeli olabilir, ancak neden tehlikeli olduğunu bilmek burada bahsetmek önemli.
Dororo

2
^ Dororo, Bu şimdiye kadar okuduğum en önemli yorumlardan biri. Bağlamın doğru kullanımı nadiren tartışılır. Bu yüzden açıklanamaz bir çok hata yaşadığımı hissediyorum!
Jonathan Dunn

@Dororo Peki herhangi bir uygulama öneriniz var mı? Bağlam değişkenlerini iletmekten kaçınmalı mıyız? O halde aktivite sınıfından api'ye ihtiyacımız olduğunda ne yapabiliriz?
Alston

35

ContextNesneleri dolaşmak iyi bir fikir değil . Bu genellikle bellek sızıntılarına neden olur. Benim önerim, bunu yapmamanız. Uygulamadaki etkinlik dışı sınıflara bağlam aktarmak zorunda kalmadan çok sayıda Android uygulaması yaptım. Daha iyi bir fikir, Activityya da içindeyken erişmeniz gereken kaynakları elde Fragmentetmek ve başka bir sınıfta tutmaktır. Daha sonra, Contextnesnelerin etrafından dolaşmak zorunda kalmadan kaynaklara erişmek için bu sınıfı uygulamanızdaki diğer sınıflarda kullanabilirsiniz .


Bu iyi bir tavsiye, teşekkürler. SQLiteOpenHelper'da sorun olur mu? Yapıcıda, bir bağlam aktarmanız gerekir. Artık diğer yöntemlerde mevcut değil ama özel bir alanda saklayabilirim.
Peter

2
@Peter Evet, bir bağlam nesnesi içinde geçmenizi gerektiren bazı sınıflar vardır. Bu nedenle, bağlam nesnesini iletmek zorunda kalmamak için bir etkinlik veya parçada yalnızca SqLiteOpenHelper gibi sınıfları kullanmaya çalışmak en iyisidir. Kaçınılmazsa, bellek sızıntısı riskini azaltmaya yardımcı olmak için tamamladığınızda bağlam nesnesine başvurunuzu null olarak ayarladığınızdan emin olun.
Jason Crosby

1
Etkinliğin yaşam döngüsünü izleyebildiğiniz sürece bağlam nesnesini geçirmek her zaman kötü değildir. Değilse, bellek sızıntılarını önlemek için getApplicationContext () kullanarak Etkinlik bağlamı yerine Uygulama bağlamını kullanın. Uygulama bağlamını almak için stackoverflow.com/questions/7144177/… adresine bakın .
FrozenFire

14

Bir nesne oluşturmadan da bir yol daha var. Referansı kontrol edin . @Cristian için teşekkürler. Aşağıda yukarıdaki referansta bahsedilen adımları ekliyorum. Benim için bunun için bir nesne oluşturmayı ve erişimi sevmiyorum. Böylece getResources()bir nesne oluşturmadan erişmeye çalıştım . Bu gönderiyi buldum. Bu yüzden cevap olarak eklemeyi düşündüm.

Nesne aracılığıyla getResources()etkinlik dışı bir sınıfa erişmek için adımları izleyin without passing a context.

  • ApplicationÖrneğin bir alt sınıf oluşturun public class App extends Application {. Adımların yanındaki koda bakın.
  • Yeni sınıfınızı gösterecek şekilde etiketinizin android:nameözniteliğini ayarlayın , örn.<application>AndroidManifest.xmlandroid:name=".App"
  • In onCreate()your bağlamda (örn tasarrufu uygulama örneğinin yöntemi thisadında bir statik alana) appve statik yöntem oluşturmak olduğunu döndürür bu alan, örneğin getContext().
  • Artık şunları kullanabilirsiniz: App.getContext()bir bağlam elde etmek istediğinizde ve sonra App.getContext().getResources()kaynaklardan değerler elde etmek için kullanabiliriz.

Nasıl görünmesi gerektiği:

public class App extends Application{

    private static Context mContext;

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

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

5

İşte cevabım:

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

}

ve çağrı şu şekilde olabilir:

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

3

bu, kullanılarak yapılabilir

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

Bu benim için Sihri yaptı. Teşekkürler @ARAsha
Kenny Dabiri

Contextnesneleri geçmek sağlıklı bir uygulama değil
Vemuri Pavan

3

Bağlamı kullanabiliriz Bunun gibi şimdi deneyin Ebeveynin ViewGroup olduğu yerde.

Context context = parent.getContext();

1

bağlamı aktarmaya ve tüm bunları yapmaya gerek yok ... basitçe şunu yapın

Context context = parent.getContext();

Düzenleme: üst, ViewGroup'tur


3
Kullanışlı bir 'ViewGroup ana' üye değişkeni olduğunu varsaydığınız için olumsuz oy verildiğini umuyorum. Oldukça aptalca bir varsayım.
2013

1

Bu her zaman benim için çalışıyor:

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

}

Bu soruyla ilgili değil, ancak aşağıdaki gibi sistem kaynaklarına / etkinliğine erişmek için bir Parça kullanma örneği:

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

Udacity'nin Temel ANdroid kursunun tur rehberi uygulamasında Fragments kavramını kullandım. Bir süredir dizelerde, xml dosyasında açıklanan bazı dize kaynaklarına erişmekte zorluk yaşadım. Sonunda bir çözüm buldum.

Bu ana aktivite sınıfıdır

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

Bu, FragmentPageAdapter'ı genişleten Activity olmayan sınıftır.

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

Basit sınıfta bağlamı bildirir ve res klasöründen dosyadan veri alır

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

        }
}

Aktivite sınıfında böyle beyan et

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

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

}

0

Geç kaldım ama tam çözüm ;: Örnek Sınıf, Bağlamı şu şekilde kullanın: -

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

Uyarı (Bellek Sızıntıları)

Bunu nasıl çözebilirim?

Seçenek 1 : Etkinlik bağlamını, yani bunu tekil sınıfına geçirmek yerine, applicationContext () öğesini iletebilirsiniz.

Seçenek 2: Etkinlik bağlamını gerçekten kullanmanız gerekiyorsa, etkinlik yok edildiğinde, singleton sınıfına ilettiğiniz bağlamın null olarak ayarlandığından emin olun.

Umarım yardımcı olur ...


0

MainActivity'de:

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

ResourcesHelper:

public class ResourcesHelper {
    public static Resources resources;
}

o zaman her yerde kullan

String s = ResourcesHelper.resources.getString(R.string.app_name);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.