ทำความเข้าใจเกี่ยวกับแนวคิด Canvas และ Surface


114

ฉันกำลังดิ้นรนเพื่อทำความเข้าใจกระบวนการวาดภาพSurfaceViewและดังนั้นทั้งSurface/ Canvas/ Bitmapระบบซึ่งใช้ใน Android

ฉันได้อ่านบทความและหน้าเอกสาร API ทั้งหมดซึ่งฉันสามารถหาได้ในไซต์สำหรับนักพัฒนาแอนดรอยด์, บทแนะนำเกี่ยวกับกราฟิก Android, ซอร์สโค้ด LunarLander และคำถามนี้

โปรดบอกฉันว่าข้อความใดเป็นจริงข้อใดไม่ใช่และเพราะเหตุใด

  1. CanvasมีของตัวเองBitmapติดอยู่ SurfaceมีของตัวเองCanvasติดอยู่
  2. ทั้งหมดViewเป็นของส่วนแบ่งหน้าต่างเดียวกันและทำให้แบ่งปันเดียวกันSurfaceCanvas
  3. SurfaceViewเป็นคลาสย่อยViewซึ่งแตกต่างจากViewคลาสย่อยอื่น ๆและViewตัวมันเองมีของตัวเองที่Surfaceจะดึงเข้ามา

นอกจากนี้ยังมีคำถามเพิ่มเติมอีกหนึ่งคำถาม:

  • เหตุใดจึงจำเป็นต้องมีSurfaceคลาสหากมีCanvasการดำเนินการระดับสูงกับบิตแมปอยู่แล้ว ยกตัวอย่างสถานการณ์ที่Canvasไม่เหมาะสำหรับการทำงานที่Surfaceสามารถทำได้

2
doc สถาปัตยกรรมกราฟิก: source.android.com/devices/graphics/architecture.html
fadden

คำตอบ:


223

คำจำกัดความบางประการมีดังนี้

  • พื้นผิวคือวัตถุที่มีพิกเซลที่ถูกรวมเข้ากับหน้าจอ ทุกหน้าต่างที่คุณเห็นบนหน้าจอ (กล่องโต้ตอบกิจกรรมแบบเต็มหน้าจอแถบสถานะ) จะมีพื้นผิวของตัวเองที่ดึงเข้ามาและ Surface Flinger จะแสดงสิ่งเหล่านี้ไปยังการแสดงผลขั้นสุดท้ายตามลำดับ Z ที่ถูกต้อง โดยทั่วไปพื้นผิวจะมีบัฟเฟอร์มากกว่าหนึ่งบัฟเฟอร์ (โดยปกติคือสอง) เพื่อทำการเรนเดอร์บัฟเฟอร์สองครั้ง: แอปพลิเคชันสามารถวาดสถานะ UI ถัดไปได้ในขณะที่พื้นผิวกำลังประกอบหน้าจอโดยใช้บัฟเฟอร์สุดท้ายโดยไม่จำเป็นต้องรอให้แอปพลิเคชันเสร็จสิ้น การวาดภาพ

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

  • มุมมองเป็นองค์ประกอบ UI แบบโต้ตอบภายในหน้าต่าง หน้าต่างมีลำดับชั้นมุมมองเดียวที่แนบมาซึ่งแสดงลักษณะการทำงานทั้งหมดของหน้าต่าง เมื่อใดก็ตามที่จำเป็นต้องวาดหน้าต่างใหม่ (เช่นเนื่องจากมุมมองทำให้ตัวเองไม่ถูกต้อง) สิ่งนี้จะทำใน Surface ของหน้าต่าง พื้นผิวถูกล็อคซึ่งจะส่งคืนผืนผ้าใบที่สามารถใช้วาดลงไปได้ การลากผ่านจะทำตามลำดับชั้นโดยส่ง Canvas ลงสำหรับแต่ละมุมมองเพื่อวาดส่วนของ UI เมื่อทำเสร็จแล้ว Surface จะถูกปลดล็อกและโพสต์เพื่อให้บัฟเฟอร์ที่เพิ่งวาดถูกสลับไปยังส่วนหน้าเพื่อนำไปประกอบเข้ากับหน้าจอโดย Surface Flinger

  • SurfaceView เป็นการใช้งานแบบพิเศษของ View ที่สร้าง Surface เฉพาะของตัวเองเพื่อให้แอปพลิเคชันดึงเข้ามาได้โดยตรง (นอกลำดับชั้นมุมมองปกติซึ่งมิฉะนั้นจะต้องแชร์ Surface เดียวสำหรับหน้าต่าง) วิธีการทำงานนี้ง่ายกว่าที่คุณคาดไว้ - SurfaceView ทั้งหมดทำคือขอให้ผู้จัดการหน้าต่างสร้างหน้าต่างใหม่บอกให้ Z สั่งหน้าต่างนั้นทันทีที่อยู่ด้านหลังหรือด้านหน้าหน้าต่างของ SurfaceView และวางตำแหน่งให้ตรงกัน ที่ SurfaceView ปรากฏในหน้าต่างที่มี หากวางพื้นผิวไว้ด้านหลังหน้าต่างหลัก (ตามลำดับ Z) SurfaceView จะเติมส่วนของหน้าต่างหลักด้วยความโปร่งใสเพื่อให้สามารถมองเห็นพื้นผิวได้

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

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


ขอบคุณมาก! คำตอบทำให้สิ่งต่างๆชัดเจนขึ้น ส่วนหนึ่งเกี่ยวกับการเชื่อมต่อ Canvas เข้ากับ Surface ยังไม่ชัดเจน นึกไม่ถึงว่าจะต้องมีการดำเนินการดังกล่าวที่ไหน ต่อไปสามารถเป็นตัวอย่างของการดำเนินการนั้น: การวาด Bitmap บน Canvas ซึ่งได้มาจาก SurfaceHolder ด้วยวิธี lockCanvas ()
fyodorananiev

1
นั่นคือวิธีที่การวาดภาพเกิดขึ้น Canvas คือ API รูปวาด 2 มิติ หากคุณกำลังจะวาด o บนพื้นผิวคุณต้องสร้าง Canvas ที่ชี้ไปที่บัฟเฟอร์เพื่อใช้ Canvas 2d drawing API เพื่อวาดลงไป
hackbod

6
นอกจาก#hackbod'sคำตอบแล้วSurfaceViewยังสามารถแสดงผลจากเธรดรองซึ่งเป็นไปไม่ได้สำหรับViewวัตถุ
Mohanraj Balasubramaniam

47

ภาพรวมแนวคิดของ Window, Surface, Canvas และ Bitmap

นี่คือภาพรวมแนวคิดพื้นฐานและเรียบง่ายว่าการโต้ตอบเกิดขึ้นระหว่าง Window, Surface, Canvas และ Bitmap อย่างไร
บางครั้งการแสดงภาพจะช่วยได้มากในการทำความเข้าใจแนวคิดที่บิดเบี้ยว
ฉันหวังว่าภาพนี้จะช่วยใครบางคนได้


4
visualy แสดงสินค้าจะดีกว่าข้อความ: D
Mavenツ

18

บิตแมปเป็นเพียงกระดาษห่อหุ้มสำหรับกลุ่มพิกเซล คิดว่ามันเป็นอาร์เรย์ของพิกเซลพร้อมฟังก์ชั่นอำนวยความสะดวกอื่น ๆ

Canvas เป็นเพียงคลาสที่มีวิธีการวาดทั้งหมด มันคล้ายกับคลาสกราฟิกใน AWT / Swing หากคุณคุ้นเคยกับสิ่งนั้น ตรรกะทั้งหมดในการวาดวงกลมหรือกล่อง ฯลฯ มีอยู่ใน Canvas ผืนผ้าใบวาดบน Bitmap หรือคอนเทนเนอร์ GL แบบเปิด แต่ไม่มีเหตุผลว่าทำไมในอนาคตจึงสามารถขยายเพื่อวาดลงบนแรสเตอร์ประเภทอื่นได้

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

คำถามของคุณ.

1.Canvas มี Bitmap ของตัวเองติดอยู่ Surface มี Canvas ของตัวเองติดอยู่

ใช่แคนวาสทำงานบนบิตแมป (หรือแผง GL แบบเปิด) Surface ช่วยให้คุณมี Canvas ที่ทำงานบนพื้นผิวใดก็ได้ที่ใช้สำหรับที่เก็บพิกเซลสไตล์บิตแมป

2. หน้าต่างมุมมองทั้งหมดใช้พื้นผิวเดียวกันและแชร์ Canvas เดียวกัน

ไม่คุณสามารถมีมุมมองพื้นผิวได้มากเท่าที่คุณต้องการ

3.SurfaceView เป็นคลาสย่อยของ View ซึ่งแตกต่างจากคลาสย่อยของ View อื่น ๆ และ View เองมี Surface ของตัวเองที่จะดึงเข้ามา

ใช่. เช่นเดียวกับ ListView เป็นคลาสย่อยของ View ที่มีโครงสร้างข้อมูล List ของตัวเอง คลาสย่อยของ View แต่ละคลาสทำสิ่งที่แตกต่างกัน


1
ดังนั้นBitmapและSurfaceเป็นเพียงที่เก็บพิกเซลที่แตกต่างกันและCanvasสามารถห่อหุ้มพวกมันได้หรือไม่?
fyodorananiev

2
โดยทั่วไปใช่ ยกเว้น Canvas ไม่สามารถเขียนลงบนพื้นผิวได้ แต่จะทำงานบน Surface ใดก็ได้ที่ใช้เป็นที่เก็บพิกเซลของตัวเอง (โดยไม่ได้ดูที่มาของ Android ฉันไม่สามารถบอกได้ว่ามันคืออะไร) อาจเป็นส่วนขยาย Bitmap บางประเภทเนื่องจาก Canvas ให้ตัวสร้างสำหรับ Bitmap และ GL เท่านั้น
sksamuel

ความช่วยเหลือที่ดีขอบคุณ! เกี่ยวกับคำตอบ 2 ในคำถามของฉันฉันหมายถึงมุมมองมาตรฐานไม่ใช่ SurfaceViews สมมติว่าฉันมี RelativeLayout ที่มีช่องและปุ่มมากมาย ในกรณีนี้ Surface แนบกับหน้าต่างทั้งหมดและใช้มุมมองทั้งหมดร่วมกันในลำดับชั้นมุมมองหรือไม่
fyodorananiev

1
จำไว้ว่า Surface เป็นเพียงชุดพิกเซล ดังนั้นแต่ละมุมมองพื้นผิวจึงมีพื้นผิวของตัวเองและแต่ละมุมมองสามารถแสดงผลบนส่วนต่างๆของหน้าจอได้ ไม่จำเป็นต้องเติมเต็มหน้าจอ (แม้ว่าจะเป็นการใช้งานทั่วไปในการแสดงผลกราฟิกบนเกมแบบเต็มหน้าจอ)
sksamuel

1
ฉันไม่คิดว่า Bitmap และ Surface จะเทียบเท่ากันจริงๆ พื้นผิวเป็นวัตถุที่พื้นผิวสั่นไหวซึ่งผู้ประกอบหน้าต่างรู้ นั่นคือเป็นสิ่งที่มองเห็นได้โดยตรงบนหน้าจอมีคำสั่ง Z บนหน้าจอ ฯลฯ
hackbod
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.