چگونه‌ها

ملاحظات عمیق‌تر عملکرد

۸ دقیقه مطالعه
۳ نویسنده
Ben Weiss, Breana Tate, Jossi Wolf

خودتان را جمع و جور کنید و اجازه دهید شما را در زمینه‌های بیشتر در مورد عملکرد راهنمایی کنیم.

به روز سوم از هفته بررسی عملکرد خوش آمدید. امروز ما به اشتراک گذاری جزئیات و راهنمایی در مورد حوزه‌های مهم عملکرد برنامه ادامه می‌دهیم. ما بهینه‌سازی هدایت‌شده توسط پروفایل، بهبود عملکرد Jetpack Compose و ملاحظات مربوط به کار در پشت صحنه را پوشش می‌دهیم. بیایید مستقیماً وارد جزئیات شویم.

بهینه‌سازی هدایت‌شده توسط پروفایل

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

وقتی یک برنامه بسته‌بندی می‌شود، dexer مربوط به d8 کلاس‌ها و متدها را می‌گیرد و فایل‌های classes.dex برنامه شما را پر می‌کند. وقتی کاربر برنامه را باز می‌کند، این فایل‌های dex یکی پس از دیگری بارگذاری می‌شوند تا برنامه بتواند شروع به کار کند. با ارائه یک نمایه راه‌اندازی، به d8 اطلاع می‌دهید که کدام کلاس‌ها و متدها را در فایل‌های classes.dex اول بسته‌بندی کند. این ساختار به برنامه اجازه می‌دهد فایل‌های کمتری را بارگذاری کند که به نوبه خود سرعت راه‌اندازی را بهبود می‌بخشد.

پروفایل‌های پایه (Baseline Profiles) به طور مؤثر مراحل کامپایل Just in Time (JIT) را از دستگاه‌های کاربر به دستگاه‌های توسعه‌دهنده منتقل می‌کنند. کد کامپایل شده‌ی Ahead Of Time (AOT) تولید شده، ثابت کرده است که زمان راه‌اندازی و مشکلات رندر را به طور یکسان کاهش می‌دهد.

پروفایل‌های ترلو و پایه

ما از مهندسان برنامه Trello پرسیدیم که چگونه پروفایل‌های پایه بر عملکرد برنامه آنها تأثیر گذاشته است. پس از اعمال پروفایل‌های پایه در مسیر اصلی کاربر، Trello شاهد کاهش قابل توجه ۲۵ درصدی در زمان راه‌اندازی برنامه بود.

تصویر.png

ترلو توانست با استفاده از پروفایل‌های پایه، زمان راه‌اندازی برنامه خود را ۲۵ درصد بهبود بخشد.

پروفایل‌های پایه در متا

همچنین، مهندسان متا اخیراً مقاله‌ای در مورد چگونگی افزایش سرعت برنامه‌های اندروید خود با پروفایل‌های پایه منتشر کرده‌اند.

تصویر.png

در سراسر برنامه‌های متا، تیم‌ها پس از اعمال پروفایل‌های پایه، شاهد بهبود معیارهای حیاتی مختلف تا ۴۰ درصد بوده‌اند.

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

با پروفایل‌های پایه شروع کنید

برای تولید یک Baseline یا Startup Profile، شما یک تست macrobenchmark می‌نویسید که برنامه را اجرا می‌کند. در طول تست پروفایل، داده‌هایی جمع‌آوری می‌شوند که در طول کامپایل برنامه استفاده خواهند شد. تست‌ها با استفاده از رابط برنامه‌نویسی کاربردی جدید UiAutomator نوشته می‌شوند که فردا به آن خواهیم پرداخت.

نوشتن یک بنچمارک مانند این ساده است و می‌توانید نمونه کامل را در گیت‌هاب مشاهده کنید.

  @Test

fun profileGenerator() {

    rule.collect(

        packageName = TARGET_PACKAGE,

        maxIterations = 15,

        stableIterations = 3,

        includeInStartupProfile = true

    ) {

        uiAutomator {

            startApp(TARGET_PACKAGE)

        }

    }


}

ملاحظات

با نوشتن یک تست ماکروبنچمارک با عنوان Baseline Profile و یک Startup Profile برای مسیری که کاربران شما بیشتر طی می‌کنند، شروع کنید. این به معنی نقطه ورود اصلی است که کاربران شما به برنامه شما وارد می‌شوند، که معمولاً پس از ورود به سیستم است. سپس به نوشتن موارد تست بیشتر ادامه دهید تا تصویر کامل‌تری فقط برای Baseline Profileها به دست آورید. نیازی نیست همه چیز را با Baseline Profile پوشش دهید. به مسیرهای پرکاربرد بچسبید و عملکرد را در این زمینه اندازه‌گیری کنید. در پست فردا بیشتر در این مورد صحبت خواهیم کرد.

با بهینه‌سازی هدایت‌شده پروفایل شروع کنید

برای آشنایی با نحوه‌ی عملکرد پروفایل‌های پایه (Baseline Profiles) در زیر بدنه، این ویدیو از اجلاس توسعه‌دهندگان اندروید (Android Developers Summit) را تماشا کنید:

و برای بررسی عمیق‌تر، قسمت «زمان ساخت اندروید» در مورد بهینه‌سازی هدایت‌شده توسط پروفایل را بررسی کنید:

ما همچنین راهنمایی‌های گسترده‌ای در مورد پروفایل‌های پایه و پروفایل‌های راه‌اندازی برای مطالعه بیشتر در دسترس داریم.

بهبود عملکرد Jetpack Compose

چارچوب رابط کاربری اندروید، سرمایه‌گذاری تیم مهندسی در بهبود عملکرد را به ثمر رسانده است. از نسخه ۱.۹ جت‌پک کامپوز، در طول یک آزمایش بنچمارک داخلی برای پیمایش طولانی، میزان خطای اسکرول به ۰.۲ درصد کاهش یافته است.

jankyFrames.png

این پیشرفت‌ها به دلیل چندین ویژگی که در جدیدترین نسخه‌ها گنجانده شده است، امکان‌پذیر شده است.

پنجره کش قابل تنظیم

به طور پیش‌فرض، طرح‌بندی‌های تنبل فقط یک آیتم را قبل از اسکرول کردن می‌سازند و پس از اینکه چیزی از صفحه خارج شد، آن آیتم حذف می‌شود. اکنون می‌توانید تعداد آیتم‌هایی را که باید در کسری از اندازه viewport یا dp نگه داشته شوند، سفارشی کنید. این به برنامه شما کمک می‌کند تا کار بیشتری را از قبل انجام دهد و پس از فعال کردن ترکیب قابل مکث بین فریم‌ها، از زمان موجود به طور مؤثرتری استفاده کند.

برای شروع استفاده از پنجره‌های کش قابل تنظیم، یک LazyLayoutCacheWindow نمونه‌سازی کنید و آن را به lazy list یا lazy grid خود منتقل کنید. عملکرد برنامه خود را با استفاده از اندازه‌های مختلف پنجره کش، به عنوان مثال ۵۰٪ از viewport، اندازه‌گیری کنید. مقدار بهینه به ساختار محتوا و اندازه آیتم شما بستگی دارد.

  val dpCacheWindow = LazyLayoutCacheWindow(ahead = 150.dp, behind = 100.dp)

val state = rememberLazyListState(cacheWindow = dpCacheWindow)

LazyColumn(state = state) {

    // column contents

}

ترکیب قابل مکث

این ویژگی امکان مکث در کامپوزیشن‌ها و تقسیم کار آنها در چندین فریم را فراهم می‌کند. این APIها در نسخه ۱.۹ ارائه شدند و اکنون به طور پیش‌فرض در نسخه ۱.۱۰ در پیش‌واکشی طرح‌بندی تنبل استفاده می‌شوند. شما باید بیشترین فایده را در موارد پیچیده با زمان‌های طولانی‌تر کامپوزیشن مشاهده کنید.

تصویر.png

بهینه‌سازی‌های بیشتر در عملکرد Compose

در نسخه‌های ۱.۹ و ۱.۱۰ از Compose، تیم توسعه‌دهنده چندین بهینه‌سازی انجام داده است که کمی کمتر به چشم می‌آیند.

چندین API که در پشت صحنه از کوروتین استفاده می‌کنند، بهبود یافته‌اند. برای مثال، هنگام استفاده از Draggable و Clickable ، توسعه‌دهندگان باید شاهد زمان واکنش سریع‌تر و تعداد تخصیص بهبود یافته باشند.

بهینه‌سازی‌ها در ردیابی مستطیل طرح‌بندی، عملکرد اصلاح‌کننده‌هایی مانند onVisibilityChanged() و onLayoutRectChanged() را بهبود بخشیده است. این امر، حتی زمانی که به صراحت از این APIها استفاده نمی‌شود، سرعت مرحله طرح‌بندی را افزایش می‌دهد.

یکی دیگر از بهبودهای عملکرد، استفاده از مقادیر ذخیره‌شده در حافظه پنهان هنگام مشاهده موقعیت‌ها از طریق onPlaced() است.

پیش‌واکشی متن در پس‌زمینه

از نسخه ۱.۹، Compose قابلیت پیش‌واکشی متن در یک نخ پس‌زمینه را اضافه می‌کند. این به شما امکان می‌دهد تا حافظه‌های پنهان را از قبل گرم کنید تا طرح‌بندی متن سریع‌تر شود و برای عملکرد رندر برنامه مرتبط است. در طول طرح‌بندی، متن باید به چارچوب اندروید منتقل شود که در آن یک حافظه پنهان کلمه پر می‌شود. به طور پیش‌فرض، این روی نخ UI اجرا می‌شود. تخلیه پیش‌واکشی و پر کردن حافظه پنهان کلمه روی یک نخ پس‌زمینه می‌تواند طرح‌بندی را سرعت بخشد، به خصوص برای متن‌های طولانی‌تر. برای پیش‌واکشی در یک نخ پس‌زمینه، می‌توانید با ارسال یک LocalBackgroundTextMeasurementExecutor به یک CompositionLocalProvider مانند این، یک اجراکننده سفارشی را به هر سازنده‌ای که از BasicText در زیر کاپوت استفاده می‌کند، منتقل کنید.

  val defaultTextMeasurementExecutor = Executors.newSingleThreadExecutor()

CompositionLocalProvider(

    LocalBackgroundTextMeasurementExecutor provides DefaultTextMeasurementExecutor

) {

    BasicText("Some text that should be measured on a background thread!")


}

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

ملاحظات عملکرد کاری پیشینه

کار پس‌زمینه بخش اساسی بسیاری از برنامه‌ها است. شما ممکن است از کتابخانه‌هایی مانند WorkManager یا JobScheduler برای انجام وظایفی مانند موارد زیر استفاده کنید:

  • بارگذاری دوره‌ای رویدادهای تحلیلی
  • همگام‌سازی داده‌ها بین یک سرویس backend و یک پایگاه داده
  • پردازش رسانه (یعنی تغییر اندازه یا فشرده‌سازی تصاویر)

یک چالش کلیدی در حین اجرای این وظایف، ایجاد تعادل بین عملکرد و بهره‌وری انرژی است. WorkManager به شما امکان می‌دهد به این تعادل دست یابید. این ابزار به گونه‌ای طراحی شده است که از نظر مصرف انرژی کارآمد باشد و اجازه دهد کار به یک پنجره اجرای بهینه که تحت تأثیر عوامل مختلفی از جمله محدودیت‌هایی که شما تعیین می‌کنید یا محدودیت‌های اعمال شده توسط سیستم قرار دارد، موکول شود.

با این حال، WorkManager یک راه‌حل یکسان برای همه نیست. اندروید همچنین تعدادی API بهینه‌شده از نظر مصرف انرژی دارد که به‌طور خاص با در نظر گرفتن برخی از مسیرهای مشترک کاربر اصلی (CUJ) طراحی شده‌اند.

برای مشاهده‌ی فهرستی از تنها چند مورد از این موارد، از جمله به‌روزرسانی ویجت و دریافت موقعیت مکانی در پس‌زمینه، به صفحه‌ی فرود «کار پس‌زمینه» مراجعه کنید.

ابزارهای اشکال‌زدایی محلی برای کار پس‌زمینه: سناریوهای رایج

برای اشکال‌زدایی از Background Work و درک دلیل تأخیر یا شکست یک وظیفه، به قابلیت مشاهده‌ی نحوه‌ی زمان‌بندی وظایف توسط سیستم نیاز دارید.

برای کمک به این امر، WorkManager چندین ابزار مرتبط دارد که به شما در اشکال‌زدایی محلی و بهینه‌سازی عملکرد کمک می‌کند (برخی از این ابزارها برای JobScheduler نیز کار می‌کنند)! در اینجا چند سناریوی رایج که ممکن است هنگام استفاده از WorkManager با آنها مواجه شوید و توضیحی در مورد ابزارهایی که می‌توانید برای اشکال‌زدایی آنها استفاده کنید، آورده شده است.

اشکال‌زدایی دلیل عدم اجرای کار زمان‌بندی‌شده

تأخیر یا عدم اجرای کار برنامه‌ریزی‌شده می‌تواند به دلایل مختلفی باشد، از جمله برآورده نشدن محدودیت‌های مشخص‌شده یا محدودیت‌هایی که توسط سیستم اعمال شده‌اند.

اولین قدم در بررسی علت عدم اجرای کار برنامه‌ریزی‌شده، تأیید موفقیت‌آمیز بودن زمان‌بندی کار است. پس از تأیید وضعیت زمان‌بندی، مشخص کنید که آیا محدودیت‌ها یا پیش‌شرط‌های برآورده‌نشده‌ای وجود دارد که مانع از اجرای کار می‌شود یا خیر.

ابزارهای مختلفی برای اشکال‌زدایی این سناریو وجود دارد.

بازرس وظیفه پس‌زمینه

ابزار Background Task Inspector ابزاری قدرتمند است که مستقیماً در اندروید استودیو ادغام شده است. این ابزار، نمایش بصری از تمام وظایف WorkManager و وضعیت‌های مرتبط با آنها (در حال اجرا، در صف انتظار، ناموفق، موفق) ارائه می‌دهد.

برای اشکال‌زدایی از دلیل عدم اجرای کار زمان‌بندی‌شده با استفاده از ابزار Background Task Inspector، به وضعیت(های) کار ذکر شده مراجعه کنید. وضعیت «در صف قرار گرفته» نشان می‌دهد که کار شما زمان‌بندی شده است، اما هنوز منتظر اجرا است.

مزایا: گذشته از ارائه روشی آسان برای مشاهده همه وظایف، این ابزار به ویژه در صورتی که کارهای زنجیره‌ای دارید مفید است. ابزار بررسی وظایف پس‌زمینه، یک نمای نموداری ارائه می‌دهد که می‌تواند به صورت بصری نشان دهد که آیا شکست یک وظیفه قبلی بر اجرای وظیفه بعدی تأثیر گذاشته است یا خیر.

تصویر.png

نمای فهرست بازرس وظایف پس‌زمینه

تصویر.png

نمای گراف بازرس وظایف پس‌زمینه

زمان‌بند کارهای پوسته adb dumpsys

این دستور لیستی از تمام کارهای فعال JobScheduler (که شامل WorkManager Workers نیز می‌شود) را به همراه محدودیت‌های مشخص شده و محدودیت‌های اعمال شده توسط سیستم، برمی‌گرداند. همچنین تاریخچه کارها را نیز برمی‌گرداند.

اگر می‌خواهید روش متفاوتی برای مشاهده کار زمان‌بندی‌شده و محدودیت‌های مرتبط با آن داشته باشید، از این استفاده کنید. برای نسخه‌های WorkManager قبل از WorkManager 2.10.0، adb shell dumpsys jobscheduler لیستی از Workerها با این نام را برمی‌گرداند:

  [package name]/androidx.work.impl.background.systemjob.SystemJobService

اگر برنامه شما چندین worker دارد، به‌روزرسانی به WorkManager 2.10.0 به شما امکان می‌دهد نام workerها را ببینید و به راحتی workerها را از هم تشخیص دهید:

  #WorkerName#@[package name]/androidx.work.impl.background.systemjob.SystemJobService

مزایا: این دستور برای فهمیدن اینکه آیا محدودیت‌های سیستمی وجود دارد یا خیر، مفید است، محدودیت‌هایی که نمی‌توانید با Background Task Inspector تعیین کنید. برای مثال، این دستور، سطل آماده به کار برنامه شما را برمی‌گرداند که می‌تواند بر پنجره‌ای که کار زمان‌بندی شده در آن تکمیل می‌شود، تأثیر بگذارد.

فعال کردن ثبت گزارش اشکال‌زدایی

شما می‌توانید گزارش‌گیری سفارشی را فعال کنید تا گزارش‌های مفصل WorkManager را که WM— به آنها پیوست شده است، مشاهده کنید.

مزایا: این به شما امکان می‌دهد تا از زمان برنامه‌ریزی کار، انجام محدودیت‌ها و رویدادهای چرخه عمر، آگاهی داشته باشید و بتوانید هنگام توسعه برنامه خود به این گزارش‌ها مراجعه کنید.

WorkInfo.StopReason

اگر متوجه عملکرد غیرقابل پیش‌بینی یک worker خاص شدید، می‌توانید به صورت برنامه‌نویسی شده دلیل توقف worker خود را در تلاش قبلی برای اجرا با WorkInfo.getStopReason مشاهده کنید.

این یک روش خوب است که برنامه خود را طوری پیکربندی کنید که WorkInfo را با استفاده از getWorkInfoByIdFlow مشاهده کند تا مشخص شود که آیا کار شما تحت تأثیر محدودیت‌های پس‌زمینه، محدودیت‌ها، وقفه‌های مکرر یا حتی توقف توسط کاربر قرار می‌گیرد یا خیر.

مزایا: می‌توانید از WorkInfo.StopReason برای جمع‌آوری داده‌های میدانی در مورد عملکرد کارگران خود استفاده کنید.

اشکال‌زدایی مدت زمان بالای قفل بیداری منتسب به WorkManager که توسط موارد حیاتی اندروید علامت‌گذاری شده است

Android Vitals دارای یک معیار قفل بیداری جزئی بیش از حد است که قفل‌های بیداری را که در تخلیه باتری نقش دارند، برجسته می‌کند. شاید تعجب کنید که بدانید WorkManager برای اجرای وظایف، قفل‌های بیداری را به دست می‌آورد و اگر قفل‌های بیداری از آستانه تعیین شده توسط Google Play فراتر روند، می‌توانند بر قابلیت مشاهده برنامه شما تأثیر بگذارند. چگونه می‌توانید دلیل اینکه چرا مدت زمان قفل بیداری زیادی به کار شما نسبت داده می‌شود را اشکال‌زدایی کنید؟ می‌توانید از ابزارهای زیر استفاده کنید.

داشبورد اطلاعات حیاتی اندروید

ابتدا در داشبورد قفل بیداری بیش از حد Android Vitals تأیید کنید که مدت زمان بالای قفل بیداری از WorkManager است و نه یک زنگ هشدار یا قفل بیداری دیگر. می‌توانید از Identify wake locks ایجاد شده توسط مستندات APIهای دیگر برای فهمیدن اینکه کدام قفل‌های بیداری به دلیل WorkManager نگه داشته شده‌اند، استفاده کنید.

پرفتو

Perfetto ابزاری برای تجزیه و تحلیل ردپاهای سیستم است. هنگام استفاده از آن برای اشکال‌زدایی WorkManager، می‌توانید بخش «وضعیت دستگاه» را مشاهده کنید تا ببینید کار شما از چه زمانی شروع شده، چه مدت اجرا شده و چگونه بر مصرف برق تأثیر می‌گذارد.

در مسیر «وضعیت دستگاه: کارها»، می‌توانید هر کارگر اجرا شده و قفل‌های بیداری مرتبط با آنها را مشاهده کنید.

وضعیت دستگاه.png

بخش وضعیت دستگاه در Perfetto، اجرای CleanupWorker و BlurWorker را نشان می‌دهد.

منابع

برای مرور کلی روش‌های اشکال‌زدایی موجود برای سایر سناریوهایی که ممکن است با آنها مواجه شوید، به صفحه Debug WorkManager مراجعه کنید.

و برای امتحان کردن عملی برخی از این روش‌ها و کسب اطلاعات بیشتر در مورد اشکال‌زدایی WorkManager، به Advanced WorkManager و Testing codelab مراجعه کنید.

مراحل بعدی

امروز ما از بحث فشرده‌سازی کد فراتر رفتیم و بررسی کردیم که چگونه Android Runtime و Jetpack Compose در واقع برنامه شما را رندر می‌کنند. چه از قبل کامپایل کردن مسیرهای بحرانی با Baseline Profiles باشد و چه روان‌سازی حالت‌های اسکرول با ویژگی‌های جدید Compose 1.9 و 1.10، این ابزارها بر حس برنامه شما تمرکز دارند. و ما عمیقاً به بهترین شیوه‌ها در مورد اشکال‌زدایی کارهای پس‌زمینه می‌پردازیم.

از اندروید بپرسید

روز جمعه ما میزبان یک جلسه پرسش و پاسخ زنده در مورد عملکرد هستیم. همین حالا با استفاده از هشتگ #AskAndroid سوالات خود را بپرسید و پاسخ آنها را از متخصصان دریافت کنید.

چالش

ما روز دوشنبه از شما خواستیم که R8 را فعال کنید. امروز، از شما می‌خواهیم که یک پروفایل پایه برای برنامه خود ایجاد کنید .

با اندروید استودیو اوتر ، ویزارد ماژول تولیدکننده پروفایل پایه این کار را آسان‌تر از همیشه می‌کند. مهم‌ترین مسیر کاربری خود را انتخاب کنید - حتی اگر فقط راه‌اندازی و ورود به برنامه شما باشد - و یک پروفایل ایجاد کنید.

وقتی آن را داشتید، یک Macrobenchmark اجرا کنید تا CompilationMode.None را با CompilationMode.Partial مقایسه کنید.

بهبودهای زمان راه‌اندازی خود را با استفاده از #optimizationEnabled در رسانه‌های اجتماعی به اشتراک بگذارید.

فردا هماهنگ کنید

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

فردا در روز چهارم به ما بپیوندید: راهنمای سطح‌بندی عملکرد ، جایی که دقیقاً نحوه اندازه‌گیری موفقیت شما را از داده‌های میدانی در Play Vitals گرفته تا ردیابی عمیق محلی با Perfetto، شرح خواهیم داد.

    نوشته شده توسط:

    ادامه مطلب