17 September 2017

[Android Dev Tips] ยุคนี้ทั้งที เปลี่ยน findViewById เป็นแบบใหม่กันเถอะ



        เป็นบทความสั้นๆเพื่ออัพเดทรูปแบบการเขียนโค้ดของคำสั่ง findViewById แบบใหม่ให้กับผู้ที่หลงเข้ามาอ่านซักหน่อย ถึงแม้ว่าผู้ที่หลงเข้ามาอ่านหลายๆคนจะรู้เรื่องนี้กันแล้ว แต่ก็น่าจะมีบางคนที่ยังไม่รู้หลงเหลืออยู่บ้าง

ใครไม่รู้จักคำสั่ง findViewById บ้าง?

        ตั้งแต่สมัยที่แอนดรอยด์ถูกสร้างขึ้นมาจวบจนมาถึงทุกวันนี้ เรียกได้ว่าไม่มีนักพัฒนาคนไหนไม่เคยเห็นคำสั่ง findViewById มาก่อน เพราะว่ามันคือคำสั่งแรกๆที่ทุกคนได้รู้จักกัน ซึ่งคำสั่งจะมีลักษณะแบบนี้

Button btnConfirm = (Button) findViewById(R.id.btnConfirm);
TextView tvRegistrationInfo = (TextView) findViewById(R.id.tvRegistrationInfo);

         และนักพัฒนาทุกคนก็จะจำกันได้อย่างแม่นยำว่า

        • ถ้าเป็น Button ก็ต้อง Cast ให้เป็น Button ก่อนทุกครั้ง
        • ถ้าเป็น RecyclerView ก็ต้อง Cast ให้เป็น RecyclerView ก่อนทุกครั้ง
        • ถ้าเป็น LinearLayout ก็ต้อง Cast ให้เป็น LinearLayout ก่อนทุกครั้ง
        • ฯลฯ

        เพราะว่า findViewById เป็นคำสั่งที่จะส่งค่ากลับมาเป็น View ทุกครั้ง

View findViewById (int id)

        ก็เลยต้องแปลงคลาสให้เป็นคลาสที่ต้องการใช้งาน โดยจะต้องเป็นคลาสที่สืบทอดมาจาก View นั่นเอง

        ซึ่งการที่ต้องมานั่งแปลงคลาสทุกครั้งเวลาจะใช้งานนั้นเป็นอะไรที่ค่อนข้างน่าเบื่อเหมือนกันนะ จนนักพัฒนาหลายๆคนได้หาตัวช่วยอื่นๆเข้ามาแทนที่มากมาย ไม่ว่าจะใช้ ButterKnife หรือว่า DataBinding เพื่อเลี่ยงคำสั่งจำเจอย่าง findViewById แต่ทว่ามันก็ยังเป็นคำสั่งยอดนิยมที่ส่วนใหญ่ใช้งานกันอยู่ดีน่ะแหละ

ถึงเวลาของ findViewByid แบบใหม่แล้ว!

        ในงาน Google I/O 2017 ที่ผ่านมาได้มีการประกาศอย่างหล่อๆว่า

        "ต่อไปนี้ไม่ต้องแปลงคลาสเวลาเรียกใช้งาน findViewById อีกต่อไปแล้ว!!!"

        นั่นก็เพราะว่าคำสั่ง findViewById จะถูกเปลี่ยนใหม่ให้กลายเป็นแบบนี้แทน

T findViewById (int id)

        ซึ่ง T ที่ว่านี้คือคลาสใดๆขึ้นอยู่กับว่า ID ที่กำหนดนั้นเป็น View แบบไหน ถ้าเป็นของ Button มันก็จะได้ออกมาเป็นคลาส Button โดยอัตโนมัติ และเวลาเรียกใช้คำสั่ง findViewById ก็ไม่ต้องเสียเวลามานั่งแปลงคลาสอีกต่อไป

Button btnConfirm = findViewById(R.id.btnConfirm);
TextView tvRegistrationInfo = findViewById(R.id.tvRegistrationInfo);

        โดยจะสังเกตได้จาก Android Studio ที่คอยแจ้งเตือนในโค้ดว่า "ให้ลบออกได้แล้ววววว"


อ้าว ทำไมของบางคนยังต้องแปลงคลาสอยู่ล่ะ?

        การใช้งาน findViewById แบบใหม่นั้นจะมีอยู่ 2 เงื่อนไขด้วยกัน ซึ่งรองรับการใช้งานกับแอนดรอยด์เวอร์ชันเก่าๆด้วยนะ

ถ้าอยากใช้งานบน Android Framework : โปรเจคต้องกำหนดเป็น API 26 ขึ้นไป 

         ในกรณีที่อยากจะให้คลาส Activity หรือ View ของ Android Framework เดิมนั้นรองรับ findViewById แบบใหม่ จะต้องกำหนดโปรเจคให้ใช้ API 26 ขึ้นไปครับ ทางที่ดีก็ให้กำหนดเหมือนๆกันทั้ง compileSdkVersion, buildToolsVersion และ targetSdkVersion ไปเลย จะได้ไม่ต้องวุ่นวายอะไรมากนัก

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.1"
    defaultConfig {
        targetSdkVersion 26
        ...
    }
    ...
}

        ส่วน minSdkVersion จะกำหนดเป็นเวอร์ชันอะไรก็ได้

ถ้าอยากใช้งานบน Android Support Library : Library ต้องกำหนดเป็นเวอร์ชัน 26 ขึ้นไป

        เจ้าของบล็อกก็เป็นคนหนึ่งที่เลิกใช้คลาส Activity แบบเดิมๆแล้ว เพราะเปลี่ยนไปใช้พวก AppCompatActivity แทนเพื่อให้ใช้งาน Android Support Library ตัวอื่นๆได้สะดวก

        ดังนั้นถ้าอยากใช้ findViewById แบบใหม่ ก็จะต้องกำหนดให้ Android Support Library ทุกตัวในโปรเจคใช้เป็นเวอร์ชัน 26 ขึ้นไปซะ

dependencies {
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support:design:26.1.0'
    implementation 'com.android.support:customtabs:26.1.0'
    ...
}

สรุป

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

        ในแง่ของการ Migrate ถ้ามีโปรเจคที่กำลังทำอยู่หรือโปรเจคเก่าๆ ก็สามารถอัพเดท SDK ในโปรเจคและ Library ของ Android Support Library ให้เป็นเวอร์ชัน 26 แล้วไล่ลบคำสั่งแปลงคลาสออกได้เลย แต่ถ้าโปรเจคเก่ามากๆแนะนำให้เช็คก่อนว่ามีการทำงานอย่างอื่นที่ส่งผลกระทบด้วยหรือป่าว เช่น Migrate มาจาก API 21 เป็น API 26 ก็ควรจะเช็คเรื่อง Runtime Permission ของ API 23 ด้วย

        แต่ถ้าไปใช้ ButterKnife, DataBinding หรือเขียนด้วย Kotlin ไปเลย น่าจะสะดวกกว่านะ ฮ่าๆ