ไม่จำเป็นต้องส่งผลลัพธ์ของ findViewById?


152

เมื่อเร็ว ๆ นี้ฉันพบว่า AndroidStudio เตือนให้ฉันลบบางนักแสดงระดับ ฉันจำได้ว่าในสมัยก่อนเราต้องส่งผลของ findViewById แต่ตอนนี้ไม่จำเป็น

ผลลัพธ์ของ findViewById ยังคงเป็นวิวดังนั้นฉันต้องการทราบว่าทำไมเราไม่จำเป็นต้องใช้คลาส?

ฉันไม่พบเอกสารใด ๆ ที่กล่าวถึงว่าใคร ๆ ก็สามารถค้นหาเอกสารใด ๆ ได้บ้าง


7
เพราะตอนนี้มันเป็น<T extends View> T findViewById(int id)?
Selvin

คุณต้องแคสต์ในกรณีของการดำเนินการใด ๆ ที่ไม่ได้อยู่ใน View class เช่นในกรณีของ ImageView หากคุณต้องการใช้ setImageResource คุณต้องใช้ findViewById ด้วย ImageView
Gagan Deep

แต่ฉันรู้สึกไม่สะดวกเล็กน้อยที่จะรู้ประเภทของตัวแปรอย่างรวดเร็วหากถอดการคัดเลือก "ซ้ำซ้อน" ออก
ผลไม้

คำตอบ:


235

เริ่มต้นด้วย API 26 findViewByIdใช้การอนุมานสำหรับชนิดส่งคืนเพื่อให้คุณไม่ต้องแปลงอีกต่อไป

คำนิยามเก่า:

View findViewById(int id)

คำนิยามใหม่:

<T extends View> T findViewById(int id)

ดังนั้นถ้าcompileSdkอย่างน้อย 26 ของคุณก็หมายความว่าคุณสามารถใช้สิ่งนี้ได้ :)


ขอบคุณและคำถามอื่น ฉันหาแหล่งสำหรับ sdk26 ในตัวจัดการ sdk ไม่ได้ฉันจะหาคำนิยามใหม่นี้ได้ที่ไหน
Eric Zhao

17
หากเราลบตัวละครออกแอพของเรายังคงสามารถทำงานได้บนอุปกรณ์ที่ต่ำกว่าใช่ไหม
user1032613

17
@ user1032613: ใช่แอปยังคงสามารถทำงานกับอุปกรณ์ที่ต่ำกว่าได้โดยไม่มีปัญหา
Alireza Noorali

1
สิ่งนี้จะทำให้เกิดข้อยกเว้นหรือไม่หากเป็นประเภทที่ไม่ถูกต้อง
fobbymaster

1
ราวกับว่ามุมมองในไฟล์เลย์เอาต์นั้นแตกต่างกันอย่างไร ClassCastExceptionใช่แน่นอนก็จะยังคงเป็น
Eduard B.

13

ตามบทความนี้ :

ฟังก์ชั่นต่อไปนี้ขึ้นอยู่กับการอนุมานประเภท generics อัตโนมัติของ Java เพื่อขจัดความจำเป็นในการคัดเลือกนักแสดง:

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

11

ในรุ่นเก่ากว่า:

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

จาก Android Studio 3.0 ด้วย SDK 26:

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

16
สิ่งนี้ไม่ได้ให้คำตอบของคำถาม
Wijay Sharma

1

Android Studio เตือนให้นำการส่งออกหากคุณใช้แอตทริบิวต์ทั่วไปจากView class เช่นการเปิดเผยหรือวิธีการทั่วไปเช่นonClick ()

ตัวอย่างเช่น:

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

ในกรณีนี้คุณสามารถเขียน:

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

2
คุณยังต้องประกาศประเภทคุณจะต้องเขียน: findViewById <ImageView> (R.id.image_car) .setVisibility (View.VISIBLE);
Slickelito

Android Studio เตือนให้เราลบการส่งที่ชัดเจนเนื่องจากมีการเปลี่ยนแปลงในการใช้งานการอนุมานแบบอัตโนมัติของ Java ทั่วไป - มันไม่มีอะไรเกี่ยวข้องกับวิธีการที่คุณใช้
zeroDivider

1

Android 0, ทำความสะอาดการคัดเลือกนักแสดง

หนึ่งในสิ่งที่ Google ประกาศใน IO 2017 คือสิ่งที่เรียกว่า 'ทิ้งไป' :) นักพัฒนา Android ไม่จำเป็นต้องทำการคัดลอกคู่มือสำหรับ findViewById () ตัวอย่างเช่นวิธีเก่า ๆ ในการรับมุมมองข้อความโดยใช้ findViewById () จะเป็นแบบนี้

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

ในขณะที่วิธีการใหม่จะเป็นเช่นนี้

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

มันเป็นการเปลี่ยนแปลงที่ง่าย แต่สำหรับโปรแกรมเมอร์ที่มีประสบการณ์แล้วรหัสที่สะอาดอย่างนี้สามารถทำให้คุณมีความสุขมากและมันจะช่วยให้คุณมีอารมณ์การเขียนโปรแกรม :)

เพื่อให้สามารถทำสิ่งนี้ได้คุณจะต้องตั้งค่าโปรเจ็กต์ sdk ที่รวบรวมเป็นเวอร์ชัน 26 ในแอพ build.gradle ของคุณ

คุณยังสามารถกำหนดเป้าหมายเวอร์ชัน sdk ก่อนหน้าได้เช่นกันดังนั้นจึงเป็นการเปลี่ยนแปลงที่ไม่ล่วงล้ำ

ทีนี้ปัญหาที่แท้จริงคุณจะทำความสะอาดโค้ดเก่าที่ใช้การคัดเลือกนักแสดงได้ตลอดเวลาอย่างไร โดยเฉพาะอย่างยิ่งเมื่อคุณมีไฟล์กิจกรรมหลายร้อยไฟล์ คุณสามารถทำได้ด้วยตนเองหรืออาจว่าจ้างผู้ฝึกงานให้ทำ😛 แต่โชคดีสำหรับผู้ฝึกงานทุกคน, android studio เตรียมไว้แล้วเพื่อช่วยเหลือพวกเรา

เมื่อคุณวางคาเร็ท (หรือคลิกที่แคสต์สตูดิโอหุ่นยนต์ซ้ำซ้อน) จะแนะนำ 2 ตัวเลือกในการจัดการแคสต์ซ้ำซ้อน

ก่อนอื่นมันจะแนะนำให้ลบ cast ที่ซ้ำซ้อนหรือคุณสามารถเลือก clean up code มันจะลบ cast ที่ซ้ำซ้อนทั้งหมดสำหรับไฟล์นั้น มันดีกว่า แต่เราต้องการมากกว่านี้ เราไม่ต้องการที่จะเปิดแต่ละไฟล์และทำความสะอาดนี้โดยหนึ่ง

หนึ่งในสิ่งที่ทำให้แนวคิดพิเศษของ IntelliJ คือฟีเจอร์ที่เรียกว่าการกระทำแบบเจตนา สิ่งที่คุณต้องทำคือกด ctrl + shift + A แล้วพิมพ์ clean และเลือกการกระทำการล้างข้อมูลโค้ดและเลือกขอบเขตโครงการทั้งหมด ด้วยขั้นตอนง่ายๆไม่กี่ขั้นตอนนี้รหัสของคุณจะสะอาดกว่าเดิมมาก

จุดสำคัญอย่างหนึ่งคือคุณทำสิ่งนี้กับระบบการควบคุมเวอร์ชันของรหัส วิธีนี้คุณสามารถเปรียบเทียบการเปลี่ยนแปลงที่เกิดขึ้นจากการกระทำโดยเจตนาและย้อนกลับไฟล์ใด ๆ ที่คุณต้องการ

คัดลอกมาจากโพสต์ต้นฉบับ:

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


1
คำถามคือwhyไม่ใช่how:The result of findViewById is still View, so i want to know why we don't need to cast the class?
zeroDivider

"สิ่งที่คุณต้องทำคือกด ctrl + shift + A แล้วพิมพ์ clean" คุณหมายถึงอะไรโดย "type clean"? หากคุณเริ่มพิมพ์ที่จุดนั้นคุณจะลบไฟล์ทั้งหมด
Stealth Rabbi

0

ในซอร์สโค้ดViewGroupมีการส่งคืนอากิวเมนต์ return ดังนั้นไม่จำเป็นต้องร่ายอีกครั้ง:

@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;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.