iOS App Developer
"اتصال به اینترنت برقرار نیست! تلاش مجدد" یک استراتژی کلی
در این مقاله قصد دارم یک راه حل کلی به جهت پیاده سازی روشی برای ارسال مجدد ریکوئست های fail شده بخاطر عدم اتصال به اینترنت ارائه بدم
من قصد دارم اینجا از RxSwift و Moya استفاده کنم (چرا که کار رو خیلی راحت تر کردن) تا ایده اصلی رو به شما منتقل کنم و بعد شما میتونید به هر نحوی که دوست داشتین پیاده سازیش کنید.
- ماجرا چیه؟
ماجرا از این قراره که ما توی خیلی از برنامه هایی که می نویسیم ریکوئست هایی رو به سرور ارسال کنیم و ممکنه این ریکوئست ها بخاطر عدم اتصال به اینترنت fail بشن.
در این جور مواقع باید پیغامی رو با متن و ظاهری مناسب به کاربر نمایش بدیم و مشکل رو بهش یادآوری کنیم و در ادامه هم امکان تلاش مجدد و یا نادیده گرفتن این پیغام رو بهش بدیم.
اما چطوری باید همه ریکوئست هایی که توی اون لحظه ارسال شدن و صرفا بخاطر عدم اتصال به اینترنت fail شدن رو دوباره ارسال کنیم؟ اینجاست که RxSwift و operator های خفنش وارد میشن
در زیر بهتره یک نگاه کلی نسبت به کاری که قراره انجام بدیم داشته باشیم:
لایه presentation و network یک رفرنس از آبجکتی از جنس GenericNetworkErrorRetryStrategy رو دارن. در واقع این دو لایه به واسطه یک آبجکت مشترک از کلاسی که GenericNetworkErrorRetryStrategy رو پیاده سازی کرده باهم تعامل دارن
با کمک moya یک لایه ساده برای api هامون ایجاد کردیم که خیلی سادست و نیاز به توضیحی نداره:
استراتژی ما
اینجا یک protocol به اسم GenericNetworkErrorRetryStrategy داریم که در ادامه پیاده سازیش میکنیم اما فعلا فقط قراره بدونیم کاربرد پراپرتی ها و متد هاش چیه:
۱) این Observable یک مقدار از جنس boolean رو emit میکنه و قراره در لایه network ازش استفاده بشه. یک مثال ساده: زمانی که کاربر روی دکمه تلاش مجدد (در لایه presentation) کلیک میکنه این observable مقدار true رو emit میکنه و در زمانی که دکمه cancel کلیک میشه مقدار false رو.
۲) از این Observable در لایه presentation استفاده میشه و زمانی که یک ریکوئست fail میشه یکی از case های تعریف شده در Api رو emit میکنه. تا بدونیم به طور دقیق کدوم یکی از ریکوئست ها ناموفق بوده(توی این مقاله از این مورد استفاده نمیکنیم).
۳) همونطور که از اسمش مشخصه وضعیت نمایش پیامی مبنی بر "عدم اتصال به اینترنت" رو emit میکنه و در لایه presentation قراره بهش subscribe انجام بشه.
۴) این متد در لایه Network مورد استفاده قرار میگیره و زمانی که ریکوئستی fail بشه و دلیلش عدم اتصال به اینترنت باشه بلافاصله صدا زده میشه.
۵ و ۶) این دو متد در لایه presentation مورد استفاده قرار میگیرن و زمانی که کاربر روی یکی از دکمه های retry یا cancel کلیک کنه صدا زده میشن
خب حالا که با این protocol آشنا شدیم بریم به ساده ترین نوع ممکن پیاده سازیش کنیم:
به کمک کلاس PublishRelay در فریم وورک RxCocoa پراپرتی ها رو مقدار دهی کردیم.
بعد از اینکه متد ها رو مرور کردید میریم تا ببینیم لایه های network و presentation چطوری قراره از این کلاس استفاده کنن تا بتونن باهم در تعامل باشن.
- لایه Presentation
ما یک کلاسی فرضی به نام Application رو در نظر گرفتیم (این میتونه AppDelegate برنامه شما باشه) که در لایه presentation قرار داره و قراره که پیغام عدم اتصال به اینترنت رو به کاربر نمایش بده و همچنین اکشن های retry و cancel رو به واسطه رفرنسی که از آبجکتی از جنس GenericNetworkErrorRetryStrategy داره به لایه Network منتقل کنه.
توجه کنید که ما تنها یک instance از کلاس GenericNetworkErrorRetryStrategyImpl ایجاد میکنیم و در لایه های presentation و network اینجکت میکنیم.
- لایه Network
در زیر یک پیاده سازی ساده از پروتکلی که بالاتر تحت عنوان Networking معرفی کردیم رو میبینیم و خواهیم دید این کلاس چطوری از GenericNetworkErrorRetryStrategy استفاده خواهد کرد:
همچنین میتونید همین پیاده سازی رو در یک Plugin/Interceptor (که سر راه ریکوئست ها قرار میگیره) انجام بدید.
۱) در اینجا بررسی میکنیم تا اگر error از نوع عدم اتصال به اینترنت بود درخواست نمایش پیغام مناسب رو با صدا زدن متد makeNetworkErrorVisible ایجاد کنیم تا در لایه presentation نمایش این پیغام انجام شود.
۲) با استفاده از یکی از operator های مهم در RxSwift تحت عنوان retryWhen خواهیم توانست اکشنی را که کاربر در لایه presentation انجام میدهد عملیاتی کنیم و در صورتی که درخواست تلاش مجدد ارسال شد اصطلاحا resubscribe انجام شود تا ریکوئست fail شده مجددا ارسال شود.
همچنین میتونید در کلاس GenericNetworkErrorRetryStrategyImpl وضعیت اتصال به اینترنت رو همواره بررسی کنید و هر موقع اتصال برقرار شد متد retry رو صدا کنید تا اگر ریکوئستی fail شده به طور خودکار مجددا ارسال بشه.
نتیجه گیری
بجای اینکه توی قسمت های مختلف در لایه presentation درگیر هندل کردن مشکلات این چنینی و نوشتن کد های تکراری باشیم میتونیم با پیاده سازی همچین روش هایی هندل کردن این مشکل رو به یک کلاس مجزا بسپاریم تا viewModel ها یا Controller ها درگیری با این مسئله نداشته باشن و روی تسک های خودشون تمرکز کنن.
امیدوارم تونسته باشم چیزی که باید رو به شما هم منتقل کنم. اگر جایی رو متوجه نشدید و واستون مبهم بود حتما کامنت کنید. شایم من بد نوشته باشم یا منظورم رو به بهترین شکل منتقل نکرده باشم.
در نهایت این الگو رو میتونید کامل تر و شخصی سازی تر کنید و ارور های دیگه ای مثل 401,403, 500 ,.... رو هندل کنید.
مطلبی دیگر از این انتشارات
بهینه سازی سرعت gradle
مطلبی دیگر از این انتشارات
معرفی و پیاده سازی دیزاین پترن سینگلتون در اندروید
مطلبی دیگر از این انتشارات
راه های افزایش مهارت های برنامه نویسی اندروید (قسمت 2)