Tidak perlu membuang hasil findViewById?

152

Baru-baru ini saya menemukan bahwa AndroidStudio mengingatkan saya untuk menghapus beberapa pemeran kelas. Saya ingat bahwa di masa lalu, kita harus memberikan hasil findViewById, tapi sekarang itu tidak perlu.

Hasil findViewById masih View, jadi saya ingin tahu mengapa kita tidak perlu membuat kelas?

Saya tidak dapat menemukan dokumen yang disebutkan itu, adakah yang bisa menemukan dokumen?

Eric Zhao
sumber
7
karena sekarang ini <T extends View> T findViewById(int id)?
Selvin
Anda perlu melakukan casting jika ada operasi yang tidak ada di kelas View, seperti dalam kasus ImageView, Jika Anda ingin menggunakan setImageResource, maka Anda harus menggunakan findViewById dengan ImageView
Gagan Deep
Tapi saya merasa agak tidak nyaman untuk mengetahui tipe variabel secara sekilas jika menghapus casting "redundant".
Buah

Jawaban:

235

Dimulai dengan API 26, findViewByIdgunakan inferensi untuk jenis pengembaliannya, jadi Anda tidak perlu lagi melakukan casting.

Definisi lama:

View findViewById(int id)

Definisi baru:

<T extends View> T findViewById(int id)

Jadi, jika Anda compileSdksetidaknya 26, itu berarti Anda dapat menggunakan ini :)

Eduard B.
sumber
Terima kasih, dan pertanyaan lain. saya tidak dapat menemukan sumber untuk sdk26 di sdk manager, jadi di mana saya dapat menemukan definisi baru ini?
Eric Zhao
17
Jika kami menghapus para pemain, aplikasi kami masih dapat berjalan di perangkat yang lebih rendah, bukan?
user1032613
17
@ user1032613: Ya aplikasi masih dapat bekerja di perangkat yang lebih rendah tanpa masalah.
Alireza Noorali
1
Apakah ini akan melempar pengecualian jika jenisnya salah?
fobbymaster
1
Seperti apakah tampilan dalam file tata letak adalah tipe yang berbeda? Ya, tentu saja, itu masih akan menjadi ClassCastException.
Eduard B.
13

Menurut artikel ini :

Fungsi berikut bergantung pada inferensi tipe otomatis generik Java untuk menghilangkan kebutuhan untuk casting manual:

protected <T extends View> T findViewById(@IdRes int id) {
    return (T) getRootView().findViewById(id);
}
zeroDivider
sumber
11

Dalam versi yang lebih lama:

AutoCompleteTextView name = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView);

Dari Android Studio 3.0 dengan SDK 26:

AutoCompleteTextView name = findViewById(R.id.autoCompleteTextView);
Midhun
sumber
16
Ini tidak memberikan jawaban atas pertanyaan itu.
Wijay Sharma
1

Android Studio mengingatkan untuk menghapus casting, jika Anda menggunakan atribut umum dari kelas Tampilan , seperti visibilitas atau beberapa metode umum, seperti onClick ()

Sebagai contoh:

((ImageView) findViewById(R.id.image_car)).setVisibility(View.VISIBLE);

Dalam hal ini Anda cukup menulis:

findViewById(R.id.image_car).setVisibility(View.VISIBLE);
Tim
sumber
2
Anda masih harus mendeklarasikan jenisnya, Anda harus menulis: findViewById <ImageView> (R.id.image_car) .setVisibility (View.VISIBLE);
Slickelito
Android Studio mengingatkan kita untuk menghapus casting eksplisit karena itu berubah dalam implementasi inferensi tipe otomatis generik Java - itu tidak ada hubungannya dengan metode apa yang Anda gunakan.
zeroDivider
1

Android 0, bersihkan casting

Salah satu hal yang diumumkan google di IO 2017 adalah sesuatu yang disebut 'dibuang' :). Pengembang Android tidak perlu melakukan casting manual untuk findViewById (). Misalnya cara lama untuk mendapatkan tampilan teks menggunakan findViewById () akan menjadi seperti ini.

TextView txtDesc = (TextView) findViewById(R.id.textViewDesc);
txtDesc.setText(getString(R.string.info_angkot_description));

Sedangkan cara baru akan seperti ini

TextView txtDesc = findViewById(R.id.textViewDesc);
txtDesc.setText(getString(R.string.info_angkot_description));

Ini perubahan sederhana. Tetapi untuk seorang programmer berpengalaman, kode bersih seperti ini dapat membuat Anda sangat senang dan ini membantu dengan suasana hati coding Anda :)

Untuk dapat melakukan ini, Anda hanya perlu mengatur versi sdk proyek yang dikompilasi ke versi 26 di build.gradle aplikasi Anda.

Anda masih dapat menargetkan versi SDK sebelumnya juga, jadi ini adalah perubahan yang tidak mengganggu.

Sekarang masalah sebenarnya, bagaimana Anda membersihkan kode lama yang menggunakan casting selama ini. Terutama ketika Anda memiliki ratusan file aktivitas. Anda dapat melakukannya secara manual, atau mungkin menyewa magang untuk melakukannya 😛. Tapi untungnya bagi semua magang itu, studio android sudah siap untuk membantu kami dengan ini.

Saat Anda meletakkan tanda sisipan Anda (atau mengklik casting redundan), studio android akan menyarankan 2 opsi untuk menangani casting redundan.

Pertama-tama akan disarankan untuk menghapus pemain yang berlebihan atau Anda dapat memilih kode pembersihan. Ini akan menghapus semua pemeran yang berlebihan untuk file itu. Ini lebih baik, tetapi kami menginginkan lebih. Kami tidak ingin membuka setiap file dan melakukan ini membersihkan satu per satu.

Salah satu hal yang membuat IntelliJ idea Special adalah fitur yang disebut niat tindakan. Yang harus Anda lakukan adalah menekan ctrl + shift + A dan kemudian ketik clean. Dan pilih Code Clean up action, dan pilih seluruh lingkup proyek. Dengan beberapa langkah sederhana ini, kode Anda akan jauh lebih bersih.

Satu poin penting adalah Anda melakukan ini dengan beberapa sistem kode versi. Dengan cara ini Anda dapat membandingkan perubahan yang dibuat oleh tindakan niat dan mengembalikan file apa pun yang Anda inginkan.

Disalin dari pos asli:

https://medium.com/@abangkis/android-0-clean-up-casting-c30acec56cef

daliaessam
sumber
1
pertanyaannya adalah why, bukan how:The result of findViewById is still View, so i want to know why we don't need to cast the class?
zeroDivider
"Yang harus Anda lakukan adalah mendorong ctrl + shift + A dan kemudian ketik bersih". Apa yang Anda maksud dengan "ketik bersih"? Jika Anda mulai mengetik pada saat itu, Anda akan menghapus seluruh file
Stealth Rabbi
0

Dalam kode sumber ViewGroup, ada para pemain argumen kembali. Jadi tidak perlu dilemparkan lagi:

@Nullable
public final <T extends View> T findViewById(@IdRes int id) {
    if (id == NO_ID) {
        return null;
    }
    return findViewTraversal(id);
}

@Override
protected <T extends View> T findViewTraversal(@IdRes int id) {
    if (id == mID) {
        return (T) this;  //###### cast to T
    }

    final View[] where = mChildren;
    final int len = mChildrenCount;

    for (int i = 0; i < len; i++) {
        View v = where[i];

        if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
            v = v.findViewById(id);

            if (v != null) {
                return (T) v; //###### cast to T
            }
        }
    }

    return null;
}
aktivitas
sumber