Panggil metode Aktivitas dari adaptor

119

Apakah mungkin untuk memanggil metode yang ditentukan Activitydari ListAdapter?

(Saya ingin membuat Buttondi list'sbaris dan ketika tombol ini diklik, harus melakukan metode, yang didefinisikan dalam yang sesuai Activity. Saya mencoba untuk set onClickListenerdi saya ListAdaptertapi saya tidak tahu bagaimana memanggil metode ini, apa yang dilaluinya. ..)

ketika saya menggunakan Activity.this.method()saya mendapatkan kesalahan berikut:

No enclosing instance of the type Activity is accessible in scope

Ada ide ?

pengguna1602687
sumber
Anda tidak bisa memanggil activity.this di beberapa kelas lain kecuali itu adalah kelas dalam untuk aktivitas itu. ikuti solusi @Eldhose M Babu untuk kasus Anda
Archie.bpgc

Jawaban:

306

Ya kamu bisa.

Di adaptor Tambahkan Bidang baru:

private Context mContext;

Di adaptor Constructor tambahkan kode berikut:

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

Di getView (...) dari Adapter:

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

ganti dengan nama kelas Anda sendiri di mana Anda melihat kode Anda, aktivitas Anda, dll.

Jika Anda perlu menggunakan adaptor yang sama ini untuk lebih dari satu aktivitas, maka:

Buat Antarmuka

public interface IMethodCaller {
    void yourDesiredMethod();
}

Implementasikan antarmuka ini dalam aktivitas yang Anda perlukan untuk memiliki fungsi pemanggilan metode ini.

Kemudian di Adapter getView (), panggil seperti:

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

Kamu selesai. Jika Anda perlu menggunakan adaptor ini untuk aktivitas yang tidak memerlukan mekanisme panggilan ini, kode tidak akan dijalankan (Jika pemeriksaan gagal).

Eldhose M Babu
sumber
29
Karena ini adalah pertanyaan yang populer, saya sangat menyarankan untuk TIDAK MENGGUNAKAN solusi ini. Anda harus menghindari transmisi kelas di sini, karena ini dapat menyebabkan pengecualian waktu proses.
Igor Filippov
3
Kakak laki-laki, saya tidak menentang Anda tetapi jawaban di bawah ini adalah praktik terbaik. Anda bahkan dapat membaca di komentar. Anda tidak boleh mentransmisikan mContext ke Aktivitas Anda karena Anda menghindari penggunaan kembali kode. Sekarang adaptor ini hanya dapat digunakan di dalam Aktivitas tempat Anda mentransmisikan variabel mContext Anda, di mana jika Anda memiliki pendengar yang ditentukan, Anda dapat menggunakan kembali Adaptor yang sama di Aktivitas lain. Percayalah, saya telah menghabiskan cukup waktu di industri dan saya hanya mencoba membantu Anda di sini, tolong jangan tersinggung.
Varundroid
2
Solusi ini adalah salah satu yang terbaik yang pernah saya temukan di SO. Jadi terima kasih banyak Pak Babu. Memanggil metode Aktivitas dengan ini, memberikan seluruh aplikasi peningkatan kinerja yang menendang 500% -> Saya tidak perlu memuat ulang database di adaptor, yang perlu saya akses. Saya tidak peduli dengan "tahun-tahun di industri", saya mencari solusi yang stabil dan berfungsi dan saya cukup yakin, saya tidak akan menemukan cara yang lebih baik untuk mendapatkan akses. Mungkin saya bisa mengatur DB sebagai singleton, tapi ini bukan cara yang saya inginkan untuk "menghilangkan struktur" proyek saya.
Martin Pfeffer
2
@RAM jika Anda perlu memanggil metode yang sama di lebih dari satu aktivitas, Anda perlu membuat antarmuka dengan nama metode itu. Kemudian implementasikan antarmuka itu di semua aktivitas yang Anda perlukan agar pemanggilan metode tersedia. Kemudian di pemroses klik, periksa contoh antarmuka Anda daripada menggunakan nama aktivitas.
Eldhose M Babu
1
Jawaban yang luar biasa. Jempol
Alok Rajasukumaran
126

Anda bisa melakukannya dengan cara ini:

Deklarasikan antarmuka:

public interface MyInterface{
    public void foo();
}

Biarkan Aktivitas Anda menerapkannya:

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

Kemudian teruskan aktivitas Anda ke ListAdater:

public MyAdapter extends BaseAdater{
    private MyInterface listener;

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

Dan di suatu tempat di adaptor, saat Anda perlu memanggil metode Aktivitas itu:

listener.foo();
Igor Filippov
sumber
5
Saya pertama kali memikirkan metode di atas seperti yang Anda lakukan dengan fragmen tetapi ini adalah solusi terbaik!
brux
1
yang mana InterfaceListener saya? bagaimana bisa menginisialisasinya? public MyAdapter (pendengar MyInterface) {this.listener = listener; }
Gilberto Ibarra
6
Bagaimana Anda meneruskan antarmuka ke adaptor (dari Aktivitas)
Brandon
1
@Brandon Anda bisa meneruskannya adalah parameter konstruktor di adaptor.
Igor Filippov
5
@Brandon, cukup tambahkan 'ini' untuk meneruskan antarmuka ke adaptor myAdapter = new MyAdapter (ini);
ajinkya
67

Asli:

Saya memahami jawaban saat ini tetapi membutuhkan contoh yang lebih jelas. Berikut adalah contoh yang saya gunakan dengan Adapter(RecyclerView.Adapter) dan Activity.

Dalam Aktivitas Anda:

Ini akan menerapkan interfaceyang kami miliki di kami Adapter. Dalam contoh ini, ini akan dipanggil saat pengguna mengklik item di 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);
    }
}

Di Adaptor Anda:

Di Activity, kami memulai kami Adapterdan meneruskan ini sebagai argumen kepada pembuatnya. Ini akan memulai interfaceuntuk metode panggilan balik kami. Anda dapat melihat bahwa kami menggunakan metode panggilan balik untuk klik pengguna.

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();
    }
}
Jared Burrows
sumber
6
terima kasih untuk ini, itulah yang saya cari. terpilih
Nactus
ini berhasil untuk saya! imo, kode kerja terlengkap sejauh ini!
publikasikan pengetahuan
2
Terima kasih untuk solusi ini
Steve
4
jawaban ini harus memiliki lebih banyak suara positif, ini solusi yang bersih dan sempurna.
Opiatefuchs
Hai @ Jared - Dapatkah Anda memperbaiki sampel yang sama EventBusseperti yang Anda sarankan?
Tohid
15

Dasar dan sederhana.

Di adaptor Anda cukup gunakan ini.

((YourParentClass) context).functionToRun();

Ck Maurya
sumber
4
bukan praktik yang baik karena Anda membatasi kelas Anda untuk bekerja hanya dengan tipe YourParentClass dan bukan kelas apa pun, tetapi berfungsi jika Anda tidak peduli untuk menggunakannya kembali, jika Anda juga mengganti nama kelas, kodenya rusak ...
Gustavo Baiocchi Costa
7

Satu cara lagi adalah:

Menulis metode dalam adaptor Anda, misalnya public void callBack () {}.

Sekarang saat membuat objek untuk adaptor dalam aktivitas mengganti metode ini. Metode override akan dipanggil saat Anda memanggil metode di adaptor.

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

Untuk Kotlin:

Di adaptor Anda, cukup panggil

(context as Your_Activity_Name).yourMethod()
Numair
sumber
0
if (parent.getContext() instanceof yourActivity) {
  //execute code
}

kondisi ini akan memungkinkan Anda untuk menjalankan sesuatu jika Kegiatan yang memiliki GroupViewyang meminta dilihat dari getView()metode Anda adapteryaituyourActivity

CATATAN: parentadalah GroupView itu

Abd Salam Baker
sumber
GroupView ini meminta tampilan dari adaptor saat memanggil getView()metode ..... jadi kami mendapatkan konteks GroupView itu, dan memeriksanya melalui kondisi di atas
Abd Salam Baker
0

Di Kotlin sekarang ada cara yang lebih bersih dengan menggunakan fungsi lambda, tidak perlu antarmuka:

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) {

    }
}
Pedang
sumber