‫SurfaceView و GLSurfaceView

میانای کاربری چارچوب برنامه Android براساس سلسله‌مراتبی از اشیایی است که با View شروع می‌شود. همه عناصر رابط کاربری مجموعه‌ای از اندازه‌گیری‌ها و فرایند چیدمانی را طی می‌کنند که آن‌ها را در ناحیه مستطیلی جای می‌دهد. سپس، چارچوب همه اشیاء نمای قابل‌مشاهده را در سطحی که توسط WindowManager هنگام آوردن برنامه به پیش‌زمینه راه‌اندازی شده است، ارائه می‌دهد. رشته میانای کاربر برنامه، چیدمان و بازپردازی را برای هر میان‌گیر قاب انجام می‌دهد.

SurfaceView

‫SurfaceView مؤلفه‌ای است که می‌توانید از آن برای جاسازی لایه ترکیبی اضافی در سلسله‌مراتب نمای خود استفاده کنید. ‫SurfaceView همان پارامترهای چیدمان را به‌عنوان نماهای دیگر می‌گیرد، بنابراین می‌توان آن را مانند هر نمای دیگری دستکاری کرد، اما محتویات SurfaceView شفاف است.

وقتی با منبع بافر خارجی، مثل بافت GL یا کدبند رسانه، پردازش می‌کنید، باید بافرها را از منبع بافر در نمایشگر کپی کنید تا بافرها روی صفحه نمایش داده شوند. استفاده از SurfaceView به شما امکان می‌دهد این کار را انجام دهید.

وقتی مؤلفه نمای SurfaceView در آستانه نمایان شدن است، چارچوب از SurfaceControl می‌خواهد که سطح جدیدی را از SurfaceFlinger درخواست کند. برای دریافت تماس‌های برگشتی هنگام ایجاد یا تخریب سطح، از میانای SurfaceHolder استفاده کنید. به‌طور پیش‌فرض، چارچوب سطح ایجادشده جدید را پشت سطح رابط کاربری برنامه قرار می‌دهد. می‌توانید ترتیب Z پیش‌فرض را ملغی کنید تا سطح جدید در بالا قرار گیرد.

پردازش با SurfaceView در مواردی که نیاز به پردازش در سطحی جداگانه دارید مفید است، مثلاً زمانی که با Camera API یا زمینه OpenGL ES پردازش می‌کنید. وقتی با SurfaceView رندر می‌کنید، SurfaceFlinger مستقیماً بافرهای صفحه را ترکیب می‌کند. بدون SurfaceView، باید میان‌گیرها را در سطح خارج از صفحه ترکیب کنید، که سپس در صفحه ترکیب می‌شود، بنابراین رندر کردن با SurfaceView کار اضافی را حذف می‌کند. پس‌از پردازش با SurfaceView، از رشته واسط کاربر برای هماهنگی با چرخه حیات فعالیت و درصورت نیاز، ایجاد تغییرات در اندازه یا موقعیت نما استفاده کنید. سپس، «ترکیب‌کننده سخت‌افزاری» واسط کاربر برنامه و لایه‌های دیگر را ترکیب می‌کند.

سطح جدید طرف تولیدکننده BufferQueue است که مصرف‌کننده آن لایه SurfaceFlinger است. می‌توانید سطح را با هر مکانیزمی که می‌تواند BufferQueue را تغذیه کند به‌روز کنید، مانند توابع Canvas ارائه‌شده توسط سطح، پیوست کردن یک EGLSurface و طراحی روی سطح با GLES، یا پیکربندی یک رمزگشای رسانه برای نوشتن سطح.

SurfaceView و چرخه حیات فعالیت

هنگام استفاده از SurfaceView، سطح را از رشته‌ای غیر از رشته رابط کاربری اصلی رندر کنید.

برای فعالیت با SurfaceView، دو ماشین حالت جداگانه اما وابسته به هم وجود دارد:

  • برنامه onCreate/onResume/onPause
  • سطح ایجاد/تغییر/تخریب شد

وقتی فعالیت شروع می‌شود، به این ترتیب تماس برگشتی دریافت می‌کنید:

  1. onCreate()
  2. onResume()
  3. surfaceCreated()
  4. surfaceChanged()

اگر روی «بازگشت» کلیک کنید، این موارد را دریافت می‌کنید:

  1. onPause()
  2. ‫surfaceDestroyed() (تماس درست قبل‌از ناپدید شدن سطح)

اگر صفحه‌نمایش را بچرخانید، فعالیت ازهم باز می‌شود و دوباره ساخته می‌شود و چرخه کامل را دریافت می‌کنید. با بررسی isFinishing() می‌توانید متوجه شوید که بازراه‌اندازی سریع است. ممکن است فعالیتی را آنقدر سریع شروع/متوقف کنید که surfaceCreated() بعداز onPause() اتفاق بیفتد.

اگر روی دکمه روشن/خاموش ضربه بزنید تا صفحه‌نمایش خالی شود، فقط onPause() را بدون surfaceDestroyed() دریافت می‌کنید. سطح فعال می‌ماند و پردازش می‌تواند ادامه یابد. اگر به درخواست رویدادهای «طراح رقص» ادامه دهید، همچنان می‌توانید آن‌ها را دریافت کنید. اگر صفحه قفلی دارید که جهت دیگری را اجبار می‌کند، ممکن است فعالیتتان هنگام روشن شدن دستگاه مجدداً شروع شود. درغیراین‌صورت، می‌توانید با همان سطح قبلی از حالت صفحه‌خالی خارج شوید.

طول عمر رشته می‌تواند به سطح یا فعالیت گره بخورد، بسته به اینکه می‌خواهید وقتی صفحه خالی می‌شود چه اتفاقی بیفتد. رشته می‌تواند در شروع/توقف فعالیت یا در ایجاد/تخریب سطح شروع/متوقف شود.

شروع/توقف رشته در شروع/توقف «فعالیت» به‌خوبی با چرخه حیات برنامه کار می‌کند. رشته پردازنده را در onResume() شروع می‌کنید و آن را در onStop() متوقف می‌کنید. هنگام ایجاد و پیکربندی رشته، گاهی سطح ازقبل وجود دارد، گاهی وجود ندارد (برای مثال، پس‌از روشن/خاموش کردن صفحه‌نمایش با دکمه روشن/خاموش، همچنان فعال است). باید صبر کنید تا سطح ایجاد شود و سپس در رشته مقداردهی اولیه کنید. نمی‌توانید در surfaceCreate() بازمانی مقداردهی اولیه کنید زیرا اگر سطح بازسازی نشود، دوباره اجرا نخواهد شد. درعوض، وضعیت سطح را پُرسمان یا ذخیره کنید و آن را به رشته رندرکننده ارسال کنید.

شروع/توقف رشته در ایجاد/ازبین بردن سطح به‌خوبی کار می‌کند زیرا سطح و رندرکننده ازنظر منطقی درهم تنیده‌اند. رشته را بعداز ایجاد سطح شروع می‌کنید، که از برخی‌از نگرانی‌های ارتباط بین‌رشته‌ای جلوگیری می‌کند؛ و پیام‌های ایجاد/تغییر سطح بازارسال می‌شوند. برای تأیید اینکه وقتی صفحه خالی می‌شود، پرداز شروع می‌شود و وقتی از حالت خالی خارج می‌شود، ازسر گرفته می‌شود، به Choreographer بگویید فراخوانی بازگشت فراخوانی ترسیم قاب را متوقف کند. onResume()اگر رشته رندر درحال اجرا باشد، تماس‌های برگشتی را ازسر می‌گیرد. بااین‌حال، اگر براساس زمان سپری‌شده بین فریم‌ها پویانمایی کنید، ممکن است فاصله زیادی قبل‌از رسیدن رویداد بعدی وجود داشته باشد؛ استفاده از پیام صریح توقف/ازسرگیری می‌تواند این مشکل را حل کند.

هر دو گزینه، چه طول عمر رشته به «فعالیت» یا سطح مرتبط باشد، بر نحوه پیکربندی رشته رندرکننده و اینکه آیا اجرا می‌شود یا نه تمرکز دارند. نگرانی مرتبط دیگر استخراج وضعیت از رشته هنگام ازبین رفتن فعالیت است (در onStop() یا onSaveInstanceState())؛ در چنین مواردی، گره زدن طول عمر رشته به فعالیت بهترین عملکرد را دارد زیرا پس‌از پیوستن رشته پردازنده، می‌توان بدون اصول همگام‌سازی به وضعیت رشته پردازنده دسترسی پیدا کرد.

GLSurfaceView

کلاس GLSurfaceView کلاس‌های کمکی برای مدیریت زمینه‌های EGL، ارتباط بین رشته‌ای، و تعامل با چرخه حیات فعالیت ارائه می‌دهد. برای استفاده از GLES، نیازی به استفاده از GLSurfaceView ندارید.

برای مثال، GLSurfaceView رشته‌ای برای رندر کردن ایجاد می‌کند و بافت EGL را در آنجا پیکربندی می‌کند. وقتی فعالیت موقتاً متوقف می‌شود، وضعیت به‌طور خودکار پاک‌سازی می‌شود. اکثر برنامه‌ها برای استفاده از GLES با GLSurfaceView نیازی به دانستن چیزی درباره EGL ندارند.

در اکثر موارد، GLSurfaceView می‌تواند کار با GLES را آسان‌تر کند. در برخی شرایط، ممکن است مزاحم باشد.