Dapatkan aktivitas dari konteks di android

184

Yang ini membuat saya bingung.

Saya perlu memanggil metode aktivitas dari dalam kelas tata letak khusus. Masalahnya adalah saya tidak tahu cara mengakses aktivitas dari dalam tata letak.

ProfileView

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

Seperti yang Anda lihat di atas, saya membuat profil profileView secara terprogram dan meneruskan activityContext dengannya. 2 pertanyaan:

  1. Apakah saya meneruskan konteks yang benar ke dalam Profileview?
  2. Bagaimana saya mendapatkan aktivitas yang mengandung dari konteks?
NADA TAMBAHAN
sumber

Jawaban:

473

Dari Anda Activity, cukup berikan thissebagai Contexttata letak Anda:

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

Setelah itu Anda akan memiliki Contextdalam tata letak, tetapi Anda akan tahu itu sebenarnya milik Anda Activitydan Anda dapat melemparkannya sehingga Anda memiliki apa yang Anda butuhkan:

Activity activity = (Activity) context;
Boris Strandjev
sumber
53
Anda tidak dapat dijamin bahwa konteks yang Anda kerjakan adalah Konteks Aktivitas atau Konteks Aplikasi. Coba sampaikan Konteks Aplikasi ke DialogView, lihat itu crash, dan Anda akan melihat perbedaannya.
Sky Kelsey
6
Boris, pertanyaannya menanyakan apakah ada cara untuk mendapatkan Kegiatan dari suatu Konteks. Ini tidak mungkin. Tentu saja Anda bisa memilih, tetapi itu adalah pilihan terakhir. Jika Anda ingin memperlakukan Konteks sebagai Aktivitas, maka jangan downcast ke Aktivitas. Itu membuat kode lebih sederhana, dan tidak terlalu rentan terhadap bug saat orang lain menjaga kode Anda.
Sky Kelsey
6
Perhatikan bahwa 'getApplicationContext ()' bukan 'ini' tidak akan berfungsi.
dwbrito
1
@ BorisStrandjev Saya belum mengerti komentar Anda. Ngomong-ngomong, saya mengatakan bahwa setelah mencoba contoh Anda tetapi alih-alih 'ini' saya menggunakan getApplicationContext () dan aplikasi mencoba untuk menggunakan Aplikasi itu sendiri, sehingga memberikan kesalahan pemain, bukan aktivitas. Setelah beralih ke 'ini', saat Anda menjawab, itu berhasil.
dwbrito
1
Jawaban terunggul tertinggi pada tautan Anda keduanya menyarankan untuk menantang pertanyaan jika itu bau. Pertanyaan ini tentu saja bau. OP pertama kali menyatakan: "Saya perlu memanggil metode aktivitas dari dalam kelas tata letak khusus." yang sepenuhnya dapat dicapai dengan penggunaan antarmuka yang tepat. Lalu dia berkata, "Masalahnya adalah saya tidak tahu cara mengakses aktivitas dari dalam tata letak." yang merupakan petunjuk signifikan terhadap kesalahpahaman. Orang-orang mencoba melakukan hal yang salah sepanjang waktu dalam pemrograman dan kita tidak boleh menutup mata terhadap hal itu.
Sam
39

Ini adalah sesuatu yang saya telah berhasil digunakan untuk mengkonversi Contextke Activityketika beroperasi di dalam UI dalam fragmen atau pandangan adat. Ini akan membongkar ContextWrapper secara rekursif atau mengembalikan nol jika gagal.

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;
}
Theo
sumber
Ini adalah jawaban yang benar. Yang lain tidak memperhitungkan hierarki ContentWrapper.
Snicolas
Ini adalah jawaban yang benar :)
lygstate
1
@lygstate: Level API target apa yang Anda gunakan di aplikasi Anda? Apa kesalahannya? Ini hanya berfungsi di UI (aktivitas, fragmen, dll), bukan di Layanan.
Theo
31
  1. Tidak
  2. Kamu tidak bisa

Ada dua konteks berbeda di Android. Satu untuk aplikasi Anda (Sebut saja yang BESAR) dan satu untuk setiap tampilan (sebut saja konteks aktivitas).

LinearLayout adalah tampilan, jadi Anda harus memanggil konteks aktivitas. Untuk menyebutnya dari suatu kegiatan, cukup panggil "ini". Sangat mudah bukan?

Saat Anda menggunakan

this.getApplicationContext();

Anda memanggil konteks BESAR, yang menggambarkan aplikasi Anda dan tidak dapat mengelola tampilan Anda.

Masalah besar dengan Android adalah bahwa konteks tidak dapat memanggil aktivitas Anda. Itu masalah besar untuk menghindari ini ketika seseorang memulai dengan pengembangan Android. Anda harus menemukan cara yang lebih baik untuk mengkodekan kelas Anda (atau mengganti "Konteks konteks" dengan "Aktivitas aktivitas" dan melemparkannya ke "Konteks" bila diperlukan).

Salam.


Hanya untuk memperbarui jawaban saya. Cara termudah untuk mendapatkan Anda Activity contextadalah dengan menentukan staticcontoh di Anda Activity. Sebagai contoh

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

Dan kemudian, di Anda Task, Dialog, View, Anda bisa menggunakan jenis yang kode untuk mendapatkan Anda Activity context:

if (DummyActivity.instance != null)
{
    // Do your operations with DummyActivity.instance
}
Manitoba
sumber
4
+1 untuk menjelaskan area kebingungan yang sangat umum antara 2 jenis konteks yang berbeda (sama seperti ada 2 perbedaan R). Orang-orang Google perlu memperkaya kosa kata mereka.
an00b
3
BTW, @BorisStrandjev benar: 2. Ya, Anda bisa . (tidak dapat berdebat dengan kode kerja)
an00b
2
2. Tidak juga. Jika konteksnya adalah konteks Aplikasi, maka aplikasi Anda akan macet.
StackOverflowed
contoh statis ?! @Nepster memiliki solusi terbaik untuk imo ini
Sam
14
Membuat referensi statis ke suatu Aktivitas adalah cara terbaik untuk membuat kebocoran memori.
BladeCoder
8

Jika Anda ingin memanggil metode aktivitas dari dalam kelas tata letak khusus (kelas Non-Aktivitas). Anda harus membuat delegasi menggunakan antarmuka.

Ini belum diuji dan saya mengkodekannya dengan benar. tetapi saya menyampaikan cara untuk mencapai apa yang Anda inginkan.

Pertama-tama buat dan Antarmuka

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

Dan terapkan ini untuk Kegiatan apa pun.

dan menyebutnya seperti

ProfileView pv = new ProfileView(actvitiyContext, null, temp, tempPd);
pv.setCallBack(new TaskCompleteListener
               {
                   public void onProfileClicked(String resultStringFromProfileView){}
               });
Zar E Ahmer
sumber
1
Ini adalah jawaban yang benar dan harus ditandai sebagai jawaban yang benar. Saya tahu jawaban yang ditandai sebagai yang benar benar-benar menjawab pertanyaan OP, tetapi seharusnya tidak menjawab pertanyaan seperti itu. Faktanya adalah bahwa itu bukan praktik yang baik untuk lulus dalam Kegiatan seperti itu di dalam tampilan. Anak itu seharusnya tidak pernah tahu tentang orang tua mereka dalam hal apa pun, kecuali melalui Context. Seperti yang dinyatakan Nepster, praktik terbaik adalah meneruskan panggilan balik, sehingga setiap kali terjadi sesuatu yang menarik bagi orang tua, panggilan balik akan dipecat dengan data yang relevan.
Darwind
6

Konteks mungkin Aplikasi, Layanan, Kegiatan, dan banyak lagi.

Biasanya konteks Penayangan dalam Aktivitas adalah Aktivitas itu sendiri sehingga Anda mungkin berpikir Anda bisa langsung melemparkan Konteks ini ke Aktivitas tetapi sebenarnya Anda tidak selalu dapat melakukannya, karena konteksnya juga bisa menjadi ContextThemeWrapper dalam kasus ini.

ContextThemeWrapper banyak digunakan dalam versi terbaru dari AppCompat dan Android (berkat atribut android: theme dalam layout) jadi saya pribadi tidak akan pernah melakukan pemeran ini.

Jadi jawaban singkatnya adalah: Anda tidak dapat secara andal mengambil suatu Kegiatan dari suatu Konteks dalam Tampilan. Lewati Aktivitas ke tampilan dengan memanggil metode yang mengambil Kegiatan sebagai parameter.

BladeCoder
sumber
3

Tidak pernah menggunakan getApplicationContext () dengan tampilan.

Itu harus selalu menjadi konteks aktivitas, karena pandangan melekat pada aktivitas. Selain itu, Anda mungkin memiliki set tema khusus, dan saat menggunakan konteks aplikasi, semua tema akan hilang. Baca lebih lanjut tentang berbagai versi konteks di sini .

lomza
sumber
3

Dan di Kotlin:

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

Suatu Kegiatan adalah spesialisasi dari Konteks, jadi, jika Anda memiliki suatu Konteks Anda sudah tahu aktivitas mana yang ingin Anda gunakan dan dapat dengan mudah memasukkan a ke dalam c ; di mana a adalah Kegiatan dan c adalah Konteks.

Activity a = (Activity) c;
ACLima
sumber
7
Ini berbahaya karena, sebagaimana disebutkan dalam komentar terpisah, konteksnya mungkin tidak selalu sebuah Aktivitas.
4
typecast only if (instance instance of Activity) {// typecast}
Amit Yadav
0

Saya menggunakan Aktivitas konversi

Activity activity = (Activity) context;
Samuel Ivan
sumber
2
Ada berbagai jenis konteks. Aktivitas dan Aplikasi dapat memiliki konteks. Ini hanya akan berfungsi ketika konteksnya adalah suatu kegiatan.
cylov
0

Metode ini harus membantu ..!

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;

    }

Saya harap ini membantu .. Selamat coding!

Taslim Oseni
sumber
Periksa bahwa konteks yang Anda berikan bukan nol .. Kemungkinan besar masalahnya.
Taslim Oseni
0

bagaimana dengan beberapa panggilan balik data langsung,

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

class ProfileActivity{

  override fun onCreateView(...){

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

}
Abhinav Atul
sumber