Android'de bağlamdan etkinlik alma


184

Bu beni zor durumda bıraktı.

Özel düzen sınıf içinde bir etkinlik yöntemi çağırmak gerekir. Buradaki sorun, etkinliğin düzen içinden nasıl erişileceğini bilmemem.

Profil görünümü

public class ProfileView extends LinearLayout
{
    TextView profileTitleTextView;
    ImageView profileScreenImageButton;
    boolean isEmpty;
    ProfileData data;
    String name;

    public ProfileView(Context context, AttributeSet attrs, String name, final ProfileData profileData)
    {
        super(context, attrs);
        ......
        ......
    }

    //Heres where things get complicated
    public void onClick(View v)
    {
        //Need to get the parent activity and call its method.
        ProfileActivity x = (ProfileActivity) context;
        x.activityMethod();
    }
}

ProfileActivity

public class ProfileActivityActivity extends Activity
{
    //In here I am creating multiple ProfileViews and adding them to the activity dynamically.

    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.profile_activity_main);
    }

    public void addProfilesToThisView()
    {
        ProfileData tempPd = new tempPd(.....)
        Context actvitiyContext = this.getApplicationContext();
        //Profile view needs context, null, name and a profileData
        ProfileView pv = new ProfileView(actvitiyContext, null, temp, tempPd);
        profileLayout.addView(pv);
    }
}

Yukarıda gördüğünüz gibi, ben profileView programlı örnekleme ve onunla activityContext geçiriyorum. 2 soru:

  1. Profil görünümüne doğru bağlamı mı aktarıyorum?
  2. Kapsayıcı etkinliği bağlamdan nasıl alabilirim?

Yanıtlar:


473

Sizden Activity, düzeniniz için thisolduğu gibi Contextiletin:

ProfileView pv = new ProfileView(this, null, temp, tempPd);

Daha sonra Contextmizanpajda bir tane olacak , ancak bunun aslında sizin olduğunu bileceksiniz Activityve ihtiyacınız olan şeye sahip olacak şekilde yayınlayabilirsiniz :

Activity activity = (Activity) context;

53
Üzerinde çalıştığınız içeriğin bir Etkinlik Bağlamı veya bir Uygulama Bağlamı olduğu garanti edilemez. Bir Uygulama Bağlamını bir DialogView öğesine aktarmayı deneyin, çökmesini izleyin ve farkı göreceksiniz.
Sky Kelsey

6
Boris, soru bir Bağlamdan Etkinlik almanın bir yolu olup olmadığını soruyor. Bu mümkün değil. Tabii ki döküm yapabilirsiniz, ama bu son çare. Bağlamı bir Etkinlik olarak değerlendirmek istiyorsanız, bir Etkinliğe indirmeyin. Daha basit bir kod sağlar ve başka bir kişi kodunuzu koruduğunda daha sonra hatalara daha az eğilimlidir.
Sky Kelsey

6
'This' yerine 'getApplicationContext ()' işlevinin çalışmadığını unutmayın.
dwbrito

1
@BorisStrandjev Yorumunuzu tam olarak anlamadım. Her neyse, örneğinizi denedikten sonra söyledim ama 'this' yerine getApplicationContext () kullandım ve uygulama, Uygulama yerine, bu nedenle etkinlik yerine bir döküm hatası vererek çalıştı. 'Buna' geçtikten sonra, cevapladığınız gibi çalıştı.
dwbrito

1
Bağlantınızdaki en yüksek oylanan cevaplar, hem koklamak için soruyu zorlamayı önerir. Bu soru kesinlikle kötü kokulu. OP ilk önce şunları söyledi: "Özel düzen sınıfından bir etkinlik yöntemi çağırmam gerekiyor." arayüzlerin uygun kullanımı ile tamamen elde edilebilir. Sonra "Buradaki sorun, etkinliğin düzen içinden nasıl erişileceğini bilmemem." Diyor. ki bu bir yanlış anlama yolunda önemli bir ipucu. İnsanlar programlamada her zaman yanlış bir şey yapmaya çalışırlar ve buna kör bir gözle bakmamalıyız.
Sam

39

Bu, UI içinde parçalar veya özel görünümlerde çalışırken dönüştürmek Contextiçin başarıyla kullandığım bir şey Activity. ContextWrapper'ı özyinelemeyle açar veya başarısız olursa null değerini döndürür.

public Activity getActivity(Context context)
{
    if (context == null)
    {
        return null;
    }
    else if (context instanceof ContextWrapper)
    {
        if (context instanceof Activity)
        {
            return (Activity) context;
        }
        else
        {
            return getActivity(((ContextWrapper) context).getBaseContext());
        }
    }

    return null;
}

Bu doğru cevap. Diğerleri ContentWrapper hiyerarşisini dikkate almaz.
Snicolas

Bu gerçek cevap :)
lygstate

1
@lygstate: Uygulamanızda hangi hedef API düzeyini kullanıyorsunuz? Hata nedir? Bu, Hizmetler'de değil, yalnızca kullanıcı arayüzünde (etkinlikler, parçalar vb.) Çalışır.
Theo

31
  1. Hayır
  2. Yapamazsın

Android'de iki farklı bağlam var. Biri uygulamanız için (BÜYÜK olanı diyelim) ve her görünüm için bir tane (buna aktivite bağlamı diyelim).

LinearLayout bir görünümdür, bu nedenle etkinlik bağlamını çağırmanız gerekir. Bir aktiviteden çağırmak için "this" demeniz yeterlidir. Çok kolay değil mi?

Kullandığınızda

this.getApplicationContext();

Uygulamanızı tanımlayan ve görünümünüzü yönetemeyen BIG bağlamını çağırırsınız.

Android ile ilgili büyük bir sorun, bir içeriğin etkinliğinizi çağıramamasıdır. Birisi Android geliştirmesiyle başladığında bundan kaçınmak büyük bir şey. Sınıfınızı kodlamanın daha iyi bir yolunu bulmalısınız (veya "Etkinlik bağlamı" ile "Bağlam bağlamını" değiştirmeli ve gerektiğinde "Bağlam" a atamalısınız).

Saygılarımızla.


Sadece cevabımı güncellemek için. Size ulaşmanın en kolay yolu, içinde Activity contextbir staticörnek tanımlamaktır Activity. Örneğin

public class DummyActivity extends Activity
{
    public static DummyActivity instance = null;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // Do some operations here
    }

    @Override
    public void onResume()
    {
        super.onResume();
        instance = this;
    }

    @Override
    public void onPause()
    {
        super.onPause();
        instance = null;
    }
}

Ve sonra, Gözlerinde farklı Task, Dialog, View, sen senin olsun kodu bu tür kullanabilirsiniz Activity context:

if (DummyActivity.instance != null)
{
    // Do your operations with DummyActivity.instance
}

4
+1, 2 farklı bağlam türü arasında çok yaygın bir karışıklık alanını açıklamak için (tıpkı 2 farklı Rs olduğu gibi ). Google milletlerinin kelime dağarcığını zenginleştirmesi gerekiyor.
an00b

3
BTW, @BorisStrandjev doğrudur: 2. Evet yapabilirsiniz . (çalışma koduyla tartışılamaz)
an00b

2
2. Pek değil. Bağlam Uygulama bağlamıysa uygulamanız çökecektir.
StackOverflowed

statik örnek ?! @Nepster bu imo için en iyi çözüme sahiptir
Sam

14
Etkinliğe statik bir başvuru oluşturmak, bellek sızıntıları oluşturmanın en iyi yoludur.
BladeCoder

8

Özel düzen sınıfından (Etkinlik Sınıfı olmayan) bir etkinlik yöntemini çağırmak istiyorsanız, arabirimi kullanarak bir temsilci oluşturmanız gerekir.

Denenmemiş ve doğru kodladım. ama istediğini başarmanın bir yolunu sunuyorum.

Her şeyden önce oluşturma ve arayüz

interface TaskCompleteListener<T> {
   public void onProfileClicked(T result);
}



public class ProfileView extends LinearLayout
{
    private TaskCompleteListener<String> callback;
    TextView profileTitleTextView;
    ImageView profileScreenImageButton;
    boolean isEmpty;
    ProfileData data;
    String name;

    public ProfileView(Context context, AttributeSet attrs, String name, final ProfileData profileData)
    {
        super(context, attrs);
        ......
        ......
    }
    public setCallBack( TaskCompleteListener<String> cb) 
    {
      this.callback = cb;
    }
    //Heres where things get complicated
    public void onClick(View v)
    {
        callback.onProfileClicked("Pass your result or any type");
    }
}

Ve bunu herhangi bir Faaliyete uygulayın.

ve şöyle deyin

ProfileView pv = new ProfileView(actvitiyContext, null, temp, tempPd);
pv.setCallBack(new TaskCompleteListener
               {
                   public void onProfileClicked(String resultStringFromProfileView){}
               });

1
Bu doğru cevaptır ve doğru cevap olarak işaretlenmelidir. Doğru olarak işaretlenen cevabı aslında OP'nin sorusunu cevaplıyor biliyorum, ama soruyu bu şekilde cevaplamamalı. Gerçek şu ki, Faaliyetin bir görünüm içinde bu şekilde aktarılması iyi bir uygulama değildir. Çocuk, hiçbir şey dışında, ebeveynleri hakkında hiçbir zaman bilmemelidir Context. Nepster'in belirttiği gibi, en iyi uygulama bir geri aramayı iletmektir, bu nedenle ebeveynin ilgisini çeken bir şey olduğunda, geri arama ilgili verilerle tetiklenir.
Darwind

6

Bağlam bir Uygulama, Hizmet, Etkinlik ve daha fazlası olabilir.

Normalde bir Aktivitedeki Görünümlerin içeriği Aktivitenin kendisidir, bu nedenle bu Bağlamı Aktiviteye yayınlayabileceğinizi düşünebilirsiniz, ancak aslında her zaman yapamazsınız, çünkü bağlam da bu durumda bir ContextThemeWrapper olabilir.

ContextThemeWrapper, AppCompat ve Android'in son sürümlerinde yoğun bir şekilde kullanılmaktadır (düzenlerde android: theme niteliği sayesinde), bu yüzden şahsen bu oyuncuları asla yapmam.

Bu yüzden kısa cevap: bir Görünümdeki Bağlamdan bir Etkinliği güvenilir bir şekilde alamazsınız. Etkinliği parametre olarak alan bir yöntemi çağırarak Etkinliği görünüme geçirin.


3

Hiçbir zaman getApplicationContext () öğesini görünümlerle kullanmayın.

Görünüm faaliyete bağlı olduğundan, her zaman etkinliğin bağlamı olmalıdır. Ayrıca, özel bir tema setiniz olabilir ve uygulamanın bağlamını kullanırken tüm temalar kaybolur. Farklı bağlam sürümleri hakkında daha fazla bilgiyi buradan edinebilirsiniz .


3

Ve Kotlin'de:

tailrec fun Context.activity(): Activity? = when {
  this is Activity -> this
  else -> (this as? ContextWrapper)?.baseContext?.activity()
}

0

Bir Aktivite, böylece Bağlamında bir uzmanlık olduğunu zaten kullanmayı düşündüğünüz ve basitçe döküm hangi etkinlik bildiğiniz bir Bağlam varsa bir içine c ; burada a bir Etkinliktir ve c bir Bağlamdır.

Activity a = (Activity) c;

7
Bu tehlikelidir, çünkü ayrı bir yorumda belirtildiği gibi, bağlam her zaman bir Faaliyet olmayabilir.

4
typecast only (etkinliğin bağlam örneği) {// typecast}
Amit Yadav

0

Etkinliği dönüştürmek için kullandım

Activity activity = (Activity) context;

2
Farklı türde bağlamlar vardır. Etkinlikler ve Uygulamaların bağlamları olabilir. Bu yalnızca bağlam bir etkinliğe sahip olduğunda çalışır.
cylov

0

Bu yöntem yardımcı olmalıdır ..!

public Activity getActivityByContext(Context context){

if(context == null){
    return null;
    }

else if((context instanceof ContextWrapper) && (context instanceof Activity)){
        return (Activity) context;
    }

else if(context instanceof ContextWrapper){
        return getActivity(((ContextWrapper) context).getBaseContext());
    }

return null;

    }

Umarım bu yardımcı olur .. Mutlu kodlama!


İletdiğiniz içeriğin boş olup olmadığını kontrol edin. Sorun büyük olasılıkla budur.
Taslim Oseni

0

canlı veri geri aramasına ne dersiniz,

class ProfileView{
    private val _profileViewClicked = MutableLiveData<ProfileView>()
    val profileViewClicked: LiveData<ProfileView> = _profileViewClicked
}

class ProfileActivity{

  override fun onCreateView(...){

    profileViewClicked.observe(viewLifecycleOwner, Observer { 
       activityMethod()
    })
  }

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