این چهارمین قسمت از سری مقالات " آموزش کاربردی شبکه در اندروید " است که ما میخواهیم در مورد لایه شبکه با دید متفاوتی صحبت کنیم
- بخش اول – Http و لایه شبکه
- بخش دوم – TLS, Certificates, Pinning
- بخش سوم – احراز هویت و رهگیرها(interceptors)
- بخش چهارم – عملکرد، افزونگی و همزمانی
- بخش پنجم – تست و ادغام
این قسمت چهارم از این سری از مقالات "آموزش کاربردی شبکه در اندروید" است، که قصد داریم در مورد افزونگی، همزمانی، برخی از قسمتهای کوروتین و عملکرد در okhttp بحث کنیم.
افزونگی
افزونگی شبکه هنر اضافه کردن موارد اضافی از دستگاهها و خطوط ارتباطی است، تا مطمئن شوید همیشه در دسترس هستیم و خطر خرابی و زمان را کاهش میدهیم.
تصور کنید شما یک مرکز داده در ایالات متحده و یک کاربر در اروپا دارید، اگر کاربر وارد برنامه شما شود، ما باید یک مرکز داده ثانویه داشته باشیم تا مطمئن شویم که درخواست شما را طولانی نمیکند، افزونگی مکانیسم نگه داشتن چندین مرکز داده به صورت همزمان است.
چند معماری اصلی در مدیریت افزونگی وجود دارد، و این ممکن است که وظیفه مهندس موبایل نباشد اما برای رسیدگی به خطاها مهم است.
در دسترس بودن
وظیفه یک معمار سیستم نرمافزاری است که از خوشههای سرور استفاده کند و آنها را رصد کند و بر روی آنها پروتکلهای خرابی را قرار بدهند. اگر مشکلی در یک سرور رخ بدهد، سرورهای پشتیبان برنامههایی را که در سرورهای ناموفق در حال اجرا بودند را تحویل گرفته و دوباره راه اندازی میکنند. مشکلی که در اینجا وجود دارد این است که اگر آنها دوباره نتوانند بوت شوند، شما با خطا مواجه میشوید.
تحمل خطا
یک معماری سخت افزاری است که برنامههایی را که در دو یا چند سیستم یکسان که بطور همزمان اجرا میشوند را منعکس میکند. اگر مشکلی در سیستم اولیه رخ دهد، سیستم پشتیبان بدون از دست دادن سرویس کار خود رابر عهده میگیرد، این معماری در صورت داشتن هر مقدار خرابی کار میکند، اما عملکرد آن عالی نیست ولی بسیار نزدیک است.
در اینجا همه چیز ممکن است اشتباه رخ دهد، داشتن برنامهای برای افزونگی، کلید مهمی برای داشتن استراتژی بررسی زیرساختهای موجود است. به هرحال در صورت داشتن چیزی که باعث تداخل در عملکرد شود یا خطای انسانی که باعث قطع ارتباط اینترنت شود، حتی گستردهترین معماری نیز به هیچ وجه کار نخواهد کرد.
دادهها همه چیز یک برنامه هستند، بنابراین باید از این دادهها به طور منظم backup تهیه شود تا در مراکز مختلف داده با echo مواجه نشیم، یک استراتژی داده خوب باید به نقشه برداری از بهترین مکانها برای تکثیر و ذخیره داده بپردازد تا بتواند در صورت خرابی سایر سیستمها و دیگر شبکههای افزوده شده به راحتی قابل دسترس باشد.
معمولاً مهندسان DevOps مسئول مراکز داده هستند، آنها آزمایشاتی را برای مطمئن شدن از یکپارچگی سیستمها و شبکه افزوده شده انجام میدهند. آنها میتوانند با قطع فیزیکی سخت افزار، اتصالات مختلف را آزمایش کنند تا اطمینان حاصل شود که خرابی مورد انتظار اتفاق میافتد، این میتواند قبل از اینکه دیگران متوجه شوند به عیب یابی شبکه کمک کند، به عنوان یک مهندس موبایل وظیفه دارم که روزانه بررسی کنم که آیا در برنامهای که در حال ساخت آن هستم همه چیز خوب است یا نه، زیرا کار ما به عنوان یک توسعهدهنده هنگامی که کد خود را ادغام میکنیم به پایان نمیرسد، بلکه زمانی به پایان میرسد که کاربران تجربه خوبی از برنامه ما داشته باشند.
همزمانی
همزمانی در اندروید(حداقل برای شبکه) به دو قسمت انتقال داده و تردها بستگی دارد. مورد اول، بطور خاص در مورد فریمهایی که در HTTP/2 به عنوان یک واحد انتقال در لایه پروتکل معرفی شدهاند است و شامل یک هدر به دنبال یک بسته است. هر فریم یک سری بیت است که بطور کلی متشکل از بیتهای هماهنگ سازی فریم، paload و یک توالی بررسی فریم است.
برای مورد دوم ما به API محاسباتی قابل تعلیق اشاره میکنیم، به این معنی که شما میتوانید دو انتخاب داشته باشید، تردهای مسدود کننده و غیر مسدود کننده.
تردها
در برنامههای تلفن همراه تعداد زیادی ترد برای فایلها، اتصال به شبکه، برای کارهای سنگین و حتی UI وجود دارد. که مهمترین قسمت این مجموعه نیز است.
برای لایه شبکه باید مطمئن شویم که درخواستها در ترد IO انجام میشوند، برای مثال اگر درخواست به یک API ناموفق باشد نمیتوانیم خطا را در برنامه هندل کنیم.
اگر برنامه درخواستی را به سرور بفرستد، ما باید ترد آن را برای پاسخگویی زنده نگه داریم، حتی اگر ناموفق باشد، باید آن ترد را تا زمانی که همه بایتها وارد میشوند، جریان بسته میشود، و یا اینکه timeout اتفاق میافتد نگه داریم، اگر فریم بمیرد نمیتوانیم هیچ فریمی از فریمهای رسیده را کنترل کنیم، اگر ترد مرده است باید ترد درخواست کننده را زنده نگه داریم که این به عنوان ترد Application/Writer شناخته میشود.
این مورد با سوکت اتفاق نمیافتد، وقتی دادهها را مداوم از سرور دریافت میکنید، تردی که پاسخ را هندل میکند ممکن است زنده نباشد، اما سرور داده را ارسال میکند و برنامه خواندن و نوشتن را انجام میدهد، و احتمالاً کارهای مربوط به presentation از بین خواهد رفت و تردی که دادهها را دریافت میکند ممکن است در دسترس نباشد و باید دادهها را بافر کنیم. هنگامی که view برنامه آماده شد، دادههای وارد شده را دریافت میکنیم و لایه اپلیکیشن view را پر میکند. بنابراین ما برای هر سوکت یک ترد اختصاصی داریم که فقط فریمها را میخواند و آنها را ارسال میکند، این موضوع Reader Thread نامیده میشود، آنها پیچیده هستند، زیرا ما باید اطمینان حاصل کنیم که اتصال بنبست نمیشود، اگر این کار را انجام دهیم، میتوانیم کل عملیات حتی اتصال را متوقف کنیم.
POOLS(استخرها)
در پایگاه داده و درخواست شبکه ما میتوانیم چندین اتصال داشته باشیم، این مجموعه به عنوان استخر اتصالات شناخته میشود، آنها ساخت و تعاملات اتصالات را مدیریت میکنند، معمولاً این یک کار گران قیمت است، به عنوان مثال در OkHttp کتابخانه برای جلوگیری از تاخیر از اتصال موجود استفاده مجدد میکند، بسته به نسخه Http ممکن است تفاوتهایی در تاخیر استفاده از اتصال داشته باشیم.
وظیفه اصلی OkHttpClient این است که همه منابع را به همه اتصالات باز بشناسد، زیرا برای رسیدگی به درخواستهای بعدی دوباره استفاده میشود.
کوروتینها
همزمانی در اندروید به این معنی است که تردها را برای انجام کارها مدیریت کنید، بدون اینکه اقدامات کاربر را مسدود کنید و برای چیزی که کاربر میبیند محدودیت ایجاد کنید، بیایید این نمودار را مرور کنیم.
به عنوان مثال کاربر اسکرول یا کلیک میکند و ما باید دادهها را از سرور دریافت کنیم، در این زمان ترد UI باید برای کاربر در دسترس باشد، و دریافت دادهها از سرور باید در یک ترد ثانویه که میتواند منتظر پاسخ دادهها باشد ایجاد شود، پس از دریافت پاسخ، میتوانیم دادهها را به ترد UI انتقال دهیم، و کاربر به تعامل با برنامه ادامه دهد.
فرایند داشتن ترد ثانویه را میتوان به روشها مختلفی مدیریت کرد، به عنوان مثال RxJava که با استفاده از Observable به ما در ساخت برنامه ناهمگام و مبتنی بر رویداد کمک میکند، اما امروز میخوایم در مورد کوروتینها صحبت کنیم که یک الگوی طراحی همروند است که میتوانید در اندروید از آن استفاده کنید، تا کدی که به صورت غیر همزمان اجرا میشود ساده کنید.
اغلب کوروتین یک ترد سبک وزن است. آنها با یک context builder از یک scope خاص راهاندازی میشوند. در کد بالا ما در حال راهاندازی یک کوروتین جدید در GlobalScope هستیم، به این معنی که طول عمر کوروتین جدید فقط به طول عمر کل برنامه محدود میشود.
در اندروید میتوانید موارد زیر را داشته باشید:
- فضای CoroutineScope برای مدیریت یک یا چند کوروتین مربوط به مهم، هنگامی که دیگر از کوروتین استفاده نمیشود این scope باید لغو شود، ما نمیتوانیم آن را زنده نگه داریم این برای RxJava نیز صدق میکند، اگر این کار را انجام ندهیم مشکلات زیادی در نشت حافظه خواهیم داشت.
- Launch تابعی است که یک کوروتین ایجاد میکند و عملکرد بدنه آن را به coroutine dispatcher میسپارد.
- Dispatchers.IO نشان میدهد که این کوروتین باید بر روی تردی که برای عملیات IO اختصاص داده شده است اجرا شود، dispatcherهای بیشتری مانند Main, Default, Undefind وجود دارد، همه آنها برای موارد مختلف از cpu گرفته تا run test وجود دارند.
ما قصد اضافه کردن کوروتین به اپلیکیشن شما را نداریم، هر سوالی در این باره دارید در زیر این پست بپرسید، اما آنها تقریباً از این الگوی تعلیق پذیری پیروی میکنند.
- ما قبلاً نکاتی را درباره launch گفتهایم، اما همچنین مهم است بدانیم این تابع مسیر اصلی آغاز فرایند خواهد بود.
- Suspend کلمه کلیدی برای توابع قابل تعلیق است که میتواند یک درخواست شبکه باشد، این درخواست شبکه به یک سرور میرود و کوروتین منتظر پاسخ خواهد بود.
- پاسخ درخواست در داخل کلاس Response<T> میرسد که میتواند موفق یا ناموفق باشد (SocketTimeOut, IOException, …).
- با Deliver ما کاری را انجام میدهیم که نتیجه آن ممکن است مربوط به UI باشد یا نباشد، اما این تقریباً روند کوروتین را به پایان میرساند.
کارایی
عملکرد در اندروید همه چیز است، حتی به jvm نیز مربوط میشود، موارد جزئی مانند لغو نکردن کوروتین پس از استفاده از آن میتواند باعث مشکل در حافظه، cpu، و حتی فرایند ایجاد OkHttpClient میتواند زمان زیادی را به ما تحمیل کند.
ما باید OKHttpClient خود را ایجاد کنیم و فقط یک Client در طول عمر برنامه داشته باشیم، زیرا هر بار که نمونه جدیدی از آن ایجاد میکنیم، یک استخر اتصال جدید، cache، interceptor جدید نیز ایجاد میکنیم، این ما را به سمت استفاده ناکارآمد از حافظه و منابع سوق میدهد و احتمالاً منجر به هدر رفتن زیاد حافظه در برنامه میشود.
برای در دسترس نگه داشتن آن ما باید ترفندهایی مانند اضافه کردن Singleton با استفاده از تزریق وابستگی را برای جمعآوری آسان آن انجام دهیم، ما همچنین میتوانیم اطمینان حاصل کنیم که استفاده از برخی الگوهای delegation مانند lazy زمان زیادی نمیبرد.
این همه مباحث مربوط به این قسمت بود. برای قسمت آخر، در مورد Testing، Mock و Integration برای درخواستهای شبکه بحث خواهیم کرد.
دیدگاه و پرسش
در حال دریافت نظرات از سرور، لطفا منتظر بمانید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید