استفاده صحیح از Analytics در کاتلین برای اندروید – از صفر تا صد


در این مقاله نشان میدهیم که چگونه میتوانید و باید کتابخانههای analytics را از کد منطق تجاری اپلیکیشن جدا کنید تا بتوانید به طرز مؤثری سرویسها و رویدادهای analytics را به صورت آنی به اپلیکیشن اضافه کرده یا حذف کنید. به این ترتیب با روش استفاده صحیح از Analytics در کاتلین برای اندروید آشنا میشویم.
کد کاملاً تزویج یافته
استفاده از analytics در اپلیکیشنهای اندروید در اغلب موارد کار دشواری به حساب میآید و علت آن این است که روش درستی برای اجرای این کار استفاده نمیشود. برای مثال افراد، چندین رویداد analytics را در صفحهها و سرویسهای مختلف با استفاده از SDK به نام Answers مربوط به Fabric اضافه میکنند. تابعهای مختلف SDK در صفحههای متفاوت اپلیکیشن پراکنده میشوند و معنی آن این است که اگر بخواهیم کتابخانه Fabric را حذف کنیم، باید به تکتک اکتیویتیها، فرگمانها، سرویسها سر بزنیم و آنها را تکتک ویرایش کنیم. همین موضوع در مورد افزودن سرویسهای تحلیلی دیگر نیز صدق میکند و باید تکتک موارد را به صورت دستی ویرایش کنیم.
برای مثال فرض کنید فراخوانیهای CustomEvent و فراخوانیهای ContentView را داریم که به صورت زیر در صفحههای مختلف اپلیکیشن پراکنده شدهاند:
1// Pre-Decoupling Code - inside Android Activity
2// event trigger
3Answers.getInstance().logCustom(CustomEvent("alarm_snoozed"))
4// content view trigger
5Answers.getInstance().logContentView(ContentViewEvent().putContentName("alarm_screen"))
اما یک پیادهسازی با تزویج سست مانند زیر بهتر است:
1// Desired Code
2// event trigger
3analytics.trackEvent(AlarmActionSnoozeEvent());
4// content view trigger
5analytics.trackContentView(AlarmActivityContentView())
ما صرفاً میخواهیم اکتیویتی یا Presenter در مورد ابزار Analytics ما مطلع باشد. پرزنتر نباید به Fabric ،Flurry ،Firebase یا هر ابزار تحلیلی مشابه دیگر وابسته باشد. کافی است صرفاً از رویدادهای که ارسال میکند و کلاس اصلی analytics مطلع باشد.
طراحی دیسپچرها و رویدادها
در این بخش با شیوه اجرای کدی که در بخش قبلی دیدیم آشنا میشویم.
کلاس Analytics فهرستی از dispatchers نگهداری میکند و پارامترهای event که از صفحههای مختلف آمدهاند را به هر یک از آنها ارسال میکند. هر dispatcher روش خاص خود را برای مدیریت event پیادهسازی میکند، یعنی برای هر سرویس آنالایتیکز یک دیسپچر داریم. بدین ترتیب نخستین کاری که باید انجام بدهیم ساختن یک اینترفیس dispatchers است که بتواند events و contentViews را مدیریت کند:
1nterface AnalyticsDispatcher {
2
3fun trackContentView(contentView: AnalyticsContentView)
4
5fun trackCustomEvent(event: AnalyticsEvent)
6
7}
گام بعدی راهاندازی اینترفیسهایی برای ContentViews و Events است. میدانیم که رویدادها یک نام دارند و همچنین ممکن است پارامترهایی داشته باشند، در حالی که ContentViews با توجه به مقاصد این مقاله تنها نام دارند.
1interface AnalyticsEvent : BaseAnalyticsEvent {
2
3 fun getParameters(): Map<String, String> {
4 // default empty map implementation
5 return emptyMap()
6 }
7
8 fun getEventName(): String
9}
10interface AnalyticsContentView : BaseAnalyticsEvent {
11
12 fun getViewName(): String
13
14}
هر دو اینترفیس فوق اینترفیس BaseAnalyticsEvent را بسط میدهند که در ادامه به بررسی آن خواهیم پرداخت. فعلاً نخستین مثال event خود را پیادهسازی میکنیم:
1class AlarmActionSnoozeEvent : AnalyticsEvent {
2 override fun getEventName() : String {
3 return "alarm_snoozed"
4 }
5
6 // could also override the getParameters() function...
7}
اکنون میتوانیم به صورت امنی یک وهله از AlarmActionSnoozeEvent را به کلاس analytics خود ارسال کنیم، اما هنوز کاری انجام نمیدهد زیرا هیچ یک از dispatcher-ها را پیادهسازی نکردهایم. فعلاً تنها یک dispatcher پیادهسازی شده داریم:
1class AnswersDispatcherImpl : AnalyticsDispatcher {
2
3 override fun trackCustomEvent(event: AnalyticsEvent) {
4 Answers.getInstance().logCustom(event.createAnswersEvent())
5 }
6
7 override fun trackContentView(contentView: AnalyticsContentView) {
8 Answers.getInstance()
9 .logContentView(contentView.createAnswersEvent())
10 }
11}
تابع createAnswersEvent به طور خودکار درون اینترفیسهای Event و ContentView قرار گرفته چون در BaseAnalyticsEvent اعلان یافته که هر دو را بسط میدهد. آن را هماینک ایجاد میکنیم:
1interface BaseAnalyticsEvent {
2 fun createAnswersEvent(): Any
3}
توجه کنید که ما یک نوع Any بازگشت میدهیم و از این رو میتوانیم در ادامه تابع را با انواع متفاوتی override کنیم که الزام Answers SDK است. به کد زیر دقت کنید:
1import com.crashlytics.android.answers.CustomEvent
2import com.crashlytics.android.answers.ContentViewEvent
3interface AnalyticsEvent : BaseAnalyticsEvent {
4 // previous functions from before...
5 override fun createAnswersEvent(): CustomEvent {
6 return CustomEvent(this.getEventName()).apply {
7 getParameters().forEach {
8 putCustomAttribute(it.key, it.value)
9 } }
10 }
11}
12interface AnalyticsContentView : BaseAnalyticsEvent {
13 // previous functions from before...
14
15 override fun createAnswersEvent(): ContentViewEvent {
16 return ContentViewEvent().putContentName(this.getViewName())
17 }
18}
کلاس Analytics
اکنون کلاسی میسازیم که مسئول همه این موارد است. سازنده کلاس Analytics باید پارامتری داشته باشد که فهرست Dispatchers را در خود جای میدهد. این کلیدواژه vararg است.
1class Analytics(private vararg val dispatchers: AnalyticsDispatcher) {
2fun trackEvent(contentView: AnalyticsEvent) {
3 // dispatch the event with every dispatcher
4 dispatchers.forEach { it.trackEvent(event) }
5}
6fun trackContentView(contentView: AnalyticsContentView) {
7 // dispatch the event with every dispatcher
8 dispatchers.forEach { it.trackContentView(event) }
9}
10}
آن را درون کلاس Application مقداردهی میکنیم.
1class App : Application() {
2 private lateinit var analytics: Analytics
3 override fun onCreate() {
4 super.onCreate()
5 analytics = Analytics(AnswersDispatcherImpl())
6 }
7}
مرحله پایانی
اکنون میتوانیم ابزار آنالایتیکز را که در ابتدای مقاله بیان کردیم فراخوانی کنیم. در گام بعدی نشان میدهیم که ایجاد ابزار آنالایتیکز دیگر تا چه حد آسان است. در این مثال از Flurry Analytics استفاده میکنیم:
1import com.flurry.android.FlurryAgent
2class FlurryDispatcherImpl : AnalyticsDispatcher {
3
4 override fun trackCustomEvent(event: AnalyticsEvent) {
5 FlurryAgent
6 .logEvent(event.getEventName(), event.getParameters())
7 }
8
9 override fun trackContentView(contentView: AnalyticsContentView){
10 FlurryAgent
11 .logEvent("contentView_" + contentView.getViewName())
12 }
13
14}
در این مورد نیز درون تابع onCreate مربوط به Application صرفاً Flurry dispatcher را به لیست دیسپچرها اضافه کردیم.
1// initiate the analytics with the different dispatchers
2analytics = Analytics(AnswersDispatcherImpl(), FlurryDispatcherImpl())
بدین ترتیب کار جداسازی ابزارهای تحلیلی پایان یافته و تنها کاری که مانده است پیادهسازی رویدادهای باقی مانده و فراخوانی شیء Analytics در مکانهای مختلف اپلیکیشن است.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامهنویسی اندروید
- مجموعه آموزشهای برنامهنویسی
- آموزش حلقه ها و تکرار در زبان برنامهنویسی کاتلین
- اسامی مستعار و کلاسهای inline در کاتلین — به زبان ساده
- سادهسازی کد کاتلین با Ktlint — راهنمای کاربردی
==