Adaptörden Etkinlik yöntemini çağırın


119

O tanımlanan yöntemi çağırmak mümkün mü Activitydan ListAdapter?

(Ben yapmak istiyorum Buttoniçinde list'ssatır ve bu düğmeye tıklandığında, bu Aktivite tekabül tanımlanan yöntem, gerçekleştirmelisiniz. Sette çalıştı onClickListenerbenim, ListAdapterama onun yol ne bu yöntemi, çağırmak nasıl bilmiyorum. ..)

kullandığımda Activity.this.method()aşağıdaki hatayı alıyorum:

No enclosing instance of the type Activity is accessible in scope

Herhangi bir fikir ?


o aktivitenin iç sınıfı olmadığı sürece başka bir sınıfta bu aktiviteyi çağıramazsınız. takip edin @Eldhose M Babu sizin durumunuz için çözüm
Archie.bpgc

Yanıtlar:


306

Evet yapabilirsin.

Adaptörde Yeni Alan Ekle:

private Context mContext;

Bağdaştırıcı Oluşturucu'da aşağıdaki kodu ekleyin:

public AdapterName(......, Context context) {
  //your code.
  this.mContext = context;
}

Bağdaştırıcının getView [...) kısmında:

Button btn = (Button) convertView.findViewById(yourButtonId);
btn.setOnClickListener(new Button.OnClickListener() {
  @Override
  public void onClick(View v) {
    if (mContext instanceof YourActivityName) {
      ((YourActivityName)mContext).yourDesiredMethod();
    }
  }
});

kodunuzu, aktivitenizi vb. gördüğünüz kendi sınıf isimlerinizle değiştirin.

Aynı adaptörü birden fazla aktivite için kullanmanız gerekiyorsa, o zaman:

Bir Arayüz Oluşturun

public interface IMethodCaller {
    void yourDesiredMethod();
}

Bu arabirimi, bu yöntem çağırma işlevine sahip olmak için ihtiyaç duyduğunuz etkinliklere uygulayın.

Ardından Adaptör getView () 'da şu şekilde çağrı yapın:

Button btn = (Button) convertView.findViewById(yourButtonId);
btn.setOnClickListener(new Button.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (mContext instanceof IMethodCaller) {
            ((IMethodCaller) mContext).yourDesiredMethod();
        }
    }
});

Bitirdiniz. Bu bağdaştırıcıyı, bu çağrı mekanizmasını gerektirmeyen etkinlikler için kullanmanız gerekirse, kod çalışmayacaktır (kontrol başarısız olursa).


29
Bu popüler bir soru olduğu için, bu çözümü KULLANMAMAYI şiddetle tavsiye ediyorum. Burada sınıf çevriminden kaçınmalısınız, çünkü bu çalışma zamanı istisnalarına yol açabilir.
Igor Filippov

3
Eldhose kardeşim, sana karşı hiçbir şeyim yok ama aşağıdaki cevap en iyi uygulama. Yorumlarda bile okuyabilirsiniz. Kodun yeniden kullanımından kaçındığınız için mContext'i Aktivitenize atmamalısınız. Artık bu bağdaştırıcı yalnızca mContext değişkeninizi attığınız Etkinlik içinde kullanılabilir; burada tanımlanmış bir dinleyiciniz varsa, aynı Bağdaştırıcıyı başka bir Etkinlik'te yeniden kullanabilirsiniz. İnan bana, endüstride yeterince zaman geçirdim ve sadece burada size yardım etmeye çalışıyorum, lütfen bunu kişisel algılamayın.
Varundroid

2
Bu çözüm, SO'da bulduğum en iyi çözümlerden biri. Bu yüzden çok teşekkürler Bay Babu. Aktivitenin yöntemlerini bu şekilde çağırmak, tüm uygulamaya% 500 tekme performans artışı sağlar -> Veritabanını, erişmem gereken bağdaştırıcıya yeniden yüklememe gerek yok. "Endüstride geçen yıllar" umurumda değil, istikrarlı ve çalışan çözümler arıyorum ve eminim ki erişim sağlamak için daha iyi bir yol bulamayacağım. Belki DB'yi bir singleton olarak kurabilirim, ancak bu benim projemin "yapısını çözmek" istediğim yol değil.
Martin Pfeffer

2
@RAM Aynı metodu birden fazla aktivitede çağırmanız gerekiyorsa, bu metot adıyla bir arayüz oluşturmanız gerekir. Ardından, yöntem çağrısının yararlanılması için ihtiyacınız olan tüm etkinliklerde bu arayüzü uygulayın. Ardından tıklama dinleyicide, etkinlik adını kullanmak yerine arayüzünüzün örneğini kontrol edin.
Eldhose M Babu

1
Harika cevap. Başparmak yukarı
Alok Rajasukumaran

126

Bunu şu şekilde yapabilirsiniz:

Arayüzü bildirin:

public interface MyInterface{
    public void foo();
}

Etkinliğinizin bunu uygulamasına izin verin:

public class MyActivity extends Activity implements MyInterface{
    public void foo(){
        //do stuff
    }
}

Ardından etkinliğinizi ListAdater'a aktarın:

public MyAdapter extends BaseAdater{
    private MyInterface listener;

    public MyAdapter(MyInterface listener){
        this.listener = listener;
    }
}

Ve bu Aktivite yöntemini çağırmanız gerektiğinde adaptörün herhangi bir yerinde:

listener.foo();

5
Önce yukarıdaki yöntemi parçalarla yapacağınız gibi düşündüm ama bu en iyi çözüm!
brux

1
Arabirim Listem hangisi? nasıl başlatabilirim? public MyAdapter (MyInterface dinleyicisi) {this.listener = dinleyici; }
Gilberto Ibarra

6
Nasıl (Activity) gerçi adaptöre arayüzü geçmek yok
Brandon

1
@Brandon bağdaştırıcıda yapıcı parametresine geçebilirsiniz.
Igor Filippov

5
@Brandon, arabirimi adaptöre geçirmek için 'this' ekleyin myAdapter = new MyAdapter (this);
ajinkya

67

Orijinal:

Mevcut cevabı anlıyorum ama daha net bir örneğe ihtiyacım vardı. İşte bir Adapter(RecyclerView.Adapter) ve Activity.

Etkinliğinizde:

Bu, interfacesahip olduğumuz şeyi uygulayacaktır Adapter. Bu örnekte, kullanıcı içindeki bir öğeyi tıkladığında çağrılacaktır RecyclerView.

public class MyActivity extends Activity implements AdapterCallback {

    private MyAdapter myAdapter;

    @Override
    public void onMethodCallback() {
       // do something
    }

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

        myAdapter = new MyAdapter(this);
    }
}

Adaptörünüzde:

İçinde Activity, biz başlattık Adapterve bunu kurucuya bir argüman olarak ilettik. Bu, interfacegeri arama yöntemimizi başlatacak . Kullanıcı tıklamaları için geri arama yöntemimizi kullandığımızı görebilirsiniz.

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    private AdapterCallback adapterCallback;

    public MyAdapter(Context context) {
        try {
            adapterCallback = ((AdapterCallback) context);
        } catch (ClassCastException e) {
            throw new ClassCastException("Activity must implement AdapterCallback.", e);
        }
    }

    @Override
    public void onBindViewHolder(MyAdapter.ViewHolder viewHolder, int position) {
        // simple example, call interface here
        // not complete
        viewHolder.itemView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    adapterCallback.onMethodCallback();
                } catch (ClassCastException e) {
                   // do something
                }
            }
        });
    }

    public static interface AdapterCallback {
        void onMethodCallback();
    }
}

6
bunun için teşekkürler, tam olarak aradığım şey buydu.
olumlu

bu benim için çalıştı! imo, şimdiye kadarki en eksiksiz çalışma kodu!
2016

2
Bu çözüm için teşekkürler
Steve

4
bu yanıtın daha fazla olumlu oyu olmalı, temiz ve mükemmel bir çözüm.
Opiatefuchs

Merhaba @Jared - Önerdiğiniz numunenin aynısını düzeltebilir EventBusmisiniz?
Tohid

15

Temel ve basit.

Adaptörünüzde bunu kullanın.

((YourParentClass) context).functionToRun();


4
iyi bir uygulama değil çünkü sınıfınızı herhangi bir sınıf yerine yalnızca YourParentClass türüyle çalışacak şekilde kısıtlıyorsunuz, ancak yeniden kullanmayı umursamıyorsanız işe yarıyor, ayrıca bir sınıfı yeniden adlandırırsanız kod bozulur ...
Gustavo Baiocchi Costa

7

Bir yol daha:

Bağdaştırıcınıza bir yöntem yazın, herkese açık void callBack () {} diyelim.

Şimdi, etkinlikte bağdaştırıcı için bir nesne oluştururken bu yöntemi geçersiz kılın. Bağdaştırıcıda yöntemi çağırdığınızda geçersiz kılma yöntemi çağrılacaktır.

Myadapter adapter = new Myadapter() {
  @Override
  public void callBack() {
    // dosomething
  }
};

5

Kotlin için:

Adaptörünüzde aramanız yeterlidir

(context as Your_Activity_Name).yourMethod()

0
if (parent.getContext() instanceof yourActivity) {
  //execute code
}

Bu koşul, eğer Aktivite sizin yönteminizden GroupViewbu görüşleri talep ediyorsa, bir şeyi yürütmenizi sağlayacaktır getView().adapter DİRyourActivity

NOT: parentGroupView


Bu GroupView, getView()yöntemi çağırdığında adaptörden görünümler ister ..... bu yüzden bu GroupView bağlamını alırız ve yukarıdaki koşul aracılığıyla inceleyeceğiz
Abd Salam Baker,

0

Kotlin'de artık lambda işlevlerini kullanmanın daha temiz bir yolu var, arayüzlere gerek yok:

class MyAdapter(val adapterOnClick: (Any) -> Unit) {
    fun setItem(item: Any) {
        myButton.setOnClickListener { adapterOnClick(item) }
    }
}

class MyActivity {
    override fun onCreate(savedInstanceState: Bundle?) {
        var myAdapter = MyAdapter { item -> doOnClick(item) }
    }


    fun doOnClick(item: Any) {

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