قابلیت های جدید Jetpack اندروید | راهنمای کاربردی
Jetpack اندروید در عمل بر مبنای Support Library ساخته شده است که مجموعهای از کامپوننتها برای بهرهگیری از قابلیتهای اندروید و حفظ سازگاری با نسخههای پیشین بود. گوگل اشاره کرده است که جتپک هماینک از سوی 99% همه اپلیکیشنهای پلی استور استفاده میشود. گوگل در طی سالهای اخیر برخی کارها و بهبودها را روی کتابخانه جتپک اندروید اعمال کرده است. به علاوه این کتابخانهها و قابلیتهای جدید موجب شدهاند که پیادهسازی اپلیکیشنهای بهتر آسان شود. در این مقاله قابلیتهای جدید Jetpack اندروید را معرفی میکنیم که برای گسترش دامنه کاربرد آن اعمال شدهاند.
معرفی Jetpack اندروید
Jetpack اندروید اساساً یک مجموعه از کتابخانهها، ابزارها و راهنماییها برای توسعه اپلیکیشنهای مدرن اندروید است.
در حال حاضر، چهار کاربرد مختلف برای Jetpack مطرح هستند که شامل معماری، UI، رفتار و شالوده میشوند. Jetpack شاهد روند کاربرد گسترده و پرشتابی است. در حال حاضر 80% از 1000 اپلیکیشن برتر پلی استور از Jetpack استفاده میکنند.
Hilt
Hilt (+) اساساً کتابخانه تزریق وابستگی پیشنهاد شده از سوی Jetpack محسوب میشود. «تزریق وابستگی» (Dependency Injection) تکنیکی است که به طور گسترده در برنامهنویسی استفاده میشود و برای توسعه اندروید بسیار مناسب است. با این حال، وابستگیها به جای این که مستقیماً در کلاس خود ارائه شوند، در یک کلاس خاص مقید میشوند. این کار به حذف تزویج از کدهای شما کمک میکند. با بهرهگیری از تزریق وابستگی میتوان کدی با قابلیت استفاده مجدد به دست آورد، زیرا تزویج بین کامپوننتها و تست کردن بسیار آسانتر میشود. دلیل این امر آن است که وابستگیهای کلاس به صورت خوش-تعریف درمیآیند.
به علاوه در جدیدترین پیمایش Android Developer Benchmark که از سوی گوگل اجرا شده است، 49% از توسعهدهندگان از گوگل خواستهاند که روی راهکارهای تزریق وابستگی کار کند. در نتیجه گوگل تیم داگر را برای ایجاد Hilt سازماندهی کرده است. کتابخانه تزریق وابستگی Dagger از سوی گوگل توسعه یافته است و به طور گستردهای از سوی اپلیکیشنهای مهم اندرویدی استفاده میشود. با این حال، آغاز کار با داگر در اندروید برخی چالشها برای توسعهدهندگان دارد، زیرا کتابخانه پیچیدهای است.
Hilt یک کتابخانه تزریق وابستگی برای اندروید است که کد قالبی مورد نیاز برای تزریق دستی وابستگی را در پروژه کاهش میدهد.
Hilt یک کتابخانه تزریق وابستگی با گزینههای زیاد است که به طور خاص برای اندروید و بر مبنای Dagger ساخته شده است. زمانی که از Hilt استفاده میکنیم، کلاسها با حاشیهنویسی AndroidEntryPoint حاشیهنگاری میشوند و Hilt آنها را قابل تزریق میسازد. از این رو میتوانید از حاشیهنویسی Inject@ برای تزریق وابستگیها استفاده کنید. علاوه بر آن میتوانید از حاشیهنویسی AndroidEntryPoint در کامپوننتهای اندرویدی دیگر استفاده کنید.
1@AndroidEntryPoint
2class SampleActivity: AppCompatActivity() { ... }
Hilt در حال حاضر کلاسهای اندروید زیر را ارائه میکند:
- Application (با استفاده از HiltAndroidApp@)
- Activity
- Fragment
- View
- Service
- BroadcastReceiver
در نهایت باید کلاس اپلیکیشن خود را با استفاده از HiltAndroidApp حاشیهنویسی کنید. همه اپلیکیشنهایی که از Hilt استفاده میکنند، کلاس Application را دارند که با HiltAndroidApp@ حاشیهنویسی شده است.
HiltAndroidApp@ تولید کد hilt را موجب میشود که شامل یک کلاس مبنا برای اپلیکیشن است که به عنوان کانتینر وابستگی سطح بالای اپلیکیشن عمل میکند.
1@iltAndroidApp
2class SampleApplication: Application() { ... }
این کامپوننت تولیدشده Hilt به چرخه عمر شیء Application الحاق مییابد و از وابستگیهایی که به آن اضافه میشوند پشتیبانی میکند. علاوه بر آن یک کامپوننت والد اپلیکیشن است، یعنی کامپوننتهای دیگر میتوانند به وابستگیهایی که ارائه میکند، دسترسی داشته باشند. بدین ترتیب Hilt میتواند گراف وابستگی را برای اپلیکیشن اندرویدی شما ایجاد کند. یکپارچگی محکم بین کتابخانههای Jetpack و Hilt میتواند به شما کمک کند که مدلسازی مجدد نیز به صورت خودکار تزریق شود. تنها کاری که باید بکنید این است که سازنده ViewModel خود را با ViewModelInject حاشیهنویسی کرده و از Hilt بخواهید که آن را تزریق کند.
اگر یک وابستگی که میخواهید ارائه کنید، نیاز به تنظیمات منوی بیشتری داشته باشد، میتوانید یک ماژول داگر با حاشیهنویسی InstallIn ایجاد کنید تا Hilt آن را به صورت خودکار پیدا کند. Hilt دارای دامنههای از پیش تعریفشدهای برای اندروید است و از این رو لزومی به تعریف حالتهای رایج برای خود ندارید. Hilt نه تنها حجم کد را کاهش میدهد، بلکه بار ذهنی برای آغاز را نیز کاهش میدهد. همچنین به خوبی با اپلیکیشن شما مقیاسبندی میشود، چون از قبل از سوی اپلیکیشنهای گوگل مانند یوتیوب استفاده میشود.
برخی مزیتها استفاده از Hilt در اپلیکیشنهای اندرویدی به شرح زیر است:
- Hilt از یک روش استاندارد برای استفاده از تزریق وابستگی (DI) در اپلیکیشن بهره میگیرد و کانتینرهایی برای کلاس اندروید در پروژه ارائه میکند که به صورت خودکار به مدیریت چرخههای عمر میپردازد.
- Hilt شامل اکستنشنهایی برای عرضه کلاسها از کتابخانههای جتپک است. Hilt از کامپوننتهای جتپک ViewModel و WorkManager پشتیبانی میکند.
- هیلت امکان یکپارچگی با اندروید استودیو نیز دارد که تجربه بهتری برای توسعهدهنده ارائه میکند.
- هیلت دامنههای خوشتعریفی برای اندروید دارد و به صورت پیشفرض از تست API پشتیبانی میکند. از این رو میتوانید وابستگیها را برای هر تست با پشتیبانی تستهای Integration و Robolectric جایگزین کنید.
- هیلت بر مبنای کتابخانه DI به نام Dagger ساخته شده است و از مزیت اصلاح زمان کامپایل، عملکرد زمان اجرا و مقیاسپذیری که داگر ارائه میکند برخوردار است.
App Startup
چنان که میدانیم زمان آغاز به کار اپلیکیشن معیاری حیاتی برای هر اپلیکیشن محسوب میشود. کاربران انتظار دارند که اپلیکیشنها واکنشگرا بوده و به سرعت بارگذاری شوند. زمانی که یک اپلیکیشن این انتظار را برآورده نسازد، کاربران را مأیوس میسازد. از این رو این انتظار برآورده نشده، ممکن است موجب امتیاز پایین کاربران به اپلیکیشن در پلی استور شود و یا حتی ممکن است تصمیم بگیرند آن را ترک کنند.
اغلب این کتابخانهها از Content Providers برای مقداردهی اولیه خودکار استفاده میکنند که شامل برخی کتابخانههای جتپک مانند WorkManager و Lifecycle میشود. هزینه ایجاد Content Provider از سوی گوگل مورد ارزیابی قرار میگیرد و آنها متوجه شدند که هر کدام از آنها دست کم دو میلیثانیه روی هر پیکسل به دستگاهی که اندروید 10 را اجرا میکند اضافه میکنند. این تنها هزینه ارائهدهندگان محتوا و نه هزینه کتابخانه است. Jetpack App Startup یک کتابخانه است که روشی سرراست و کارآمد برای مقداردهی کامپوننتها در آغاز به کار اپلیکیشن ارائه میکند. بنابراین هم توسعهدهندگان کتابخانه و هم توسعهدهندگان اپلیکیشن میتوانند از App Startup برای سرراست ساختن فرایند آغازین اپلیکیشن و تعیین صریح ترتیب مقداردهی استفاده کنند.
در ادامه مثالی از یک کامپوننت مقداردهی میبینید که WorkManager را پیکربندی میکند. این کامپوننت API به نام initializer را با تعیین نوع تعیین میکند و زمانی که create فراخوانی شود، به سادگی WorkManager را مقداردهی کرده و وهله مورد نظر را بازگشت میدهد.
1class WorkManagerInitializer : Initializer<WorkManager> {
2 override fun create(context: Context): WorkManager {
3 val configuration = Configuration.Builder()
4 .setMinimumLoggingLevel(Log.DEBUG)
5 .build()
6
7 WorkManager.initialize(context, configuration)
8 return WorkManager.getInstance(context)
9 }
10
11 // This component does not have any dependencies
12 override fun dependencies() = emptyList<Class<out Initializer<*>>>()
13}
به طور جایگزین کامپوننت initializer میتواند وابستگیهایش را نیز تعریف کند. به طوری که کتابخانه Startup وابستگیها را پیش از مقداردهی کامپوننت، مقداردهی کند. بدین ترتیب کتابخانه Startup در پسزمینه از یک ارائهدهنده محتوای منفرد که بین این initializer-ها مشترک هستند استفاده میکند تا زمان آغاز به کار اپلیکیشن را کاهش دهد. در نتیجه کتابخانه App Startup میتواند هم روی اپلیکیشن و هم در زمانی که توسعهدهنده تلاش میکند فرایند آغاز به کار را بهبود بخشد، مورد استفاده قرار گیرد. این کتابخانه امکان مقداردهی با تأخیر را برای بهبود بیشتر عملکرد آغاز به کار اپلیکیشن از طریق اجتناب از تکمیل ارائهدهنده محتوا فراهم ساخته است. به علاوه به صورت خودکار نقاط ردگیری را برای هر initializer اضافه میکند. به این ترتیب کامپوننتها در زمان اجرای اپلیکیشن با استفاده از ابزارهایی مانند Systrace و Perfetto مقداردهی میشوند.
SDK بازی اندروید
گوگل برای این که فرایند توسعه بازیهای اندروید آسانتر باشد، SDK بازی اندروید را اخیراً معرفی کرده است. این SDK شامل مجموعهای از کتابخانهها است که برای کمک به بهبود عملکرد بازی روی دستگاههای مختلف طراحی شدهاند. این SDK روی وبسایت اندروید موجود است و اینک به عنوان بخشی از خانواده جتپک نگریسته میشود. ضمناً روی ریپازیتوری Maven گوگل نیز عرضه شده است. این SDK در حال حاضر دو قابلیت مهم دارد که یکی کتابخانه Android Frame Pacing است که به بازیها امکان میدهد تا نرخ فریم ثابتی داشته باشند و تأخیر ورودی بازی را کاهش میدهد.
این کتابخانه نرخ فریم مورد انتظار را شناسایی کرده و دفعات نمایش فریم را بر همین اساس تنظیم میکند. مورد دیگر Android Performance Tuner است که امکان اندازهگیری و بهبود نرخ فریم را در مقیاس بزرگ روی کل اکوسیستم اندروید فراهم میسازد. همچنین شما با درج این کتابخانه در بازی خود گزارشهای جدیدی در موارد مهم اندروید دریافت میکنید که به طور خاص برای توسعهدهندگان بازی طراحی شدهاند. در حال حاضر این قابلیت به صورت آلفا روی ریپازیتوری ماون گوگل عرضه شده است.
Benchmark 1.1
کتابخانه Benchmark جتپک تهیه بنچمارک سریع از کدهای مبتنی بر کاتلین یا مبتنی بر جاوا را درون اندروید استودیو فراهم میسازد. این کتابخانه زمان راهاندازی را مدیریت کرده و عملکرد کد و دفعات تخصیص را اندازهگیری میکند و خروجی نتایج بنچمارک را هم روی کنسول اندروید استودیو و یک فایل JSON با جزییات بیشتر نمایش میدهد.
نسخه جدید کتابخانه بنچمارک اخیراً از سوی گوگل عرضه شده است و این نسخه با CPU Profiler ادغام شده است. از این رو میتوانید بنچمارکهای خود را پروفایل کرده و سپس با متد یا رد نمونه مربوطه در اندروید استودیو ترکیب نمایید. همچنین امکان پشتیبانی از ردگیری تخصیص حافظه اضافه شده است. بنابراین میتوانید زمان صرف شده برای تخصیصها را بهینهسازی کرده و garbage collection را تا حدود زیادی کاهش دهید.
Paging 3
Paging در ابتدا یک کتابخانه بود که به بارگذاری و نمایش مقادیر کوچک دادهها به صورت افزایشی کمک میکرد، اما Paging 3 کاملاً کتابخانه را با استفاده از کوروتینهای کاتلین بازنویسی کرده و قابلیتهایی با تقاضای بالا مانند Separator-ها به آن اضافه شده است. این قابلیت نقطه مرکزی Paging است که به بکاند متصل میشویم.
کتابخانه Paging به بارگذاری و نمایش دادهها از دیتاستهای بزرگتر روی فضای ذخیرهسازی دستگاه یا شبکه کمک میکند. این رویکرد به اپلیکیشن امکان میدهد که هم از پهنای باند و هم منابع سیستم به طرز کارآمدتری استفاده کند.
در نسخه جدید کلاس PagingSource بسط یافته است که یک متد منفرد است که باید پیادهسازی شود. در کد زیر API را با فراخوانی کرده و با دریافت نتایج آنها را بازگشت میدهیم. اگر مشکلی پیش بیاید، یک نتیجه خطا بازگشت میدهیم تا به Paging اعلام کنیم که خطایی رخ داده است. زمانی که PagingSource به دست آمد میتوانید یک pager بزرگتر بسازید و با ارائه پیکربندی اندازه صفحه آن را به خدمت بگیرید و در نهایت لایه UI مقادیر را دریافت کرده و به آداپتر paging ارسال میکند. این آداپتر نیز مسئولیت نمایش آنها را بر عهده دارد.
1class DoggosRemotePagingSource(
2 val backend: GoodDoggosService
3) : PagingSource<Int, Dog>() {
4 override suspend fun load(
5 params: LoadParams<Int>
6 ): LoadResult<Int, Dog> {
7 try {
8 // Load page 1 if undefined.
9 val nextPageNumber = params.key ?: 1
10 val response = backend.getDoggos(nextPageNumber)
11 return LoadResult.Page(
12 data = response.doggos,
13 prevKey = null, // Only paging forward.
14 nextKey = response.nextPageNumber + 1
15 )
16 } catch (e: Exception) {
17 // Handle errors in this block
18 return LoadResult.Error(exception)
19 }
20 }
21}
Paging در نسخه جدید، از صفر با استفاده از کوروتینهای کاتلین و Flow بازنویسی شده است. نسخه جدید AI داخلی در هدر، فوتر و جداکنندهها دارد. علاوه بر آن میتوانید تغییرهایی مانند نگاشت آیتمها با فیلتر کردن را اجرا کنید. در نهایت باید گفت که Paging 3 کاملاً با نسخه قبلی خود یعنی Paging 2 سازگار است که به تسهیل فرایند مهاجرت به نسخه جدید کمک زیادی میکند. در این لحظه این نسخه به صورت آلفا عرضه شده است.
CameraX
ساخت فیلترهای آنی روی تصاویر دریافتی تا چند سال وظیفه دشواری محسوب میشد. CameraX یک کتابخانه از جتپک است که موجب میشود استفاده از دوربین در اپلیکیشن شما بسیار آسان و پایدار باشد. این کتابخانه در بهمن سال 98 به نسخه بتا رسیده است و گوگل روی ثبات و مستندات آن تمرکز کرده تا آن را به نسخه پایداری برساند. CameraX روی 90% از دستگاههای اندرویدی کار میکند، یعنی از نظر عملکرد و قابلیتها تنوع بسیار زیادی وجود دارد. PreviewView ویجتی است که پیشنمایش دوربین را در اپلیکیشن شما نمایش میدهد.
در حال حاضر این ویجت تعاملها با چرخه عمر اپلیکیشن را از طریق صفحهها به صورت مطمئنی اجرا میکند. علاوه بر آن، نمای سطحی شما به صورت شفافی در پسزمینه دستگاه دیده میشود. به این ترتیب بافرینگ کمتر و کارایی توان بیشتری ارائه میکند. همچنین گوگل روی ارائه راهنماییهایی برای تسهیل استفاده از آن تمرکز کرده است. آنها نمونهای برای تبدیل YUV به RGB برای اجرای تحلیل تصویر در قالبهای آشناتر اضافه کردهاند. در نتیجه میتوانید به سادگی آن را با کتابخانههایی مانند AppKit ادغام کنید. نمونههای دیگر شامل OpenGL و مدیریت چرخش تصاویر هستند.
WorkManager
WorkManager (+) کتابخانه جتپک است که امکان اجرای کارهای پسزمینه با قابلیت تأخیر مانند ارسال ایمیل بسیار مهم در زمان اتصال کاربر به اینترنت را فراهم میسازد. WorkManager نه تنها روی JobScheduler برای اجرای کارها تکیه دارد، بلکه ابزار زمانبندی داخل فرایندی برای امتحان کردن ورکرها را نیز دارد. گوگل در طی این سالها به مقدار زیادی آن را بهبود بخشیده است. «ابزار زمانبندی» (Scheduler) دیگر محدودیتهایی روی زمانبندی الزام نمیکند که موجب بهبود عملکرد درخواستهای کاری میشود. WorkManager از اجرای بلندمدت یا زنده نگهداشتن کارهای مهم از سوی سیستم عامل پشتیبانی میکند.
WorkManager یک API است که زمانبندی وظایف ناهمگام با قابلیت تأخیر را که انتظار میرود حتی در صورت خروج کاربر از اپلیکیشن یا ریاستارت شدن دستگاه نیز انجام یابند را تسهیل میکند.
گاهی اوقات دانستن این که چرا یک ورکر با وجود این که انتظار میرفت اجرا شود، اجرا نشده است، کار دشواری است. در این حالتها، گوگل قابلیت جدیدی به نام Diagnostics API ارائه کرده است که میتواند با adb فراخوانی شود تا حالت درونی WorkManager را مورد بررسی قرار دهد. زمانی که این API فراخوانی شود، WorkManager حالت کنونی آن را در Logcat دامپ میکند که میتوان به سادگی از طریق یک دستور adb Logcat آن را مشاهده کرد. به علاوه برای شناسایی اشتباهات، قواعدی اضافه شدهاند که این اشتباهات را با استفاده از بررسیهای Lint به صورت برخی هشدارها شناسایی میکنند. از این رو اندروید استودیو میتواند بیدرنگ به شما اطلاع دهد که آیا خطایی در کدبیس وجود دارد یا نه.
Navigation
کتابخانه Navigation بهر شما امکان میدهد که بین صفحههای مختلف اپلیکیشن با سهولت ناوبری کنید و همچنین از اصول UI اندروید نیز پیروی کنید.
ناوبری به معنی تعاملهایی است که به کاربران امکان میدهد به بخشهای مختلف محتوای اپلیکیشن بروند، در آن گردش کرده و از آنها خارج شوند. کامپوننت Navigation جتپک از یک کلیک ساده دکمه تا الگوهای پیچیدهتر از بیل نوارهای ناوبری و منوهای ناوبری اپلیکیشن به پیادهسازی ناوبری کمک میکند.
گوگل در نسخه 2.3 از Navigation امکان پشتیبانی از ماژولهای قابلیت دینامیک را فراهم ساخته است که امکان دانلود بخشهای مختلف اپلیکیشن را بسته به نیازهای کاربران فراهم ساخته است. این امر موجب کاهش چشمگیری در اندازه دانلود اپلیکیشن شما میشود. یکپارچهسازی کامپوننت ناوبری در اپلیکیشن امکان ناوبری به این ماژولها را به طرزی فراهم میُسازد که گویی بخشی از APK پایه هستند. تنها کاری که باید بکنید این است که فرگمانهای خود را با همان ماژول حاشیهنویسی (annotate) کنید.
بنابراین کتابخانه Navigation از دانلود کردن در صورتی که برای رفتن به صفحه بعد ضروری باشد، پشتیبانی میکند. به علاوه چند بهبود دیگر نیز در مورد قابلیت Deep Linking در Navigation انجام یافته است. اکنون میتوانید به سادگی به پارامترهای کوئری دسترسی داشته باشید، اکشنهای سفارشی ارائه کنید و نوعهای meme را تعیین کنید.
در نهایت در Navigation 2.3 اکنون هر صفحه اپلیکیشن یک NavBackStackEntry دارد که امکان دسترسی به همان حالت آن مدخل را فراهم میسازد. برای این که مطمئن شویم نتایج در زمان تغییر یافتن پیکربندیها یا پردازش آنها، کامپوننت Navigation از کلاس خاصی برای ارسال دادههای بین صفحهها استفاده میکند.
فرگمانها میتوانند با استفاده از BackStackEntry قبلی به savedStateHandle فرگمان قبلی دسترسی پیدا کنند. زمانی که دستگیره savedStateHandle را از مدخل قبلی به دست آوردید، میتوانید همان مقدار را از SavedState مربوط به currentBackStackEntry به دست آورید و مقدار مورد نظر را بدون LiveData مشاهده کنید. به این ترتیب مشاهده به صورت یک آگاهی Lifecycle نگریسته میشود زیرا اینک از SavedState استفاده میکنیم که حتی در صورت ریاستارت شدن اپلیکیشن بین این دو صفحه نیز کار میکند.
سخن پایانی
جتپک اندروید مجموعهای از کتابخانهها، ابزارها و راهنماییها برای توسعه اپلیکیشنهای پیشرفته اندروید است. در حال حاضر چهار دسته از کاربردها از جتپک استفاده میکنند که شامل معماری، UI، رفتار و شالوده هستند. در طی سالهای اخیر گوگل بهبودهای زیادی روی این کتابخانه صورت داده است. در این مقاله برخی از جدیدترین قابلیتها و بهبودهایی که در طی ماههای اخیر روی کتابخانه جتپک اندروید اجرا شده است را مورد بررسی قرار دادیم.