เรียนรู้การเขียนแอพ Android สไตล์ Front-end Web Developer

หลังจากที่ผมได้ลองศึกษาการเขียนแอพ Android ดูคร่าวๆ ก็พบว่ามีเนื้อหาหลายๆ ส่วนเลย ที่ front-end web developer อย่างเราๆ จะได้เปรียบในการทำความเข้าใจครับ เพราะหลักการโดยรวมๆ นั้นไม่ได้แตกต่างกันมาก เรียกได้ว่าหากใครเป็น front-end web developer อยู่แล้ว และสามารถเขียน Java ได้ด้วย การเขียนแอพ Android นี่ถือเป็นสกิลที่ห้ามพลาดเลยล่ะครับ

จะเขียนแอพ Android ไปทำไม ?

สาเหตุที่ผมเขียนบทความนี้ขึ้นมาก็เพราะเสียดายสกิลของเพื่อนๆ ครับ อย่างที่บอกไปแล้วว่า หากเราเขียน Java เป็นอยู่แล้ว การเขียนแอพ Android นั้น ถือเป็นการต่อยอดที่น่าลงทุนเอามากๆ ครับ บางคนอาจจะกลัวว่าเขียนเป็นแต่ html, css, js แบบนี้จะไปรอดมั้ย ? บอกเลยว่ารอดครับ เดี๋ยวผมจะพยายามโยงการเขียนแอพ Android เข้ากับโลกของ front-end web development ที่เราคุ้นเคย แล้วอะไรๆ ก็จะง่ายขึ้นเองครับ ส่วนภาษา Java นี่ หากใครยังไม่เคยเขียนมาก่อนก็ไม่ต้องกังวลไปครับ เพราะถือเป็นภาษาที่เรียนรู้ได้ไม่ยากเลย

ภาพรวมของการเขียนแอพ Android

การเขียนแอพ Android นั้น สิ่งที่เราต้องทำจะแบ่งออกเป็น 2 ส่วนหลักๆ เท่านั้นเองครับ

  • UI Implementation ui ถือเป็นส่วนที่สำคัญเอามากๆ ของแอพเลย ความท้าทายของการทำ ui ใน Android นั้นอยู่ที่ความหลากหลายของ device ครับ บางคนทำแอพออกมาดูดีมากๆ ใน mobile แต่พอไปใช้กับ tablet แล้วคนละเรื่องเลย
  • Input / Event Handling การรับ input และดัก event ต่างๆ รวมไปถึงการเชื่อม ui ต่างๆ เข้าด้วยกัน ก็สำคัญไม่แพ้กันครับ ความท้าทายในส่วนนี้อยู่ที่เราจะเขียนโค้ดอย่างไรให้แอพมันมี performance ที่ดี ไม่กินแรม

เข้าใจ UI ในโลกของ Android

เรามาเริ่มทำความเข้าใจเกี่ยวกับ ui ในโลกของ Android กันดีกว่าครับ ว่ามันเหมือนหรือแตกต่างจากโลกของเว็บอย่างไร ตรงไหนบ้าง ?

สร้างด้วย XML

หากเป็นเว็บ เราจะสร้าง ui ต่างๆ ด้วย html แล้วตกแต่งสไตล์ให้มันด้วย css ใช่มั้ยล่ะครับ แต่พอเป็น Android เราจะเขียนด้วย xml แทนครับ ทั้งส่วนที่เป็น ui และส่วนที่เป็นการตกแต่งสไตล์เลย เรียกว่าเข้าทางสายเว็บอย่างเราเอามากๆ ^0^

รู้จักกับ Resources System

เวลาทำเว็บ เราก็มักจะสร้างโฟลเดอร์สำหรับจัดเก็บไฟล์ static อย่าง css, images หรือ template เอาไว้ถูกมั้ยครับ การเขียน Android ก็เหมือนกันครับ เราจะเอาพวกไฟล์ static ทั้งหลายเก็บไว้ในโฟลเดอร์ที่ชื่อ res ซึ่งก็คือ resources ต่างๆ ที่แอพจะต้องใช้นั่นเองครับ ภายในโฟลเดอร์ res นี้ ยังถูกแบ่งออกเป็นโฟลเดอร์ย่อยๆ อีก ไม่ว่าจะเป็น drawable (รูป), layout (เทมเพลท), values (สไตล์, ค่าคงที่ต่างๆ) ฯลฯ

วิธีสร้าง Layout / Element ต่างๆ

มาถึงตรงนี้ เรารู้แล้วว่าการทำ ui ใน Android นั้นก็แค่สร้างไฟล์ xml ขึ้นมาอันนึง แล้วก็เขียนโค้ดสำหรับสร้าง ui ลงไปตามรูปแบบที่เค้ากำหนดไว้ จากนั้นก็เอาไปใส่ไว้ในโฟลเดอร์ res/layout เท่านั้นเอง ทีนี้เราลองมาสร้าง layout แบบง่ายๆ กันเลยดีกว่า

Layout

จริงๆ แล้ว layout มีอยู่หลายแบบครับ แต่ที่เราใช้บ่อยๆ ก็จะเป็นแบบ linear และ relative

  • Linear – element ต่างๆ จะเรียงต่อๆ กันไปในแนวเส้นตรง เราสามารถเลือกได้ว่าจะให้เรียงแนวตั้งหรือแนวนอน
  • Relative – element ต่างๆ จะสามารถทับกันได้ สามารถกำหนดให้จัดชิดซ้าย กลาง ขวา บน ล่าง ต่อจากตัวนั้น อยู่ล่างตัวนี้ ได้หมดเลย

รู้สึกว่ามันคุ้นๆ มั้ยครับ ? มันก็เหมือนกับการกำหนด display หรือ position ของ container ในการทำเว็บนั่นเอง เพื่อให้เห็นภาพมากขึ้นเรามาดูตัวอย่างโค้ดกันเลยดีกว่าครับ

ส่วน layout แบบ relative ก็จะคล้ายๆ กันเลยครับ

จะเห็นว่ามันก็เป็นแค่ xml ธรรมดาๆ ที่กำหนด namespace เอาไว้เท่านั้นเองครับ ชื่อ tag จะเอาไว้บอกว่ามันคืออะไร ส่วนชื่อ attribute ก็จะเอาไว้บอกว่ามันมีลักษณะอย่างไร อย่างในกรณีนี้ก็จะได้ว่าทั้ง 2 layout ด้านบนจะมีขนาดเป็น match_parent ซึ่งหมายถึงเท่ากับ parent ของมัน พูดง่ายๆ ก็คือ width: 100%; height: 100%; นั่นเองครับ

Views

เมื่อได้ layout มาแล้ว ทีนี้เราก็มาทำความรู้จักกับ view ใน Android กันบ้างครับ พูดง่ายๆ มันก็คืออะไรก็ตามที่แสดงผลออกมาในแอพนั่นละครับ ไม่ว่าจะเป็น

  • View – มันคือ div เปล่าๆ ที่ทำได้แค่เปลี่ยนสี background ครับ
  • TextView – มันคือข้อความครับ ผมมองว่ามันเหมือนกับ span
  • EditText – อันนี้เหมือน input[type="text"] เลย คือสามารถแก้ไขข้อความได้ด้วย
  • Button – คือ input[type="button"] เลย
  • ImageView – คือ img ครับ
  • ImageButton – คือ input[type="image"]
  • Checkbox – คือ input[type="checkbox"]
  • RadioButton – คือ input[type="radio"]
  • ScrollView – อันนี้จะเหมือนกับการสร้าง container ขึ้นมาอันนึง แล้วกำหนด overflow: auto เอาไว้ครับ

จริงๆ ยังมีอีกเยอะเลยนะครับ ผมขอยกมาแค่นี้ก่อนแล้วกัน พอเรารู้จักกับ view ใน Android แล้ว ทีนี้ก็ลองหยิบมันไปใส่ใน layout เมื่อกี้ได้เลยครับ

สังเกต attribute ของ TextView และ ImageView ที่ผมใส่ไปนะครับว่ามันสามารถเดาได้ง่ายๆ เลยว่ามันเอาไว้ทำอะไร

นอกจากนี้ layout ยังสามารถซ้อนใน layout ได้ด้วยนะครับ (ก็ผมบอกแล้วว่า layout มันก็คือ container ในเว็บดีๆ นี่เอง) ลองมาดูตัวอย่างกันเลย

มาถึงตรงนี้ก็จะเห็นว่าการเขียนโค้ดสร้าง ui ใน Android นั้น มีส่วนคล้ายคลึงกับการทำ front-end ของเว็บไม่น้อยเลยล่ะครับ ที่เราต้องทำก็แค่สร้าง layout ขึ้นมา แล้วก็หยิบ view ต่างๆ ไปใส่ จากนั้นก็ไล่ใส่ attribute ให้มันเพื่อที่จะได้แสดงผลออกมาตามที่เราต้องการก็เท่านั้นเอง

วิธีทำให้ดูดีทุกขนาดหน้าจอ

มาถึงเรื่องสำคัญในการสร้าง ui ใน Android ครับ ซึ่งมันก็คือการทำให้ ui ของเรายังคงโอเคอยู่ ไม่ว่าจะดูด้วย device ที่มีหน้าจอขนาดไหนก็ตาม (ซึ่งหน้าจอของ Android device นั้นมีหลายขนาดเอามากๆ) ลองเดาเล่นๆ กันสิว่า เราจะต้องทำยังไง ?

กำหนดตำแหน่งแบบ Relative

อย่างแรกเลยก็คือ เราจะต้องกำหนดตำแหน่งของ view ต่างๆ ให้เป็นแบบ relative ไม่ใช่แบบ absolute ครับ สมมติเราต้องการจะจัดข้อความเอาไว้ด้านล่างสุดของหน้าจอ วิธีทำก็คือให้ใส่ attribute ที่เอาไว้ทำหน้าที่นี้โดยเฉพาะอย่าง layout_alignParentBottom ไม่ใช่ไปใส่ layout_marginTop เยอะๆ เพื่อดันให้มันมาอยู่ข้างล่าง เพราะถ้าทำแบบนั้น เวลาเปิดดูในหน้าจอใหญ่ๆ ข้อความมันอาจจะไม่อยู่ด้านล่างสุดก็ได้ครับ

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

กำหนดขนาดด้วยหน่วย DP/SP

เราจะใช้หน่วย dp หรือ Density-independent pixel ในการกำหนดขนาดในโลกของ Android ครับ ซึ่งมันก็คือ pixel จำลอง ที่จะไม่สนความหนาแน่นของ pixel ของหน้าจอของ device นั้นๆ หรือพูดง่ายๆ ก็คือรูปขนาด 320px ใน Note3 กับ  Note4 จะใหญ่ไม่เท่ากัน เพราะจอของ Note4 มันละเอียดกว่า แต่รูปขนาด 320dp ใน Note3 กับ  Note4 จะใหญ่พอๆ กันครับ เพราะหน่วย dp มันจะตัดปัจจัยในเรื่องของความหนาแน่นของ pixel ออกไปนั่นเอง

คุ้นๆ อีกแล้วใช่มั้ยครับ ? การใช้หน่วย dp แทนหน่วย px มันก็เหมือนกับการกำหนด viewport meta tag ให้มีค่าเป็น width=device-width นั่นเอง แต่ถ้าใครยังไม่คุ้น ขอให้จำไว้ว่าเราจะไม่ใช้หน่วย px อย่างเด็ดขาดครับ ให้ใช้หน่วย dp เสมอ ไม่ว่าจะเป็นการกำหนดขนาดของ margin, padding, height เว้นเสียแต่ width ที่เรามักจะกำหนดให้เป็น match_parent ซึ่งก็คือ 100% นั่นเอง หรือถ้าหากจะแบ่งออกเป็นคอลัมน์ๆ เราก็จะใช้ layout_weight แทน ซึ่งจะเหมือนกับการกำหนด width ให้เป็น % ในโลกของเว็บครับ

ส่วนหน่วย sp นี่ก็จะคล้ายๆ กับ dp นั่นแหละครับ เพียงแต่เราจะใช้กับ text เพราะขนาดของมันจะแปรผันตามขนาดตัวอักษรที่กำหนดเอาไว้ใน setting ของ device นั้นๆ แม่เจ้า! นี่มันหลักการเดียวกับหน่วย em ในโลกของเว็บ ชัดๆ

ใช้ Configuration Qualifier

มาถึงกลไกระดับเทพของ Android ที่จะทำให้เราสามารถทำ resource selection ให้กับ device ต่างๆ ได้ครับ เราสามารถกำหนดได้ว่าหากเป็น device ที่มีหน้าจอความละเอียดสูง ให้เอารูปความคมชัดสูงไปใช้นะ หากหน้าจอใหญ่ 600dp ขึ้นไป ให้หยิบไฟล์ layout นี้ไปใช้นะ หากเป็น Android เวอร์ชั่น 5.0+ ให้ใช้ธีมนี้นะ

แน่นอนว่าต้องมีคนนึกถึง css media queries ในโลกของเว็บใช่มั้ยล่ะครับ แต่เจ้า configuration qualifier นี้ มันเทพกว่านั้นเยอะตรงที่มันไม่ได้เลือกได้แค่สไตล์ แต่มันยังสามารถเอาไปทำ responsive image ได้ สามารถแยกเทมเพลทของ app เวอร์ชั่น tablet ออกจากเวอร์ชั่น mobile ไปเลยก็ได้ แอบคิดเหมือนกันว่าถ้าเว็บมีกลไกแบบนี้บ้างก็คงจะดีไม่น้อยเลยล่ะครับ

ส่วนวิธีใช้ configuration qualifier นั้นก็ง่ายเอามากๆ ครับ เราก็แค่ต้องใส่ suffix เข้าไปต่อท้ายชื่อโฟลเดอร์ปกติของเราแค่นั้นเอง สมมติเราจะทำกับ res/layout ก็ให้เราสร้าง res/layout-sw600dp ขึ้นมาครับ แบบนี้ device ที่มีหน้าจอ 600dp ขึ้นไปก็จะมาอ่าน layout จากโฟลเดอร์นี้แทน หากเงื่อนไขไม่ตรง มันก็จะไปอ่านที่ res/layout ตามปกติ ในทำนองเดียวกัน หากเรากลัวว่าภาพจะแตกใน device ที่มีหน้าจอความคมชัดสูงๆ เราก็อาจเตรียมภาพที่ชัดเป็นพิเศษมา แล้วเอาไปใส่ไว้ในโฟลเดอร์ res/drawable-xhdpi หรือ res/drawable-xxhdpi ซึ่ง device หน้าจอความคมชัดสูงมากๆ จะเอาไปใช้ครับ

เพื่อให้เห็นภาพมากขึ้น เรามาดูตัวอย่างการเรียกใช้ resource แบบง่ายๆ กันดีกว่าครับ

จะเห็นว่าที่ src นั้น เราไม่ต้องไปกำหนด suffix ใดๆ ลงไปนะครับ ปล่อยให้กลไกของ configuration qualifier มันทำงานเองได้เลย

ทำ UI ให้มีชีวิตด้วย Java

จบแล้วครับ เรื่องราวเกี่ยวกับ ui แต่ตอนนี้มันก็เป็นเพียงแค่ไฟล์ static ธรรมดาที่ไม่มีชีวิตถูกมั้ยครับ หากเป็นเว็บก็เหมือนกับการเขียน html และ css เสร็จหมดแล้ว แต่ยังขาด business logic นั่นเอง ในหัวข้อนี้เราเลยจะมาพูดถึงการทำแอพให้มีชีวิตขึ้นมา ซึ่งภาษาที่จะใช้นั้นก็คือ Java นั่นเองครับ

รู้จักกับ Activity

activity คือ “หน้า” ของแอพครับ โดยหน้าที่ว่านี้ เราสามารถเลือกไฟล์ layout มาผูกกับมันได้ สมมติเราจะทำแอพอ่านข่าว เราก็อาจจะสร้างไว้ 2 activity เพื่อรองรับหน้ารวมข่าวอันนึง แล้วก็รองรับหน้าอ่านข่าวอีกอันนึง โดยแต่ละ activity นั้น เราก็จะผูกไว้กับ layout คนละตัวกันครับ (แหงล่ะ ไม่งั้นหน้าตามันก็เหมือนกันน่ะสิ !)

วิธีการผูก UI เข้ากับ Activity

เราลองมาดูโค้ดของการผูก layout เข้ากับ activity กันดีกว่าครับ สมมติ activity ของเรามีชื่อว่า MainActivity หากเราต้องการนำไฟล์ layout ที่มีชื่อว่า activity_main.xml มาผูกกับ activity ดังกล่าว เราก็จะต้องเขียนโค้ดแบบนี้

เราจะใช้ setContentView ในการผูก layout เข้ากับ activity ครับ โดยเราจะส่ง R.layout.activity_main เข้าไป ซึ่ง R ก็ไม่ใช่ใครที่ไหน มันคือ class ที่เก็บ resource ทั้งหมดของเรา ที่อยู่ในโฟลเดอร์ res นั่นเอง อย่างในกรณีนี้ มันก็คือการบอกให้ไปดูที่ไฟล์ activity_main.xml ที่อยู่ใน res/layout นั่นเองครับ

วิธีการเข้าถึง Element ต่างๆ

มาดูการเข้าถึง element ต่างๆ ที่อยู่ใน layout ที่เราผูกไว้กันบ้างครับ สมมติใน layout ของเรามี Button อยู่อันนึง หากเราอยากจะเข้าถึงมัน ก็ให้เราใส่ id ให้มันก่อนเลยครับ แบบนี้

จากนั้นมาดูที่ activity ของเราครับ เราจะสามารถเข้าถึง Button ดังกล่าวได้ผ่าน findViewById แบบนี้เลย

วิธีการใส่ Event Listener

ทีนี้เราจะมาลองใส่ event listener ให้กับ Button นี้กันครับ แต่ก่อนอื่น ให้เราสร้าง TextView ขึ้นมาตัวนึงก่อน แล้วใส่ข้อความอะไรก็ได้ลงไป พร้อมกับใส่ id ให้มัน

จากนั้น ให้เราลองดัก click event ที่ Button นี้ ด้วย setOnClickListener แบบนี้ครับ

หากลองไล่โค้ดดู ก็พอจะเดาได้ครับว่า เมื่อมีการกด Button นี้ ข้อความใน TextView ก็จะเปลี่ยนมาเป็น “SiamHTML” ครับ

เชื่อมแต่ละ Activity เข้าด้วยกันด้วย Intent

ในการทำแอพจริงๆ แล้ว เราคงไม่ได้ใช้เพียงแค่ activity เดียวหรอกครับ คำถามคือ แล้วเราจะสื่อสารกันระหว่าง activity ยังไง ? ใช้ link แบบเว็บหรือเปล่า ? คำตอบคือไม่

ในโลกของ Android นั้น แต่ละ activity จะไม่ได้คุยกันตรงๆ ครับ แต่จะสื่อสารผ่านสิ่งที่เรียกว่า Intent ซึ่งเป็น object ที่จะระบุ action ว่าต้องการให้ทำอะไร รวมไปถึง data ที่ action นั้นสามารถเอาไปใช้ได้

เพื่อให้เห็นภาพมากขึ้น ให้เราสร้าง MainActivity ขึ้นมา แล้วผูกกับ layout หน้าแรกของแอพไว้ จากนั้นก็สร้าง ContentActivity ขึ้นมาอีกอัน แล้วผูกกับ layout หน้าอ่านเนื้อหาไว้ เรามาลองทำ Button ที่พอกดแล้วจะเปลี่ยนไปอีกหน้านึงกันดูครับ เริ่มด้วยการใส่ click event listener ที่ Button ใน MainActivity ก่อนเลย จากนั้นก็ใส่โค้ดสำหรับสร้าง intent เข้าไปแบบนี้

จากโค้ดด้านบน intent จะถูกส่งไปยัง ContentActivity พร้อมกับ someValue ที่มีค่าเป็น “SiamHTML” ครับ ทีนี้เรามาดูทางฝั่ง ContentActivity กันบ้างครับ ให้เราลองเขียนโค้ดเพื่อรับค่าจาก intent มาใช้แบบนี้

เห็นมั้ยครับว่าเราสามารถส่งผ่านข้อมูลระหว่าง activity ได้ง่ายๆ แบบนี้เลย ในการทำแอพจริงๆ หากเป็นแอพคอนเทนต์ (เช่น SiamHTML) เราก็จะต้องมี api สำหรับดึงข้อมูลก่อนครับ จากนั้นเราก็อาจจะเขียนโค้ดสำหรับดึงเนื้อหาทั้งหมดมาแสดงเอาไว้ที่ MainActivity ส่วนใน ContentActivity เราก็จะเขียนโค้ดสำหรับแสดงเนื้อหาแบบเต็มๆ ของเนื้อหานั้นๆ ซึ่งข้อมูลที่เราจะส่งจาก MainActivity ไปยัง ContentActivity ก็อาจจะเป็น id หรือ slug ของเนื้อหา เพื่อที่จะเอาไป query ผ่าน api ได้นั่นเอง

เข้าใจหมดเลย แต่ไม่รู้จะเริ่มต้นยังไง ?

สาเหตุที่ผมเขียนบทความนี้ขึ้นมาก็เพื่อที่จะให้เพื่อนๆ เข้าใจภาพรวมในการเขียนแอพ Android ครับ ไม่ได้หวังว่าพออ่านจบแล้วจะทำได้เลย จากนี้ไป เพื่อนๆ ก็จะสามารถศึกษาเพิ่มเติมต่อได้ด้วยตัวเองแล้วล่ะครับ โดยผมแนะนำให้อ่านจากเว็บหลักได้เลย ส่วน IDE ที่ใช้เขียนโค้ดก็ขอแนะนำเป็น Android Studio ไปเลยครับ เพราะว่ามันเตรียมของที่เราจำเป็นต้องใช้มาให้หมดแล้ว ก็ลองเล่นกันดูนะครับ รับรองว่าการเขียนแอพ Android ไม่ยากอย่างที่คิด

(Visited 23,817 times, 5 visits today)

19 Responses to “เรียนรู้การเขียนแอพ Android สไตล์ Front-end Web Developer”

  1. บทความเลอค่ามากเลยครับ ทำให้คนเขียน web เข้าใจ android ได้ง่ายขึ้นมากๆ เป็นการสร้างมุมมองที่ดีมากเลยครับ

  2. เขียนอธิบายเข้าใจง่ายมากครับ ขอบคุณมากครับสำหรับการแบ่งปัน^^

  3. พื้นฐานครบครัน

  4. ไม่ได้เป็นเรื่องแปลกใหม่ ใครๆก็รู้ แต่ที่สุดยอดคือ "คุณอธิบายได้ดีและเข้าใจง่ายมาก" ผมซื้อหนังสือมาหลายเล่ม ยังอธิบายไม่ดี และอ่านง่ายเท่าคุณเลย ขอชื่นชมครับ

  5. ขอบคุณมากครับ

  6. อยากให้ทำเป็นบทความสอนการเขียนแอพอ่าครับ หรือจะทำเป็นหนังสือขายก็ได้ครับ ผมจะซื้อ เขียนบทความได้ดีมากๆ เข้าใจง่าย

  7. ขอบคุณสำหรับบทความครับ อ่านแล้ว ทำให้เพิ่มความเข้าใจในการเขียนโปรแกรมบน android ได้ดีขึ้น และง่ายขึ้นครับ

  8. ขอบคุณมากๆครับ // เริ่มต้นอ่านก็โดนใจ จนมาเจอประโยคปิดท้าย …เข้าใจหมดเลย แต่ไม่รู้จะเริ่มต้นยังไง? เล่นเอาซึ้งเข้าไปใหญ่ครับ 555+++

  9. บทความคุณภาพอีกแล้วครับท่าน
    เปรียบเทียบได้ดีมากครับ o/

  10. อ่านเพลินเลย

  11. กำลังเขียนอยู่พอดีครับ ขอบคุณครับ

  12. ดีมากครับ ขอบคุณครับ

  13. ขอบคุณคับ เข้าจมุมมอง ของ front end เลย

  14. ขอบคุณครับกลับมาอ่านทบทวนกันลืม

  15. ขอบคุณมากๆครับ

  16. สุดยอด ครับ เป็นบทความที่ดี มีคุณค่าต่อสายงานเวปจริงๆ ครับ อ่านแล้วเข้าใจเลย

  17. ขอบคุณครับ ชัดเจน แจ่มแจ้ง

Leave a Reply