เคล็ดลับและเครื่องมือในการเพิ่มประสิทธิภาพแอป Android

เผยแพร่แล้ว: 2022-03-11

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

มาดูตัวเลขบางส่วนก่อนเพื่อพิจารณาว่าการเพิ่มประสิทธิภาพนั้นสำคัญไฉน ตามโพสต์ Nimbledroid 86% ของผู้ใช้ (รวมถึงฉัน) ได้ถอนการติดตั้งแอพหลังจากใช้งานเพียงครั้งเดียวเนื่องจากประสิทธิภาพต่ำ หากคุณกำลังโหลดเนื้อหา คุณมีเวลาน้อยกว่า 11 วินาทีที่จะแสดงให้ผู้ใช้เห็น ผู้ใช้คนที่สามเท่านั้นที่จะให้เวลาคุณมากขึ้น คุณอาจได้รับรีวิวแย่ๆ มากมายบน Google Play เพราะมัน

สร้างแอปที่ดีขึ้น: รูปแบบประสิทธิภาพของ Android

การทดสอบความอดทนของผู้ใช้เป็นทางลัดในการถอนการติดตั้ง
ทวีต

สิ่งแรกที่ผู้ใช้สังเกตเห็นซ้ำแล้วซ้ำเล่าคือเวลาเริ่มต้นของแอป ตามโพสต์อื่นของ Nimbledroid จาก 100 แอพยอดนิยม 40 แอพเริ่มภายใน 2 วินาทีและ 70 แอพเริ่มภายใน 3 วินาที ดังนั้น หากเป็นไปได้ โดยทั่วไปคุณควรแสดงเนื้อหาบางส่วนโดยเร็วที่สุด และชะลอการตรวจสอบพื้นหลังและอัปเดตเล็กน้อย

โปรดจำไว้เสมอว่า การเพิ่มประสิทธิภาพก่อนเวลาอันควรเป็นรากเหง้าของความชั่วร้ายทั้งหมด คุณไม่ควรเสียเวลามากเกินไปกับการเพิ่มประสิทธิภาพไมโคร คุณจะเห็นประโยชน์สูงสุดจากการเพิ่มประสิทธิภาพโค้ดที่ทำงานบ่อย ตัวอย่างเช่น ฟังก์ชันนี้รวมถึง onDraw() ซึ่งรันทุกเฟรม โดยควรเป็น 60 ครั้งต่อวินาที การวาดเป็นการดำเนินการที่ช้าที่สุด ดังนั้นให้ลองวาดใหม่เฉพาะสิ่งที่คุณต้องทำ ข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้จะมาในภายหลัง

เคล็ดลับประสิทธิภาพ

ตามทฤษฎีแล้ว ต่อไปนี้คือรายการสิ่งที่คุณควรพิจารณาหากประสิทธิภาพมีความสำคัญต่อคุณ

1. สตริงกับ StringBuilder

สมมติว่าคุณมีสตริง และด้วยเหตุผลบางอย่างที่คุณต้องการผนวกสตริงเพิ่มเติมเข้าไป 10,000 ครั้ง รหัสอาจมีลักษณะเช่นนี้

 String string = "hello"; for (int i = 0; i < 10000; i++) { string += " world"; }

คุณสามารถดูได้จาก Android Studio Monitors ว่าการต่อสตริงบางรายการไม่มีประสิทธิภาพเพียงใด มีขยะสะสม (GC) เกิดขึ้นมากมาย

String vs StringBuilder

การดำเนินการนี้ใช้เวลาประมาณ 8 วินาทีในอุปกรณ์ที่ค่อนข้างดีของฉันซึ่งมี Android 5.1.1 วิธีที่มีประสิทธิภาพมากขึ้นในการบรรลุเป้าหมายเดียวกันคือการใช้ StringBuilder เช่นนี้

 StringBuilder sb = new StringBuilder("hello"); for (int i = 0; i < 10000; i++) { sb.append(" world"); } String string = sb.toString();

บนอุปกรณ์เดียวกัน สิ่งนี้จะเกิดขึ้นเกือบจะในทันที ในเวลาน้อยกว่า 5 มิลลิวินาที การแสดงภาพ CPU และหน่วยความจำเกือบจะแบนราบทั้งหมด ดังนั้นคุณสามารถจินตนาการได้ว่าการปรับปรุงนี้จะใหญ่ขนาดไหน สังเกตว่า เพื่อให้บรรลุความแตกต่างนี้ เราต้องผนวก 10,000 สตริง ซึ่งคุณอาจไม่ได้ทำบ่อย ดังนั้น ในกรณีที่คุณเพิ่มสตริงสองสามสตริงเพียงครั้งเดียว คุณจะไม่เห็นการปรับปรุงใดๆ อย่างไรก็ตาม ถ้าคุณทำ:

 String string = "hello" + " world";

มันได้รับการแปลงภายในเป็น StringBuilder ดังนั้นมันจะทำงานได้ดี

คุณอาจสงสัยว่าเหตุใดการต่อสตริงจึงช้าในตอนแรก เกิดจากข้อเท็จจริงที่ว่า Strings นั้นไม่เปลี่ยนรูป ดังนั้นเมื่อสร้างแล้วจะไม่สามารถเปลี่ยนแปลงได้ แม้ว่าคุณคิดว่าคุณกำลังเปลี่ยนค่าของสตริง คุณกำลังสร้างสตริงใหม่ด้วยค่าใหม่ ในตัวอย่างเช่น:

 String myString = "hello"; myString += " world";

สิ่งที่คุณจะได้รับในความทรงจำไม่ใช่ 1 สตริง "สวัสดีชาวโลก" แต่จริงๆ แล้วเป็น 2 สตริง สตริง myString จะมีคำว่า "สวัสดีชาวโลก" อย่างที่คุณคาดไว้ อย่างไรก็ตาม String เดิมที่มีค่า "hello" ยังมีชีวิตอยู่โดยไม่มีการอ้างอิงใด ๆ เพื่อรอการเก็บขยะ นี่เป็นเหตุผลที่คุณควรเก็บรหัสผ่านไว้ในอาร์เรย์ถ่านแทนที่จะเป็นสตริง หากคุณเก็บรหัสผ่านเป็นสตริง รหัสผ่านจะอยู่ในหน่วยความจำในรูปแบบที่มนุษย์อ่านได้จนถึง GC ถัดไปเป็นระยะเวลาที่คาดเดาไม่ได้ กลับไปที่ความไม่เปลี่ยนรูปที่อธิบายข้างต้น สตริงจะยังคงอยู่ในหน่วยความจำ แม้ว่าคุณจะกำหนดค่าอื่นให้หลังจากใช้งานแล้วก็ตาม อย่างไรก็ตาม หากคุณล้างอาร์เรย์ char หลังจากใช้รหัสผ่าน รหัสผ่านจะหายไปจากทุกที่

2. การเลือกประเภทข้อมูลที่ถูกต้อง

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

แล้วกรณีที่คุณต้องการคอลเลกชันที่มีวัตถุที่ไม่ซ้ำกันล่ะ? คุณควรเลือก Set โดยจะต้องไม่ซ้ำกันตามการออกแบบ ดังนั้นคุณจึงไม่ต้องดูแลเอง มีชุดหลายประเภท ดังนั้นให้เลือกชุดที่เหมาะกับกรณีการใช้งานของคุณ สำหรับกลุ่มไอเท็มที่ไม่ซ้ำง่ายๆ คุณสามารถใช้ HashSet หากคุณต้องการรักษาลำดับของรายการที่แทรกไว้ ให้เลือก LinkedHashSet TreeSet จะจัดเรียงรายการโดยอัตโนมัติ ดังนั้นคุณจึงไม่ต้องเรียกใช้วิธีการจัดเรียงใดๆ นอกจากนี้ยังควรจัดเรียงรายการอย่างมีประสิทธิภาพโดยที่คุณไม่ต้องนึกถึงอัลกอริทึมการจัดเรียง

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

การเรียงลำดับจำนวนเต็มหรือสตริงค่อนข้างตรงไปตรงมา อย่างไรก็ตาม ถ้าคุณต้องการจัดเรียงคลาสตามคุณสมบัติบางอย่างล่ะ สมมติว่าคุณกำลังเขียนรายการอาหารที่คุณกิน และเก็บชื่อและการประทับเวลาของอาหารเหล่านั้น คุณจะจัดเรียงอาหารตามการประทับเวลาจากต่ำสุดไปสูงสุดอย่างไร โชคดีที่มันค่อนข้างง่าย การใช้งานอินเทอร์เฟซ Comparable ในคลาส Meal และแทนที่ฟังก์ชัน compareTo() ก็เพียงพอแล้ว ในการจัดเรียงอาหารตามการประทับเวลาจากต่ำสุดไปสูงสุด เราสามารถเขียนสิ่งนี้ได้

 @Override public int compareTo(Object object) { Meal meal = (Meal) object; if (this.timestamp < meal.getTimestamp()) { return -1; } else if (this.timestamp > meal.getTimestamp()) { return 1; } return 0; }

3. การอัปเดตตำแหน่ง

มีแอพมากมายที่รวบรวมตำแหน่งของผู้ใช้ คุณควรใช้ Google Location Services API เพื่อจุดประสงค์ดังกล่าว ซึ่งมีฟังก์ชันที่มีประโยชน์มากมาย มีบทความแยกต่างหากเกี่ยวกับการใช้งานดังนั้นฉันจะไม่ทำซ้ำ

ฉันแค่ต้องการเน้นประเด็นสำคัญบางประเด็นจากมุมมองของประสิทธิภาพ

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

คุณยังสามารถใช้ฟังก์ชันของ LocationRequest เรียกว่า setSmallestDisplacement() การตั้งค่านี้เป็นเมตรจะทำให้แอปของคุณไม่ได้รับการแจ้งเตือนเกี่ยวกับการเปลี่ยนแปลงตำแหน่งหากแอปมีขนาดเล็กกว่าค่าที่กำหนด ตัวอย่างเช่น หากคุณมีแผนที่ที่มีร้านอาหารใกล้เคียงอยู่รอบตัวคุณ และคุณตั้งค่าระยะห่างที่เล็กที่สุดไว้ที่ 20 เมตร แอปจะไม่ส่งคำขอให้ตรวจสอบร้านอาหารหากผู้ใช้เพียงแค่เดินไปมาในห้อง คำขอจะไร้ประโยชน์ เนื่องจากจะไม่มีร้านอาหารใหม่ๆ ในบริเวณใกล้เคียงอยู่แล้ว

กฎข้อที่สองคือการขออัปเดตตำแหน่งบ่อยเท่าที่คุณต้องการเท่านั้น นี้ค่อนข้างอธิบายตนเอง หากคุณกำลังสร้างแอปพยากรณ์อากาศจริงๆ คุณไม่จำเป็นต้องขอตำแหน่งทุกๆ สองสามวินาที เนื่องจากคุณอาจไม่มีการคาดการณ์ที่แม่นยำเช่นนี้ (โปรดติดต่อฉันหากคุณมี) คุณสามารถใช้ฟังก์ชัน setInterval() เพื่อตั้งค่าช่วงเวลาที่ต้องการซึ่งอุปกรณ์จะอัปเดตแอปของคุณเกี่ยวกับตำแหน่ง หากหลายแอปร้องขอตำแหน่งของผู้ใช้ ทุกแอปจะได้รับแจ้งทุกครั้งที่อัปเดตตำแหน่งใหม่ แม้ว่าคุณจะตั้งค่า setInterval() ที่สูงกว่าก็ตาม เพื่อป้องกันไม่ให้แอปของคุณได้รับการแจ้งเตือนบ่อยเกินไป ตรวจสอบให้แน่ใจว่าได้ตั้งค่าช่วงเวลาการอัปเดตที่เร็วที่สุดด้วย setFastestInterval() เสมอ

และสุดท้าย กฎข้อที่สามคือการขออัปเดตตำแหน่งก็ต่อเมื่อคุณต้องการเท่านั้น หากคุณกำลังแสดงวัตถุใกล้เคียงบนแผนที่ทุก ๆ x วินาที และแอปทำงานในพื้นหลัง คุณไม่จำเป็นต้องทราบตำแหน่งใหม่ ไม่มีเหตุผลที่จะต้องอัปเดตแผนที่หากผู้ใช้มองไม่เห็นอยู่ดี ตรวจสอบให้แน่ใจว่าได้หยุดฟังการอัปเดตตำแหน่งตามความเหมาะสม โดยเฉพาะอย่างยิ่งใน onPause() จากนั้นคุณสามารถดำเนินการอัปเดตต่อใน onResume()

4. คำขอเครือข่าย

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

อันที่สองคือแบตเตอรี่ ทั้ง WiFi และเครือข่ายมือถือสามารถกินได้ค่อนข้างมากหากใช้มากเกินไป สมมติว่าคุณต้องการดาวน์โหลด 1 kb หากต้องการขอเครือข่าย คุณต้องปลุกสัญญาณมือถือหรือวิทยุ WiFi จากนั้นจึงดาวน์โหลดข้อมูลได้ อย่างไรก็ตาม วิทยุจะไม่หลับทันทีหลังการผ่าตัด มันจะอยู่ในสถานะใช้งานค่อนข้างนานประมาณ 20-40 วินาที ขึ้นอยู่กับอุปกรณ์และผู้ให้บริการของคุณ

คำขอเครือข่าย

ดังนั้นคุณสามารถทำอะไรกับมันได้บ้าง? แบทช์ เพื่อหลีกเลี่ยงไม่ให้วิทยุปลุกทุกสองสามวินาที ให้ดึงข้อมูลล่วงหน้าที่ผู้ใช้อาจต้องการในนาทีต่อๆ ไป วิธีการแบทช์ที่เหมาะสมนั้นจะมีไดนามิกสูงขึ้นอยู่กับแอปของคุณ แต่ถ้าเป็นไปได้ คุณควรดาวน์โหลดข้อมูลที่ผู้ใช้อาจต้องการในอีก 3-4 นาทีข้างหน้า ผู้ใช้ยังสามารถแก้ไขพารามิเตอร์แบตช์ตามประเภทอินเทอร์เน็ตของผู้ใช้หรือสถานะการชาร์จ ตัวอย่างเช่น หากผู้ใช้ใช้ WiFi ขณะชาร์จ คุณสามารถดึงข้อมูลล่วงหน้าได้มากกว่าหากผู้ใช้ใช้อินเทอร์เน็ตบนมือถือที่มีแบตเตอรี่เหลือน้อย การพิจารณาตัวแปรเหล่านี้อาจเป็นเรื่องยาก ซึ่งมีเพียงไม่กี่คนที่จะทำ โชคดีที่มี GCM Network Manager คอยช่วยเหลือ!

GCM Network Manager เป็นคลาสที่มีประโยชน์จริงๆ พร้อมด้วยแอตทริบิวต์ที่ปรับแต่งได้มากมาย คุณสามารถกำหนดเวลาทั้งงานที่ทำซ้ำและครั้งเดียวได้อย่างง่ายดาย ในการทำงานซ้ำ คุณสามารถตั้งค่าช่วงต่ำสุดและช่วงการทำซ้ำสูงสุดได้ วิธีนี้จะช่วยให้จัดกลุ่มได้ไม่เพียงแค่คำขอของคุณเท่านั้น แต่ยังรวมถึงคำขอจากแอปอื่นๆ ด้วย ต้องปลุกวิทยุเพียงครั้งเดียวในช่วงเวลาหนึ่ง และในขณะที่ยังไม่เปิด แอปทั้งหมดในคิวจะดาวน์โหลดและอัปโหลดสิ่งที่พวกเขาควรจะทำ ตัวจัดการนี้ยังรับรู้ถึงประเภทเครือข่ายของอุปกรณ์และสถานะการชาร์จ ดังนั้นคุณจึงสามารถปรับเปลี่ยนได้ตามนั้น คุณสามารถดูรายละเอียดและตัวอย่างเพิ่มเติมได้ในบทความนี้ เราขอแนะนำให้คุณลองดู งานตัวอย่างมีลักษณะดังนี้:

 Task task = new OneoffTask.Builder() .setService(CustomService.class) .setExecutionWindow(0, 30) .setTag(LogService.TAG_TASK_ONEOFF_LOG) .setUpdateCurrent(false) .setRequiredNetwork(Task.NETWORK_STATE_CONNECTED) .setRequiresCharging(false) .build();

อย่างไรก็ตาม ตั้งแต่ Android 3.0 หากคุณทำการร้องขอเครือข่ายบนเธรดหลัก คุณจะได้รับ NetworkOnMainThreadException นั่นจะเตือนคุณอย่างแน่นอนว่าอย่าทำอย่างนั้นอีก

5. การสะท้อนกลับ

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

6. ออโต้บ็อกซ์

การทำ Autoboxing และ Unboxing เป็นกระบวนการในการแปลงประเภทดั้งเดิมเป็นประเภท Object หรือในทางกลับกัน ในทางปฏิบัติหมายถึงการแปลง int เป็นจำนวนเต็ม เพื่อให้บรรลุสิ่งนั้น คอมไพเลอร์ใช้ฟังก์ชัน Integer.valueOf() ภายใน การแปลงไม่ได้ช้าเพียงเท่านั้น Objects ยังใช้หน่วยความจำมากกว่าหน่วยความจำที่เทียบเท่าดั้งเดิมอีกด้วย มาดูโค้ดกันบ้าง

 Integer total = 0; for (int i = 0; i < 1000000; i++) { total += i; }

แม้ว่าจะใช้เวลาประมาณ 500ms โดยเฉลี่ย การเขียนใหม่เพื่อหลีกเลี่ยงการ autoboxing จะทำให้การทำงานเร็วขึ้นอย่างมาก

 int total = 0; for (int i = 0; i < 1000000; i++) { total += i; }

โซลูชันนี้ทำงานที่เวลาประมาณ 2 มิลลิวินาที ซึ่งเร็วกว่า 25 เท่า ถ้าไม่เชื่อก็ลองดู ตัวเลขจะต่างกันอย่างเห็นได้ชัดในแต่ละอุปกรณ์ แต่ก็ยังน่าจะเร็วกว่ามาก และยังเป็นขั้นตอนง่ายๆ ในการเพิ่มประสิทธิภาพอีกด้วย

โอเค คุณคงไม่ได้สร้างตัวแปรประเภท Integer แบบนี้บ่อยๆ แต่แล้วกรณีที่หลีกเลี่ยงได้ยากขึ้นล่ะ? เช่นเดียวกับในแผนที่ที่คุณต้องใช้ Objects เช่น Map<Integer, Integer> ? ดูวิธีแก้ปัญหาที่หลายคนใช้

 Map<Integer, Integer> myMap = new HashMap<>(); for (int i = 0; i < 100000; i++) { myMap.put(i, random.nextInt()); }

การแทรก 100k ints สุ่มในแผนที่จะใช้เวลาประมาณ 250 มิลลิวินาทีในการรัน ตอนนี้ดูวิธีแก้ปัญหาด้วย SparseIntArray

 SparseIntArray myArray = new SparseIntArray(); for (int i = 0; i < 100000; i++) { myArray.put(i, random.nextInt()); }

ใช้เวลาน้อยกว่ามาก ประมาณ 50ms นอกจากนี้ยังเป็นหนึ่งในวิธีที่ง่ายกว่าในการปรับปรุงประสิทธิภาพ เนื่องจากไม่ต้องทำอะไรซับซ้อน และโค้ดก็ยังสามารถอ่านได้ ในขณะที่ใช้งานแอพที่ชัดเจนด้วยวิธีแก้ปัญหาแรกใช้หน่วยความจำของฉัน 13MB การใช้ int ดั้งเดิมนั้นใช้บางอย่างที่ต่ำกว่า 7MB ดังนั้นเพียงครึ่งเดียวเท่านั้น

SparseIntArray เป็นเพียงหนึ่งในคอลเล็กชันสุดเจ๋งที่สามารถช่วยคุณหลีกเลี่ยงการทำ autoboxing ได้ แผนที่เช่น Map<Integer, Long> สามารถแทนที่ด้วย SparseLongArray เนื่องจากค่าของแผนที่เป็นประเภท Long หากคุณดูซอร์สโค้ดของ SparseLongArray คุณจะเห็นสิ่งที่น่าสนใจทีเดียว ภายใต้ประทุนนั้นโดยพื้นฐานแล้วเป็นเพียงอาร์เรย์คู่หนึ่ง คุณยังสามารถใช้ SparseBooleanArray ได้เช่นเดียวกัน

หากคุณอ่านซอร์สโค้ด คุณอาจสังเกตเห็นข้อความแจ้งว่า SparseIntArray อาจช้ากว่า HashMap ฉันได้ทดลองมามากแล้ว แต่สำหรับฉัน SparseIntArray นั้นดีกว่าเสมอทั้งในด้านหน่วยความจำและประสิทธิภาพ ฉันเดาว่ามันยังคงขึ้นอยู่กับคุณว่าจะเลือกแบบไหน ทดลองกับกรณีการใช้งานของคุณและดูว่าแบบใดที่เหมาะกับคุณที่สุด มี SparseArrays อยู่ในหัวของคุณอย่างแน่นอนเมื่อใช้แผนที่

7. OnDraw

ดังที่ฉันได้กล่าวไว้ข้างต้น เมื่อคุณทำการเพิ่มประสิทธิภาพ คุณอาจเห็นประโยชน์สูงสุดในการเพิ่มประสิทธิภาพโค้ดซึ่งทำงานบ่อย หนึ่งในฟังก์ชั่นที่ใช้งานบ่อยคือ onDraw() อาจไม่แปลกใจเลยที่รับผิดชอบในการวาดมุมมองบนหน้าจอ เนื่องจากอุปกรณ์มักจะทำงานที่ 60 fps ฟังก์ชันจึงทำงาน 60 ครั้งต่อวินาที ทุกเฟรมมีเวลา 16 ms ให้จัดการอย่างเต็มที่ รวมถึงการจัดเตรียมและการวาดภาพ ดังนั้นคุณควรหลีกเลี่ยงฟังก์ชันที่ช้าจริงๆ เฉพาะเธรดหลักเท่านั้นที่สามารถวาดบนหน้าจอได้ ดังนั้นคุณควรหลีกเลี่ยงการดำเนินการที่มีราคาแพงกับมัน หากคุณตรึงเธรดหลักไว้หลายวินาที คุณอาจได้รับกล่องโต้ตอบ Application Not Responding (ANR) ที่น่าอับอาย สำหรับการปรับขนาดรูปภาพ งานฐานข้อมูล ฯลฯ ให้ใช้เธรดพื้นหลัง

หากคุณคิดว่าผู้ใช้ของคุณไม่สังเกตเห็นว่าอัตราเฟรมลดลง คุณคิดผิด!
ทวีต

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

สิ่งหนึ่งที่คุณควรหลีกเลี่ยงใน onDraw() คือการจัดสรรวัตถุเช่น Paint เตรียมทุกอย่างในตัวสร้างเพื่อให้พร้อมเมื่อวาด แม้ว่าคุณจะปรับให้เหมาะสม onDraw() แล้ว คุณควรเรียกมันบ่อยเท่าที่จำเป็นเท่านั้น อะไรจะดีไปกว่าการเรียกใช้ฟังก์ชันที่ปรับให้เหมาะสมที่สุด? ดีแล้วที่ไม่เรียกใช้ฟังก์ชันใดๆ เลย ในกรณีที่คุณต้องการวาดข้อความ มีฟังก์ชันตัวช่วยที่เรียกว่า drawText() ซึ่งคุณสามารถระบุสิ่งต่างๆ เช่น ข้อความ พิกัด และสีข้อความได้

8. ViewHolders

คุณคงรู้จักสิ่งนี้ แต่ฉันข้ามมันไม่ได้ รูปแบบการออกแบบ Viewholder เป็นวิธีการทำให้รายการเลื่อนดูราบรื่นขึ้น เป็นการแคชมุมมองชนิดหนึ่ง ซึ่งสามารถลดการโทรไปยัง findViewById() ได้อย่างจริงจัง และเพิ่มมุมมองโดยการจัดเก็บไว้ มันสามารถมีลักษณะเช่นนี้

 static class ViewHolder { TextView title; TextView text; public ViewHolder(View view) { title = (TextView) view.findViewById(R.id.title); text = (TextView) view.findViewById(R.id.text); } }

จากนั้น ภายในฟังก์ชัน getView() ของอแด็ปเตอร์ คุณสามารถตรวจสอบว่าคุณมีมุมมองที่ใช้งานได้หรือไม่ ถ้าไม่ คุณสร้างมันขึ้นมา

 ViewHolder viewHolder; if (convertView == null) { convertView = inflater.inflate(R.layout.list_item, viewGroup, false); viewHolder = new ViewHolder(convertView); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.title.setText("Hello World");

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

9. การปรับขนาดรูปภาพ

เป็นไปได้มากที่แอปของคุณจะมีรูปภาพบางส่วน ในกรณีที่คุณดาวน์โหลด JPG บางไฟล์จากเว็บ ไฟล์เหล่านี้อาจมีความละเอียดที่มหาศาล อย่างไรก็ตาม อุปกรณ์ที่จะแสดงจะมีขนาดเล็กกว่ามาก แม้ว่าคุณจะถ่ายภาพด้วยกล้องของอุปกรณ์ คุณจะต้องลดขนาดภาพก่อนที่จะแสดง เนื่องจากความละเอียดของภาพถ่ายนั้นใหญ่กว่าความละเอียดของจอแสดงผลอย่างมาก การปรับขนาดรูปภาพก่อนแสดงเป็นสิ่งสำคัญ หากคุณจะลองแสดงผลแบบเต็มความละเอียด คุณจะมีหน่วยความจำไม่เพียงพออย่างรวดเร็ว มีการเขียนมากมายเกี่ยวกับการแสดงบิตแมปอย่างมีประสิทธิภาพในเอกสาร Android ฉันจะลองสรุป

คุณมีบิตแมป แต่คุณไม่รู้อะไรเลย บริการของคุณมีแฟล็กบิตแมปที่มีประโยชน์ซึ่งเรียกว่า inJustDecodeBounds ซึ่งช่วยให้คุณสามารถค้นหาความละเอียดของบิตแมปได้ สมมติว่าบิตแมปของคุณคือ 1024x768 และ ImageView ที่ใช้สำหรับแสดงเป็นเพียง 400x300 คุณควรหารความละเอียดของบิตแมปด้วย 2 ต่อไปจนกว่าจะยังใหญ่กว่า ImageView ที่กำหนด หากคุณทำเช่นนั้น มันจะลดขนาดบิตแมปลงเป็น 2 เท่า ทำให้คุณได้บิตแมปขนาด 512x384 บิตแมปที่ลดขนาดตัวอย่างใช้หน่วยความจำน้อยลง 4 เท่า ซึ่งจะช่วยคุณได้มากในการหลีกเลี่ยงข้อผิดพลาด OutOfMemory ที่มีชื่อเสียง

เมื่อรู้วิธีแล้ว ก็ไม่ควรทำ … อย่างน้อย ก็ไม่ใช่ว่าแอปของคุณต้องอาศัยรูปภาพจำนวนมาก และไม่ใช่แค่ 1-2 รูปภาพเท่านั้น หลีกเลี่ยงสิ่งต่าง ๆ เช่นการปรับขนาดและรีไซเคิลรูปภาพด้วยตนเองอย่างแน่นอน ใช้ไลบรารีของบุคคลที่สามสำหรับสิ่งนั้น ภาพที่ได้รับความนิยมมากที่สุด ได้แก่ Picasso by Square, Universal Image Loader, Fresco by Facebook หรือ Glide ที่ฉันชอบ มีชุมชนนักพัฒนาจำนวนมากอยู่รอบๆ ตัว คุณจึงสามารถพบผู้คนที่เป็นประโยชน์มากมายในส่วนปัญหาบน GitHub เช่นกัน

10. โหมดเข้มงวด

Strict Mode เป็นเครื่องมือสำหรับนักพัฒนาที่มีประโยชน์มากซึ่งหลายคนไม่รู้จัก มักใช้สำหรับตรวจจับคำขอเครือข่ายหรือการเข้าถึงดิสก์จากเธรดหลัก คุณสามารถตั้งค่าว่าโหมดเข้มงวดควรมองหาปัญหาใดและควรให้โทษใด ตัวอย่าง google มีลักษณะดังนี้:

 public void onCreate() { if (DEVELOPER_MODE) { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads() .detectDiskWrites() .detectNetwork() .penaltyLog() .build()); StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() .detectLeakedSqlLiteObjects() .detectLeakedClosableObjects() .penaltyLog() .penaltyDeath() .build()); } super.onCreate(); }

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

ประสิทธิภาพการดีบัก: The Pro Way

ตอนนี้เรามาดูเครื่องมือบางอย่างที่สามารถช่วยคุณค้นหาปัญหาคอขวด หรืออย่างน้อยก็แสดงว่ามีบางอย่างผิดปกติ

1. Android Monitor

นี่คือเครื่องมือที่สร้างขึ้นใน Android Studio ตามค่าเริ่มต้น คุณจะพบ Android Monitor ที่มุมล่างซ้าย และคุณสามารถสลับไปมาระหว่าง 2 แท็บได้ที่นั่น Logcat และจอภาพ ส่วนจอภาพประกอบด้วย 4 กราฟที่แตกต่างกัน เครือข่าย CPU GPU และหน่วยความจำ พวกมันอธิบายตัวเองได้ค่อนข้างดี ดังนั้นฉันจะรีบดำเนินการ นี่คือภาพหน้าจอของกราฟที่ถ่ายขณะแยกวิเคราะห์ JSON บางส่วนเมื่อดาวน์โหลด

จอภาพ Android

ส่วนเครือข่ายแสดงการรับส่งข้อมูลขาเข้าและขาออกเป็น KB/s ส่วน CPU แสดงการใช้งาน CPU เป็นเปอร์เซ็นต์ จอภาพ GPU จะแสดงระยะเวลาที่ใช้ในการแสดงเฟรมของหน้าต่าง UI นี่คือมอนิเตอร์ที่มีรายละเอียดมากที่สุดใน 4 ตัวนี้ ดังนั้นหากคุณต้องการรายละเอียดเพิ่มเติม โปรดอ่านสิ่งนี้

สุดท้ายเรามีตัวตรวจสอบหน่วยความจำซึ่งคุณอาจจะใช้มากที่สุด โดยค่าเริ่มต้นจะแสดงจำนวนหน่วยความจำว่างและหน่วยความจำที่จัดสรรในปัจจุบัน คุณสามารถบังคับ Garbage Collection ด้วยเพื่อทดสอบว่าจำนวนหน่วยความจำที่ใช้ลดลงหรือไม่ มีคุณสมบัติที่มีประโยชน์ที่เรียกว่า Dump Java Heap ซึ่งจะสร้างไฟล์ HPROF ซึ่งสามารถเปิดได้ด้วย HPROF Viewer and Analyzer ที่จะช่วยให้คุณเห็นจำนวนอ็อบเจ็กต์ที่คุณจัดสรร จำนวนหน่วยความจำที่ถูกใช้ไป และบางทีอ็อบเจกต์ใดที่ทำให้หน่วยความจำรั่ว การเรียนรู้วิธีใช้เครื่องวิเคราะห์นี้ไม่ใช่งานที่ง่ายที่สุด แต่ก็คุ้มค่า สิ่งต่อไปที่คุณสามารถทำได้ด้วยตัวตรวจสอบหน่วยความจำคือทำการติดตามการจัดสรรตามกำหนดเวลา ซึ่งคุณสามารถเริ่มและหยุดได้ตามที่คุณต้องการ อาจมีประโยชน์ในหลายกรณี เช่น เมื่อเลื่อนหรือหมุนอุปกรณ์

2. GPU Overdraw

นี่เป็นเครื่องมือช่วยเหลือง่ายๆ ซึ่งคุณสามารถเปิดใช้งานได้ในตัวเลือกสำหรับนักพัฒนาซอฟต์แวร์ เมื่อคุณเปิดใช้งานโหมดนักพัฒนาซอฟต์แวร์แล้ว เลือก Debug GPU overdraw, “แสดงพื้นที่ overdraw” และหน้าจอของคุณจะมีสีแปลก ๆ ไม่เป็นไร นั่นคือสิ่งที่ควรจะเกิดขึ้น สีหมายถึงจำนวนครั้งที่มีการวาดพื้นที่เฉพาะ สีที่แท้จริงหมายความว่าไม่มีการทับซ้อน นี่คือสิ่งที่คุณควรตั้งเป้าไว้ สีน้ำเงินหมายถึงการถอนหนึ่งครั้ง สีเขียวหมายถึงสอง สีชมพูสาม สีแดงสี่

GPU Overdraw

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

3. การแสดงผล GPU

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

การแสดงผล GPU

แถบสีประกอบด้วย 3-4 สี และตามเอกสารของ Android ขนาดของแถบนั้นมีความสำคัญจริงๆ ยิ่งเล็กยิ่งดี ที่ด้านล่าง คุณมีสีน้ำเงิน ซึ่งหมายถึงเวลาที่ใช้ในการสร้างและอัปเดตรายการที่แสดงของ View หากส่วนนี้สูงเกินไป แสดงว่ามีการวาดมุมมองแบบกำหนดเองจำนวนมาก หรือมีงานทำมากมายใน onDraw() หากคุณมี Android 4.0+ คุณจะเห็นแถบสีม่วงเหนือแถบสีน้ำเงิน นี่แสดงถึงเวลาที่ใช้ในการถ่ายโอนทรัพยากรไปยังเธรดการแสดงผล จากนั้นส่วนสีแดงก็มาถึง ซึ่งแสดงถึงเวลาที่ใช้โดยตัวแสดงภาพ 2D ของ Android ที่ออกคำสั่งไปยัง OpenGL เพื่อวาดและวาดรายการที่แสดงใหม่ ที่ด้านบนสุดคือแถบสีส้ม ซึ่งแสดงถึงเวลาที่ CPU กำลังรอให้ GPU ทำงานจนเสร็จ หากสูงเกินไป แสดงว่าแอปทำงานบน GPU มากเกินไป

ถ้าคุณเก่งพอ มีอีกสีหนึ่งที่อยู่เหนือสีส้ม เป็นเส้นสีเขียวแสดงถึงขีดจำกัด 16 ms เนื่องจากเป้าหมายของคุณควรจะเรียกใช้แอปของคุณที่ 60 fps คุณจึงมีเวลา 16 ms ในการวาดทุกเฟรม หากคุณไม่ดำเนินการ ระบบอาจข้ามบางเฟรม แอปอาจกระตุก และผู้ใช้จะสังเกตเห็นได้อย่างแน่นอน ให้ความสนใจเป็นพิเศษกับแอนิเมชั่นและการเลื่อน นั่นคือจุดที่ความราบรื่นสำคัญที่สุด แม้ว่าคุณจะตรวจจับเฟรมที่ข้ามได้ด้วยเครื่องมือนี้ แต่ก็ไม่ได้ช่วยให้คุณทราบได้ว่าปัญหาอยู่ที่ไหนจริงๆ

4. โปรแกรมดูลำดับชั้น

นี่เป็นหนึ่งในเครื่องมือที่ฉันโปรดปรานที่สุด เพราะมันทรงพลังจริงๆ คุณสามารถเริ่มต้นจาก Android Studio ผ่านเครื่องมือ -> Android -> การตรวจสอบอุปกรณ์ Android หรืออยู่ในโฟลเดอร์ sdk/tools ของคุณในฐานะ "จอภาพ" คุณยังสามารถค้นหาไฟล์เรียกทำงาน hierarachyviewer แบบสแตนด์อโลนได้ที่นั่น แต่เนื่องจากเลิกใช้แล้ว คุณควรเปิดจอภาพ อย่างไรก็ตาม คุณเปิด Android Device Monitor ให้เปลี่ยนไปใช้มุมมองของ Hierarchy Viewer หากคุณไม่เห็นแอปที่ทำงานอยู่ซึ่งกำหนดให้กับอุปกรณ์ของคุณ มีสองสิ่งที่คุณสามารถแก้ไขได้ ลองตรวจสอบกระทู้นี้ด้วย มีคนมีปัญหาทุกประเภทและวิธีแก้ไขทุกประเภท บางอย่างก็ควรได้ผลสำหรับคุณเช่นกัน

ด้วย Hierarchy Viewer คุณจะได้รับภาพรวมที่ดีของลำดับชั้นการดูของคุณ (อย่างเห็นได้ชัด) หากคุณเห็นทุกเลย์เอาต์ใน XML แยกกัน คุณอาจมองเห็นมุมมองที่ไร้ประโยชน์ได้ง่าย อย่างไรก็ตาม หากคุณยังคงรวมเลย์เอาต์เข้าด้วยกัน อาจทำให้สับสนได้ง่าย เครื่องมือเช่นนี้ทำให้มองเห็นได้ง่าย เช่น RelativeLayout บางตัวซึ่งมีลูกเพียง 1 ลูก และ RelativeLayout อีกอัน นั่นทำให้หนึ่งในนั้นถอดออกได้

หลีกเลี่ยงการเรียก requestLayout() เพราะมันทำให้เกิดการสำรวจลำดับชั้นของมุมมองทั้งหมด เพื่อค้นหาว่าแต่ละมุมมองควรมีขนาดใหญ่เพียงใด หากมีข้อขัดแย้งกับการวัด ลำดับชั้นอาจถูกข้ามหลายครั้ง ซึ่งหากเกิดขึ้นระหว่างแอนิเมชันบางรายการ จะทำให้บางเฟรมถูกข้ามไปอย่างแน่นอน หากคุณต้องการทราบข้อมูลเพิ่มเติมว่า Android มีมุมมองอย่างไร โปรดอ่านสิ่งนี้ ลองดูที่มุมมองเดียวตามที่เห็นใน Hierarchy Viewer

ผู้ดูลำดับชั้น

มุมบนขวามีปุ่มสำหรับขยายการแสดงตัวอย่างมุมมองเฉพาะในหน้าต่างแบบสแตนด์อโลน ใต้นั้น คุณยังสามารถดูตัวอย่างมุมมองจริงในแอพได้อีกด้วย รายการถัดไปคือตัวเลข ซึ่งแสดงถึงจำนวนลูกที่มุมมองที่กำหนด ซึ่งรวมถึงมุมมองด้วย หากคุณเลือกโหนด (ควรเป็นโหนดหลัก) และกด "รับเวลาเลย์เอาต์" (วงกลมสี 3 วง) คุณจะมีค่าเพิ่มขึ้น 3 ค่าพร้อมกับวงกลมสีที่ปรากฏเป็นหน่วยวัด เลย์เอาต์ และวาด อาจไม่น่าแปลกใจเลยที่ระยะการวัดแสดงถึงเวลาที่ใช้ในการวัดมุมมองที่กำหนด เฟสของเลย์เอาต์นั้นเกี่ยวกับเวลาในการเรนเดอร์ ในขณะที่การวาดคือการดำเนินการวาดจริง ค่าและสีเหล่านี้สัมพันธ์กัน สีเขียวหมายความว่ามุมมองแสดงผลใน 50% สูงสุดของการดูทั้งหมดในแผนภูมิต้นไม้ สีเหลืองหมายถึงการแสดงผลใน 50% ที่ช้ากว่าของการดูทั้งหมดในทรี สีแดงหมายความว่าการดูที่กำหนดเป็นหนึ่งในมุมมองที่ช้าที่สุด เนื่องจากค่าเหล่านี้เป็นค่าสัมพัทธ์ จึงจะมีค่าสีแดงเสมอ คุณไม่สามารถหลีกเลี่ยงได้

ภายใต้ค่าที่คุณมีชื่อคลาส เช่น “TextView” ID มุมมองภายในของอ็อบเจ็กต์ และ android:id ของมุมมอง ซึ่งคุณตั้งค่าในไฟล์ XML เราขอแนะนำให้คุณสร้างนิสัยในการเพิ่ม ID ให้กับทุกมุมมอง แม้ว่าคุณจะไม่ได้อ้างอิง ID เหล่านี้ในโค้ดก็ตาม จะทำให้การระบุมุมมองใน Hierarchy Viewer เป็นเรื่องง่าย และในกรณีที่คุณมีการทดสอบอัตโนมัติในโครงการของคุณ ก็จะทำให้การกำหนดเป้าหมายองค์ประกอบเร็วขึ้นมาก ซึ่งจะช่วยประหยัดเวลาสำหรับคุณและเพื่อนร่วมงานของคุณในการเขียน การเพิ่ม ID ให้กับองค์ประกอบที่เพิ่มในไฟล์ XML นั้นค่อนข้างตรงไปตรงมา แต่สิ่งที่เกี่ยวกับองค์ประกอบที่เพิ่มเข้ามาแบบไดนามิกล่ะ มันกลับกลายเป็นว่าง่ายจริงๆด้วย เพียงสร้างไฟล์ ids.xml ในโฟลเดอร์ค่าของคุณแล้วพิมพ์ลงในฟิลด์ที่จำเป็น สามารถมีลักษณะดังนี้:

 <resources> <item name="item_title" type="id"/> <item name="item_body" type="id"/> </resources>

จากนั้นในโค้ด คุณสามารถใช้ setId(R.id.item_title) มันไม่ง่ายเลย

มีอีกสองสามสิ่งที่ต้องให้ความสนใจเมื่อเพิ่มประสิทธิภาพ UI โดยทั่วไปคุณควรหลีกเลี่ยงลำดับชั้นที่ลึกในขณะที่เลือกลำดับชั้นที่ตื้นหรือกว้าง อย่าใช้เลย์เอาต์ที่คุณไม่ต้องการ ตัวอย่างเช่น คุณอาจแทนที่กลุ่มของ LinearLayouts ที่ซ้อนกันด้วย RelativeLayout หรือ TableLayout ทดลองกับเลย์เอาต์ต่างๆ ได้ตามสบาย อย่าเพียงแค่ใช้ LinearLayout และ RelativeLayout ทุกครั้ง ลองสร้างมุมมองแบบกำหนดเองเมื่อจำเป็น มันสามารถปรับปรุงประสิทธิภาพได้อย่างมากหากทำได้ดี ตัวอย่างเช่น คุณรู้หรือไม่ว่า Instagram ไม่ได้ใช้ TextViews เพื่อแสดงความคิดเห็น?

คุณสามารถหาข้อมูลเพิ่มเติมเกี่ยวกับ Hierarchy Viewer ได้ในเว็บไซต์ Android Developers พร้อมคำอธิบายของบานหน้าต่างต่างๆ โดยใช้เครื่องมือ Pixel Perfect ฯลฯ อีกสิ่งหนึ่งที่ฉันจะชี้ให้เห็นคือการจับภาพมุมมองในไฟล์ .psd ซึ่งสามารถทำได้โดย ปุ่ม "จับภาพเลเยอร์หน้าต่าง" ทุกมุมมองจะอยู่ในเลเยอร์ที่แยกจากกัน ดังนั้นจึงง่ายมากที่จะซ่อนหรือเปลี่ยนแปลงใน Photoshop หรือ GIMP โอ้ เป็นอีกเหตุผลหนึ่งที่ต้องเพิ่ม ID ให้กับทุกการดูที่คุณทำได้ มันจะทำให้เลเยอร์มีชื่อที่สมเหตุสมผลจริงๆ

คุณจะพบเครื่องมือแก้ไขข้อบกพร่องอีกมากมายในตัวเลือกสำหรับนักพัฒนา ดังนั้นฉันแนะนำให้คุณเปิดใช้งานและดูว่าพวกเขากำลังทำอะไรอยู่ สิ่งที่อาจจะผิดไป?

ไซต์นักพัฒนาซอฟต์แวร์ Android มีชุดแนวทางปฏิบัติที่ดีที่สุดสำหรับประสิทธิภาพ พวกเขาครอบคลุมพื้นที่ต่างๆ มากมาย รวมถึงการจัดการหน่วยความจำ ซึ่งฉันไม่ได้พูดถึงจริงๆ ฉันเพิกเฉยอย่างเงียบ ๆ เพราะการจัดการหน่วยความจำและการติดตามการรั่วไหลของหน่วยความจำนั้นเป็นเรื่องราวที่แยกจากกันทั้งหมด การใช้ไลบรารีของบุคคลที่สามเพื่อแสดงรูปภาพอย่างมีประสิทธิภาพจะช่วยได้มาก แต่ถ้าคุณยังมีปัญหาด้านหน่วยความจำ ให้ลองดู Canary รั่วที่สร้างโดย Square หรืออ่านสิ่งนี้

ห่อ

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

อย่าลืมเรียนรู้จากนักพัฒนาชั้นนำและบริษัทชั้นนำ คุณสามารถค้นหาบล็อกวิศวกรรมสองสามร้อยบล็อกได้ที่ลิงค์นี้ เห็นได้ชัดว่าไม่ใช่แค่สิ่งที่เกี่ยวกับ Android ดังนั้นหากคุณสนใจเฉพาะ Android คุณต้องกรองบล็อกนั้น ๆ ฉันขอแนะนำบล็อกของ Facebook และ Instagram เป็นอย่างยิ่ง แม้ว่า UI ของ Instagram บน Android จะน่าสงสัย แต่บล็อกด้านวิศวกรรมของพวกเขาก็มีบทความดีๆ บางอย่าง สำหรับฉันมันยอดเยี่ยมมากที่ได้เห็นวิธีการทำสิ่งต่างๆ ในบริษัทต่างๆ ที่จัดการผู้ใช้หลายร้อยล้านคนทุกวันได้อย่างง่ายดาย ดังนั้นการไม่อ่านบล็อกของพวกเขาจึงดูบ้า โลกกำลังเปลี่ยนแปลงไปอย่างรวดเร็ว ดังนั้นหากคุณไม่พยายามปรับปรุง เรียนรู้จากผู้อื่น และใช้เครื่องมือใหม่ๆ อยู่เสมอ คุณจะถูกทิ้งไว้ข้างหลัง ดังที่ Mark Twain กล่าว คนที่ไม่อ่านไม่มีข้อได้เปรียบเหนือคนที่อ่านหนังสือไม่ออก