x تبلیغات
مقالات تخصصی طراحی اپلیکیشن در مشهد

Garbage Collector در دارت

 

 
Garbage Collector در دارت
Garbage Collector در دارت به طور Generational میباشد و مشمول دو مرحله میباشد: «جستجو فضای نو» (Young Space Scavenger) و «نماد‌گذاری برابر و گردآوری‌آوری‌کننده‌های طراحی اپلیکیشن در مشهد  روبشی» (Parallel Mark Sweep Collectors).
 
e
 
 
کلیک فرمایید
مجال‌بندی
جهت معدود‌خیس کردن تأثیرهای «توده آشغال» (Garbage Collection) روی نرم افزار و کوشش رابط کاربری، Garbage Collector قلاب‌هایی به موتور فلاتر تولید می‌نماید که هنگامی موتور تشخیص دهد نرم افزار بدون شغل میباشد و استفاده کننده تعاملی با آن ندارد، آغاز به عمل می‌نماید. براین اساس فرصتی در دست Garbage Collector قرار می گیرد تا فازهای جمع آشغال خویش را سوای تولید اشکالی در کوشش نرم افزار اعمال نماید.
 
Garbage Collector می تواند فشرده‌سازی لغزشی را نیز در طول این برهه زمانی‌های بیکاری اعمال نماید و براین اساس سربار خاطر را با کاستن از تکه تکه شدن (Fragmentation) یاد کم کند.
 
مرحله جستجو فضای تازه
این مرحله برای تمیز‌سازی اشیای با قدمت کوتاه مانند ویجت‌های بی‌شرایط به کارگیری میگردد. با این که‌این مرحله مسدودکننده میباشد؛ ولی بسیار سریع‌خیس از مرحله دوم نشان‌گذاری/روبش میباشد. مرحله دوم هنگامی یار با فرصت‌بندی اعمال گردد سبب ساز تولید تاخیر‌هایی در موادتشکیل دهنده بصری نرم افزار در حین جاری ساختن میگردد.
 
اشیاء بر پایه ی ماهیت خویش در فضای پیوسته‌ای از خاطر اختصاص می یابند و وقتی که شی ءها ساخت‌و‌ساز می شوند به فضای مو جود آتی یاد اختصاص می یابند تا وقتیکه تک تک فضای اختصاص‌یافته مالامال خواهد شد. دارت از اختصاص اشاره‌گر bump برای اختصاص سریع در فضای نو استعمال می‌نماید که موجب ارتقا سرعت قابل‌مراعات‌ای درین روند میگردد.
 
فضای تازه هنگام اختصاص یافتن اشیای نو مشتمل بر دو نصفه میباشد که به اسم نیم گوشه و کنار شناخته می شوند. هر توشه صرفا یک نصفه به کار گیری می گردد. در حالی که یک نصفه فعال میباشد، نصفه دیگر غیر فعال باقی میماند. اشیای تازه در نصفه فعال اختصاص می یابند و هنگامی که نصفه دیگر لبریز گردد، اشیای زنده از نصفه فعال به نصفه غیر فعال نسخه برداری میشوند و اشیای مرده نادیده گرفته می گردند. آن گاه نصفه غیر فعال، فعال می گردد و این پروسه تکرار میگردد.
 
برای انتخاب این که شی ءها زنده یا این که مرده می‌باشند، Collector از اشیای ریشه مانند متغیرهای پشته شروع می‌نماید و آنچه را ارجاع داده‌اند نظارت می‌نماید. آن‌گاه اشیای ارجاع یافته را جابجایی میدهد. درین مرحله نظارت می‌نماید که اشیای ارجاع یافته به کجا اشاره می‌نمایند و این اشیای ارجاع یافته را جابجایی میدهد. این پروسه تا‌وقتی‌که کلیه اشیای زنده جابجایی یابند تداوم می یابد. اشیای مرده دیگر هیچ ارجاعی ندارند و از این رو در آنجا باقی میمانند و در پی زمانی garbage collection آجل چهره بدهد، اشیای زنده روی آنها نسخه برداری می گردند.
 
 
Garbage Collection در مرحله جستجو فضای جدید
آرم‌گذاری برابر و روبش هم‌زمان
هنگامی که شی ها به قدمت معینی برسند به فضای یاد جدیدی جابجایی می یابند که از سوی collector نسل دوم یعنی mark-sweep مدیر می شود.
 
تکنیک توده آشغال در‌این قسمت دو مرحله دارااست: آغاز گراف شیء پیمایش میشود و اشیایی که هنوز گزینه به کار گیری می باشند نشان‌گذاری می شوند. در طول مرحله دوم، مجموع یاد نسخه برداری میشود و هر شیئی که آرم‌گذاری نشده میباشد حذف می گردد. بعد از آن کلیه فلگ‌ها منزه می گردند.
 
این صورت از جمع آشغال در مرحله نماد‌گذاری موجب انسداد می گردد، زیرا هیچ تغییری در یاد نمی‌تواند صورت بدهد و نخ رابط کاربری مسدود می گردد. این عده، فراوانی یه خرده دارااست و اشیای با قدمت کوتاه عموماً از سوی «جستجو فضای نو» مدیر می‌گردد؛ البته مواقعی وجود دارا هستند که سیستم مجال اجرای دارت بایستی آویزان خواهد شد تا این نوع جمع آشغال اعمال خواهد شد. با اعتنا به بضاعت فلاتر برای فرصت‌بندی توده، تأثیر این حالت اندک خواهد بود.
 
قابل ذکر میباشد که چنانچه یک نرم افزار از «فرضیه نسل ضعیف» تقلید نکند، یعنی اکثر اوقات اشیای آن در سن نادر نمیرند، دراین‌صورت این صورت از توده به مراتب بیشتر صورت میدهد. با دقت به طرز پیاده‌سازی ویجت‌های فلاتر این احتمال اندک میباشد؛ البته نکته‌ای میباشد که بایستی در خیال داشت.
 
ایزولت‌ها (Isolates)
قابل ذکر میباشد که ایزولت های فلاتر خاطر هیپ منحصر به فرد خویش را دارا هستند که غیر وابسته از همدیگر میباشند. از‌آنجا‌که هر ایزولت در یک نخ منقطع انجام می‌گردد، رویدادهای توده آشغال برای هر ایزولت تأثیری روی تلاش ایزولت های دیگر نخواهد داشت. استعمال از ایزولت ها جهت دوری از انسداد رابط کاربری و معدود کردن توشه پردازش شغل‌های هنگفت مطلوب میباشد.
 
صحبت آخری
در‌این نوشته به پژوهش نحوه استعمال از Garbage Collector قوی برای کاستن از تأثیرهای انسدادی روی داد عده آشغال در نرم افزار‌های فلاتر پرداختیم. بدین ترتیب نباید از Garbage Collector بترسید زیرا به بهبود کارکرد نرم افزار شما بسیار یاری می‌نماید.
 

تنظیمات پراکسی

 

 
تنظیمات پراکسی
در مشابه‌ساز اندروید، نرم افزار Settings را گشوده فرمائید.  طراحی اپلیکیشن در مشهد به مسیر ذیل بروید:
 
Network & internet >Wi-Fi >AndroidWifi
و بعد روی دکمه Edit بزنید.
 
 
ادامه تنظیمات پراکسی
آیتم Proxy را روی Manual قرار دهید. آیتم Proxy hostname و Proxy port را نیز بر همین شالوده تهیه نمائید. مقدار مورد Bypass proxy for را به طور 127.0.0.1,localhost تهیه و تنظیم کرده و Save را کلیک فرمائید.
 
در مشابه‌ساز اندروید، نرم افزار گوگل کروم را گشوده نمایید. به نشانی پایین بروید:
 
https://d1ahtucjixef4r.cloudfront.net/Exponent-1.14.0.apk
و فولدر APK را دانلود و نصب نمایید. در شکل نیاز، مجوزهای سیستم را به‌این مراد تهیه و تنظیم فرمایید.
 
در فضا پیشرفت Expo آیتم ...Open existing project را تعیین کرده و در پی نرم افزار React Native را گزینش کنید. به دنبال آیتم Expo XDE را تعیین و بعد Install Android App را کلیک فرمائید.
 
 
 
به این ترتیب APK که پیش از اینً نصب گردیده بود، کنسل نصب می‌گردد و با جدیدترین ورژن جایگزین می گردد. از آن‌جا که کوشش کرده‌اید، جدیدترین ورژن را سوای کنسل نصب ورژن دیرین، نصب نمایید در شرایطی که که مبادرت به کنسل نصب ورژن سابق ناموجود بکنید با خطایی مواجه می شوید.
 
براین اساس پیام «!Installation Success» ظواهر نمیشود و آیکون چرخان در حین کامل شدن شدن نصب به آسانی ناپدید میگردد. همچنان که در دور و بر توسعه و گسترش Expo می باشید، روی آیکون پیکربندی به صورت چرخ‌دنده کلیک فرمائید و آنگاه Host را به localhost تغییر تحول دهید.
 
 
 
در مشابه‌ساز اندروید پیکربندی مشابه‌ساز را از روش منوی سه‌نقطه (...) در سمت راست پنجره گشوده فرمایید.
 
 
 
برگه Snapshots را کلیک کرده و آنگاه دکمه Take Snapshot را کلیک فرمایید. براین اساس مطمئن می‌شویم که شغل ما تا به اینجا تمیز نخواهد شد. تنظیمات ما می بایست در حال حاضر در وضعیت کاری باشد.
 
قدم سوم: اجرای نرم افزار
در اندروید استودیو آیتم Tools و آن‌گاه AVD Manager را تعیین نمایید. در سمت راست، دکمه سبز رنگ پخش را بزنید. به این ترتیب مشابه‌ساز استارت به شغل می‌نماید. درپی میتوانید پنجره‌های AVD Manager و Android Studio را ببندید تا فقط مشابه‌ساز گشوده بماند.
 
 
کلیک نمایید
در خط دستور امر yarn android را در دایرکتوری ریشه پروژه React Native خویش اعمال فرمائید. در مشابه‌ساز اندروید، نرم افزار Expo را گشوده نمایید. برای یافتن نرم افزار Expo، روی نوار جستجوی گوگل به سمت بالا درگ نمایید و آن‌گاه Expo را بزنید.
 
 
 
شما میتوانید موشواره خویش را روی نرم افزار Expo کلیک کرده و نگهدارید تا آن را برای استعمال‌های آتی و تسهیل دسترسی روی دسکتاپ دستگاه اندرویدی قرار دهید.
 
در نرم افزار Expo روی آیکون Explore کلیک نمائید.
 
 
 
آیکون کاوش را زده و عبارت exp://localhost:19000 را وارد فرمایید و یا این که میتوانید URL-ی را که از سوی yarn android ارائه گردیده است را وارد فرمائید.
 
 
 
روی عبارت Tap to attempt to open project at exp://localhost:19000 کلیک فرمائید. فعلا می بایست نرم افزار React Native خویش را ببینید. پوشه‌های پروژه را در ویرایشگر متنی متبوع خویش دستکاری فرمائید تا از قابلیت لود دوباره آنی فایده‌مند گردید.
 
صحبت آخری
شما میتوانید مشابه‌ساز را پین نمایید تا همواره فراتر از پنجره‌های دیگر ظواهر گردد. به این مراد در پیکربندی مشابه‌ساز (به عبارتی منوی سه‌نقطه در سمت راست پنجره) روی برگه Settings کلیک فرمائید. در صفحه General، سوئیچ Emulator always on top را فعال فرمائید. براین اساس به نقطه پایان این نوشته‌ی علمی می‌رسیم و امید داریم در انتهای تفحص آن، با شیوه اجرای نرم افزار‌های React Native روی «مشابه‌ساز اندروید» (Android Emulator) آشنا گردیده باشید و تنظیمات‌های مختلفی که به‌این مراد ما یحتاج میباشند را بشناسید.
 

مقداردهی اول با تأخیر (lazy Initialization)

 

 
مقداردهی اول با تأخیر (lazy Initialization)
مقداردهی با تأخیر (by lazy) در مواقعی که سرگرم پیاده‌سازی مشخصه‌های تنها-خواندنی هستیم که به طور با تأخیر در کاتلین ایفا میگردند موثر خواهد بود. by lazy { … } مقداردهی اول خویش را جایی اعمال میدهد که مشخصه نخستین دفعه استعمال می شود و خیر در طول طراحی اپلیکیشن در مشهد  اعلان کردن آن.
 
class Demo { val myName: String by lazy { "John" } }
 
مقداردهی نماید
مقداردهی نماید متغیرها به‌این معنا میباشد که بسط‌دهندگان پیش از دسترسی به متغیر آن را جایی در کد مقداردهی نخستین می‌نمایند.
 
class Demo { val myName: String by lazy { "John" } }
کلاس داده
ما به صورت مکرر کلاس‌هایی میسازیم که کاری به جز محافظت داده‌ها ندارند. در اینگونه کلاس‌هایی بعضا کارکردهای استاندارد غالباً به طور مکانیکی از داده‌ها مشتق میشوند. در کاتلین، این فعالیت در کلاس داده انجام می گردد و به طور داده‌ای نشانه‌گذاری می گردد.
 
data class Developer(val name: String, val age: Int)
هنگامی که یک کلاس به طور کلاس داده نشانه‌گذاری خواهد شد، نیاز وجود ندارد که تابع‌های پایین را مانند جاوا در آن پیاده‌سازی یا این که ساخت کنیم:
 
()hashCode
()equals
()toString
()copy
کامپایلر به طور اتوماتیک این مفاد را به طور داخلی ساخت می‌نماید و به این ترتیب کد تمیزتری خوا هیم داشت.
 
کلاس‌های مهر و موم گردیده
کلاس‌های مهر و موم گردیده برای اکران سلسله مراتب کلاس محدودشده به کارگیری می شوند که در آنان شیء یا این که مقدار صرفا یک نوع می تواند داشته باشد و از این رو با نوع ثابتی در سلسله مراتب مواجه هستیم. کلاس‌های مهر و موم گردیده به صورت مکرر در مورد ها مختلفی که می دانیم مقدار مفروضی دارنده فقطً مورد‌های محدودی میباشد، به کارگیری میشوند.
 
1sealed class Operation {
2 class Add(val value: Int) : Operation()
3 class Substract(val value: Int) : Operation()
4 class Multiply(val value: Int) : Operation()
5 class Divide(val value: Int) : Operation()
6 }
 
تابع‌های اکستنشن
تابع‌های اکستنشن در کاتلین به ما قابلیت و امکان می دهند که کارکرد یک کلاس را با اضافه کردن امکان‌های نو توسعه دهیم. این کلاس لزوماً نباید به ما وابستگی داشته باشد، بلکه میتواند کتابخانه فرد ثالث باشد و همینطور الزامی به ارث‌بری از کلاس نیست.
 
1fun Int.triple(): Int {
2 return this * 3
3 }
 
براین اساس به انتهای این نوشته‌علمی می‌رسیم و امید خواهیم داشت از آن سود کافی را برده باشید.
 
 
نوتیفیکیشن اندروید – اصول مقدماتی
استارت
برای شروع بایستی آغاز «فایربیس» (Firebase) را در نرم افزار خویش فعال‌سازی کنیم. بدین خواسته پیش از هر چیز می بایست یک پروژه در کنسول فایربیس (+) تولید کنیم. دقت داشته باشید که در حین کتابت این نوشته‌ی‌علمی، کشور‌ایران در فهرست کشورهای تحریم گردیده از سوی این خدمت قراردارد و برای دسترسی به آن بایستی از ابزارهای کمکی قابل قبولی استعمال نمایید.
 
 
کلیک نمایید
بعداز اجرای این مرحله قادر خواهیم بود نرم افزار خویش را به پروژه اضافه کنیم. به‌این خواسته روی پروژه خویش کلیک کرده و بعد روی دکمه + Add app کلیک کرده و درپی روی آیکون اندروید بزنید. در غایت می بایست برخی داده ها مقدماتی در ارتباط نرم افزار خویش وارد فرمائید و پوشه تنظیمات google-services.json را که برای اتصال نرم افزار به فایربیس ضروری میباشد را دانلود نمائید. در این زمینه درپی بیشتر توضیح خوا هیم بخشید. موقتاً همین امور در کنسول فایربیس کافی میباشد.
 
اتصال نرم افزار به فایربیس
فعلا به نصیب دیدنی داستان می‌رسیم. در پروژه اندروید پوشه build.gradle پروژه را گشوده نمائید. باور پیدا فرمایید که ریپازیتوری maven گوگل را در هر دو بلوک repositories و همینطور بلوک allprojects اضافه کرده‌اید و در ضمنً پلاگین Google Services را در تعلق‌ها به طور ذیل قرار داده‌اید:
 
1buildscript {
2 repositories {
3 google()
4 // ... Your other repo's go here
5 }
6
7 dependencies {
8 // ... Your other dependencies
9 classpath 'com.google.gms:google-services:4.2.0'
10 }
11}
12
13allprojects {
14 // ...
15
16 repositories {
17 google()
18 // ... Your other repo's go here
19 }
20}
مشاهده بی نقص کدها
پیرو به پوشه build.gradle نرم افزار راز می زنیم. همینطور تعلق Firebase Core را به پروژه اضافه کرده و پلاگین Google Services را در انتهای پوشه اضافه می کنیم:
 
1dependencies {
2 // ... Put your other dependencies here
3
4 implementation 'com.google.firebase:firebase-core:16.0.9'
5}
6
7apply plugin: 'com.google.gms.google-services' // Make sure you apply the plugin at the bottom of the file
 
عمل به طور تقریبً به نقطه پايان رسیده میباشد. به خیال و خاطر دارید که در مرحله پیشین پوشه تنظیمات google-services.json را از کنسول فایربیس دانلود کردیم. در حال حاضر بایستی این پوشه را در دایرکتوری app اضافه کنیم تا شغل تنظیمات فایربیس در نرم افزار به پایان برسد.
 
ارسال پیام
فعلا که نرم افزار خویش را به پروژه فایربیس اضافه کردیم، مهیا هستیم تا از خدمت پیام‌رسانی ابری خویش منفعت بگیریم. FCM که اختصاری برای «پیام‌رسانی ابری فایربیس» (Firebase Cloud Messaging) میباشد، استاندارد جدیدی برای نوتیفیکیشن به حساب می آید، زیرا گوگل مدد از GCM را متوقف کرده و آن را منسوخ کرده است. به این مراد کافی میباشد تعلق را به پوشه build.gradle نرم افزار اضافه کنیم:
 
1implementation 'com.google.firebase:firebase-messaging:18.0.0'
 
در شرایطی‌که میخواهید روی مدیر نوتیفیکیشن‌ها در پیش‌قضیه در اختیار گرفتن بیشتری داشته باشد، داده‌ها را باطن نوتیفیکیشن رئیس نمائید و یا این که میخواهید دستگاه‌های منفرد خاص یا این که دسته‌های معینی از اشخاص را هنگام ارسال نوتیفیکیشن مقصود‌گیری فرمائید، در این‌حالت به سرویسی نیاز دارید که FirebaseMessagingService را توسعه و گسترش دهد. ما آن را MessagingService.kt می‌نامیم:
 
1class MessagingService : FirebaseMessagingService() {
2
3 override fun onNewToken(token: String) {
4 // Sync your token with the backend here (optional)
5 }
6
7 override fun onMessageReceived(remoteMessage: RemoteMessage?) {
8 // Handle the incoming message here
9 }
10}
 
این دقیقاً به عبارتی جایی میباشد که یک پیام ورودی یا این که احتمالاً رفرش/ساخت توکن را رئیس می کنید. بنابراین می‌قدرت یک توکن را برای مثال در فراخوانی onNewToken به بک‌اند فرستاد و روی آن کارهایی اجرا بخشید یا این که یک نوتیفیکیشن در onMessageReceived تشکیل داد. به حافظه بسپارید که نیازی به ایجاد کرد یک نوتیفیکیشن برای اکران دادن نیست. این مورد را پیرو بیشتر توضیح می دهیم.
 
اینک که MessagingService خویش را ساخته‌ایم، بایستی آن را در مانیفست نیز تصویب کنیم:
 
1
2 3 android:name=".MessagingService"
4 android:exported="false">
5
6
7
8
 
اکنون حاذق هستیم نوتیفیکیشن ورودی خویش را از روش خدمت پیام‌رسانی خودمان مدیر کنیم.
 

تزریق تعلق در Koin – به لهجه معمولی

 

 
تزریق تعلق در Koin – به لهجه معمولی
فرض نمائید دو کلاس به اسم‌های A و B داریم که کلاس A با استعمال از متدی در کلاس B به آن اشاره می‌نماید. این عملیات مستقیماً یک تعلق میان دو کلاس ساخت و ساز می‌نماید، زیرا قبل از آماده داخل شدن قابلیت استعمال از سیاق یک کلاس در کلاس‌های دیگر مورد نیاز میباشد که دفعه‌ای از آن کلاس ساخت‌و‌ساز گردد. در این باره مورد نیاز میباشد که کلاس A دفعه‌ای از کلاس B را قبل از دسترسی به متدهای آن تولید کرده‌با‌شد. در یک پروژه بی آلایش، دفعه‌سازی از شی ها کاری میباشد که می‌قدرت به طور دستی اعمال بخشید، ولی در بعضا موردها ما یحتاج میباشد که شی ها به طور خود کار با به کار گیری از برای مثالً یک فریمورک نوبت‌سازی شوند. به این ترتیب جابجایی وظیفه ساخت‌و‌ساز یک شیء به شخص دیگر و به کار گیری بدون واسطه از تعلق به عبارتی تزریق تعلق طراحی اپلیکیشن در مشهد  نامیده می گردد.
به کار گیری از تزریق تعلق چه اهمیتی دارااست؟
اصل پنجم S.O.L.I.D ذکر می‌نماید که یک کلاس می بایست به تجرید متعلق باشد و خیر کد طاقت فرسا. S.O.L.I.D مشتمل بر پنج اصل نرم افزار‌نویسی شیءگرا میباشد که از سوی Uncle Bob پیاده سازی گردیده است. مفهوم گفته فوق این میباشد که یک کلاس، نباید تعلق‌های خویش را به طور استاتیک تنظیمات نماید؛ بلکه می بایست آنها را توسط کلاس‌هایی از فارغ خویش تنظیمات نماید.
 
با به کار گیری از این اصول، کد شما می تواند به طریق بی آلایش‌ای آزمایش خواهد شد و وراثت در میان کلاس‌های گوناگون آسوده‌خیس می‌گردد و کامپوننت‌های نرم افزار «وصلت سست» (loose coupling) خواهند داشت که در نرم افزار‌نویسی نرم افزار نکته مهمی به حساب می آید.
 
Koin چیست؟
Koin (+) یک فریمورک تزریق تعلق اپلیکیشن‌نویسی گردیده مدل برای توسعه و گسترش‌دهندگان کاتلین میباشد که مسئولیت نوبت‌سازی اشیای متعدد را در نرم افزار بر ذمه میگیرد.
 
 
کلیک فرمایید
به کار گیری از Koin در پروژه‌های اندروید
برای فهم بدون نقص طریق به کارگیری از Koin یک نرم افزار خرد اندرویدی میسازیم که فهرستی از یوزرها گیت‌هاب را که در‌این نشانی (+) جانور میباشد اکران میدهد.
 
معماری نرم افزار ما به طور تصویر پایین خواهد بود. ما قصد نداریم از مقر داده SQLite استعمال کنیم و نرم افزار مستقیماً با داده‌هایی که از خدمت اینترنت میاید، فارغ از این که آنان‌را در مقر داده محلی ذخیره نماید، تعامل خواهد کرد.
 
 
 
چنانچه به تصویر فوق اعتنا نمائید، می بینید که Activity مستقیماً با View-model تعامل می یابد که آن نیز به نوبه خویش مستقیماً با Repository تعامل داراست که مسئول گزینش منبع داده میباشد. در ارتباط این نمونه ریپازیتوری فقط یک منبع داراست.
 
چنان که در تصویر فوق می بینید، کامپوننت‌های مهم نرم افزار ما به همپا تعلق‌های بینشان معین گردیده‌اند. Activity یک ارجاع به ViewModel داراست و آن نیز به نوبه خویش ارجاعی به Repository داراست که از retrofit برای بازیابی داده‌ها از سرور به کارگیری می‌نماید. در طی این راهنما با نحوه مدیر مؤثر این تعلق‌ها از سوی Koin آشنا خوا‌هیم شد.
 
قدم 1: اضافه کردن تعلق‌های ما یحتاج در پوشه gradle
فولدر build.gradle
 
1// Retrofit
2implementation 'com.squareup.retrofit2:retrofit:2.6.0'
3implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
4
5// We will use it for loading the images
6implementation 'com.squareup.picasso:picasso:2.71828'
7
8// For ViewModel
9implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
10implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.0.0"
11
12// Koin
13implementation "org.koin:koin-android:2.0.1"
14implementation 'org.koin:koin-androidx-viewmodel:2.0.1'
15implementation 'org.koin:koin-androidx-scope:2.0.1'
مشاهده بدون نقص کدها
قدم 2: ساخت کلاسی که مخاطب را روی گیت‌هاب اکران می دهد
به خواسته آسانی نرم افزار، فقط سه گزینه از داده ها استفاده کننده یعنی id، اسم کاربری و تصویر او‌را ذخیره میکنیم:
 
پوشه User.kt
 
1data class GithubUser(
2 val id: Long,
3 val login: String,
4 val avatar_url: String
5)
 
قدم 3: ساخت و ساز کامپوننت‌های نرم افزار
اینترفیسی که اینترنت‌خدمت را اکران می دهد:
 
فولدر GithubApi.kt
 
1interface GithubApi {
2
3 @GET("users")
4 fun getUsers(): Call>
5}
 
کلاس ریپازیتوری به طور پایین میباشد. یک پارامتر به اسم GithubApi داراست.
 
پوشه UserRepository.kt
 
1class UserRepository(private val api: GithubApi) {
2 fun getAllUsers() = api.getUsers()
3}
 
سبک نما یک نوبت از UserRepository را تحت عنوان پارامتر میگیرد:
 
پوشه UserViewModel.kt
 
1class UserViewModel(private val repo: UserRepository) : ViewModel(), Callback> {
2
3 private val _loadingState = MutableLiveData()
4 val loadingState: LiveData
5 get() = _loadingState
6
7 private val _data = MutableLiveData>()
8 val data: LiveData>
9 get() = _data
10
11 init {
12 fetchData()
13 }
14
15 private fun fetchData() {
16 _loadingState.postValue(LoadingState.LOADING)
17 repo.getAllUsers().enqueue(this)
18 }
19
20 override fun onFailure(call: Call>, t: Throwable) {
21 _loadingState.postValue(LoadingState.error(t.message))
22 }
23
24 override fun onResponse(call: Call>, response: Response>) {
25 if (response.isSuccessful) {
26 _data.postValue(response.body())
27 _loadingState.postValue(LoadingState.LOADED)
28 } else {
29 _loadingState.postValue(LoadingState.error(response.errorBody().toString()))
30 }
31 }
32}
مشاهده بی نقص کدها
نکته: ما از کلاس کمکی به کار گیری کردیم تا بتوانیم موقعیت بار گذاری را رئیس کنیم.
 
فولدر LoadingState.kt
 
1data class LoadingState private constructor(val status: Status, val msg: String? = null) {
2 companion object {
3 val LOADED = LoadingState(Status.SUCCESS)
4 val LOADING = LoadingState(Status.RUNNING)
5 fun error(msg: String?) = LoadingState(Status.FAILED, msg)
6 }
7
8 enum class Status {
9 RUNNING,
10 SUCCESS,
11 FAILED
12 }
13}
 

تشکیل داد نرم افزار یادداشت با فلاتر و دارت – از صفر تا صد

 

 
تشکیل داد نرم افزار یادداشت با فلاتر و دارت – از صفر تا صد
فلاتر یک فریمورک توسعه و گسترش تلفن همراه چندپلتفرمی اوپن سورس میباشد که از سوی گوگل عرضه گردیده‌است. نرم افزار‌ها‌ی فلاتر با دارت نوشته می گردند. فلاتر به طور پیش‌فرض مجهز به کامپوننت‌های «متریال طراحی صفحه» (Material Design) میباشد و همین فرمان موجب گردیده‌است تا تشکیل داد نرم افزار با ظواهر و شم عالی با به کارگیری از فلاتر بسیار آسوده باشد. در فلاتر هر چیزی یک ویجت از نوع باحالت یا این که بی‌شرایط به حساب می آید. در‌این راهنما تحت عنوان یک پروژه برای استارت یادگیری فلاتر، ‌مبادرت به تشکیل داد نرم افزار یادداشت با فلاتر و دارت خوا هیم کرد.
درصورتی که هنوز فلاتر را روی سیستم خویش نصب نکرده‌اید، آن را به یار یک طراحی اپلیکیشن در مشهد  IDE جانبداری‌گردیده نصب نمایید. ارشادوراهنمایی‌های مایحتاج درین کاغذ (+) انجام شده میباشد.
 
آغاز پروژه را تهیه می کنیم. فرایند عمل به طور ذیل میباشد:
 
یک پروژه فلاتر در اندروید استودیو ساخت و ساز نمایید یا این که فرمان flutter create notes را در ترمینال یا این که CMD وارد نمائید.
در فولدر main.dart کلاس homepage را حذف کرده و یک فولدر نو با کلاس homepage خودتان ساخت فرمائید که Stateful Widget را توسعه و گسترش دهد. این کلاس مشتمل بر چارچوب کلی نرم افزار ما خواهد بود.
کلاس ویجت باحالت دیگری ساخت نمایید. این کلاس مشتمل بر نصیب Body میباشد که یک نمای Staggered را برای Home در خویش مکان داده میباشد. اسم آن را StaggeredGridPage میگذاریم.
 
کلیک نمایید
درین نرم افزار کوشش می کنیم که اختراع به خرج بدهیم و یادداشت‌ها را به نحوه Staggered جالبی اکران دهیم. از این پکیج دارت برای (+) ‌ساخت و ساز نمای کانال‌ای Staggered استعمال می کنیم. از SQLite نیز برای ذخیره داده‌های یادداشت‌ها روی دستگاه به کارگیری می کنیم.
 
در‌پی قطعه کدی را از pubspec.yaml می بینید که تعلق‌های فهرست گردیده را الزام نموده است. آنان‌را اضافه کرده، فولدر را ذخیره نمائید و از فرمان فلاتر flutter packages get برای نصب تعلق‌های اضافه گردیده تازه استعمال نمایید.
 
1dependencies:
2 flutter:
3 sdk: flutter
4
5 cupertino_icons: ^0.1.2
6 flutter_staggered_grid_view: ^0.2.7
7 auto_size_text: ^1.1.2
8 sqflite:
9 path:
10 intl: ^0.15.7
11 share: ^0.6.1
 
یک کلاس برای یادداشت‌ها ساخت‌و‌ساز نمائید. ما به تابع toMap برای کوئری‌های مقر داده نیاز داریم.
 
فولدر note.dart
1class Note {
2 int id;
3 String title;
4 String content;
5 DateTime date_created;
6 DateTime date_last_edited;
7 Color note_color;
8 int is_archived = 0;
9
10 Note(this.id, this.title, this.content, this.date_created, this.date_last_edited,this.note_color);
11
12 Map toMap(bool forUpdate) {
13 var data = {
14// 'id': id, since id is auto incremented in the database we don't need to send it to the insert query.
15 'title': utf8.encode(title),
16 'content': utf8.encode( content ),
17 'date_created': epochFromDate( date_created ),
18 'date_last_edited': epochFromDate( date_last_edited ),
19 'note_color': note_color.value,
20 'is_archived': is_archived // for later use for integrating archiving
21 };
22 if(forUpdate){ data["id"] = this.id; }
23 return data;
24 }
25
26// Converting the date time object into int representing seconds passed after midnight 1st Jan, 1970 UTC
27int epochFromDate(DateTime dt) { return dt.millisecondsSinceEpoch ~/ 1000; }
28
29void archiveThisNote(){ is_archived = 1; }
30}
مشاهده بی نقص کدها
کد کوئری‌های مقر داده SQLite برای کلاس note فوق و جدول مربوطه به طور پایین میباشد:
 
فولدر SqliteHandler.dart
1import 'package:sqflite/sqflite.dart';
2import 'package:path/path.dart';
3import 'package:sqflite/sqlite_api.dart';
4import 'dart:async';
5import 'Note.dart';
6
7class NotesDBHandler {
8
9 final databaseName = "notes.db";
10 final tableName = "notes";
11
12
13 final fieldMap = {
14 "id": "INTEGER PRIMARY KEY AUTOINCREMENT",
15 "title": "BLOB",
16 "content": "BLOB",
17 "date_created": "INTEGER",
18 "date_last_edited": "INTEGER",
19 "note_color": "INTEGER",
20 "is_archived": "INTEGER"
21 };
22
23
24 static Database _database;
25
26
27 Future get database async {
28 if (_database != null)
29 return _database;
30
31 _database = await initDB();
32 return _database;
33 }
34
35
36 initDB() async {
37 var path = await getDatabasesPath();
38 var dbPath = join(path, 'notes.db');
39 // ignore: argument_type_not_assignable
40 Database dbConnection = await openDatabase(
41 dbPath, version: 1, onCreate: (Database db, int version) async {
42 print("executing create query from onCreate callback");
43 await db.execute(_buildCreateQuery());
44 });
45
46 await dbConnection.execute(_buildCreateQuery());
47 _buildCreateQuery();
48 return dbConnection;
49 }
50
51
52// build the create query dynamically using the column:field dictionary.
53 String _buildCreateQuery() {
54 String query = "CREATE TABLE IF NOT EXISTS ";
55 query += tableName;
56 query += "(";
57 fieldMap.forEach((column, field){
58 print("$column : $field");
59 query += "$column $field,";
60 });
61
62
63 query = query.substring(0, query.length-1);
64 query += " )";
65
66 return query;
67
68 }
69
70 static Future dbPath() async {
71 String path = await getDatabasesPath();
72 return path;
73 }
74
75 Future insertNote(Note note, bool isNew) async {
76 // Get a reference to the database
77 final Database db = await database;
78 print("insert called");
79
80 // Insert the Notes into the correct table.
81 await db.insert('notes',
82 isNew ? note.toMap(false) : note.toMap(true),
83 conflictAlgorithm: ConflictAlgorithm.replace,
84 );
85
86 if (isNew) {
87 // get latest note which isn't archived, limit by 1
88 var one = await db.query("notes", orderBy: "date_last_edited desc",
89 where: "is_archived = ?",
90 whereArgs: [0],
91 limit: 1);
92 int latestId = one.first["id"] as int;
93 return latestId;
94 }
95 return note.id;
96 }
97
98
99 Future copyNote(Note note) async {
100 final Database db = await database;
101 try {
102 await db.insert("notes",note.toMap(false), conflictAlgorithm: ConflictAlgorithm.replace);
103 } catch(Error) {
104 print(Error);
105 return false;
106 }
107 return true;
108 }
109
110
111 Future archiveNote(Note note) async {
112 if (note.id != -1) {
113 final Database db = await database;
114
115 int idToUpdate = note.id;
116
117 db.update("notes", note.toMap(true), where: "id = ?",
118 whereArgs: [idToUpdate]);
119 }
120 }
121
122 Future deleteNote(Note note) async {
123 if(note.id != -1) {
124 final Database db = await database;
125 try {
126 await db.delete("notes",where: "id = ?",whereArgs: [note.id]);
127 return true;
128 } catch (Error){
129 print("Error deleting ${note.id}: ${Error.toString()}");
130 return false;
131 }
132 }
133 }
134
135
136 Future>> selectAllNotes() async {
137 final Database db = await database;
138 // query all the notes sorted by last edited
139 var data = await db.query("notes", orderBy: "date_last_edited desc",
140 where: "is_archived = ?",
141 whereArgs: [0]);
142
143 return data;
144
145 }
146
147
148
149}
مشاهده بدون نقص کدها
فعلا کاغذ مهم نرم افزار متریال بایستی یک چارچوب (Scaffold) از پوشه HomePage.dart داشته باشد که بدنه آن به طور StaggeredGridView میباشد. در قسمت AppBar این چارچوب یک دکمه اکشن قرار میدهیم تا استفاده کننده بتواند در میان موقعیت‌های اکران لیستی و Staggered تعیین نماید. فراموش نکنید که Body را داخل SafeArea قرار دهید، زیرا میخواهیم نرم افزار روی موبایل‌های امروزی نیز تلاش قابل قبولی داشته باشد.
 
کتابخانه نمای Staggered یک‌سری یادداشت برای نما الزام می‌نماید که به طور دینامیک بر مبنای پهنا اندازه شیت اکران انتخاب میگردد. این حالت مستلزم این میباشد که تعداد یادداشت‌هایی که قرار میباشد در کنار هم اکران یابند، معلوم گردیده باشد. در حالت افقی موبایل یا این که روی تبلت، تعداد یادداشت‌ها را به طور افقی روی 3 عدد و برای شرایط عمودی روی موبایل روی عدد 2 تهیه میکنیم.
 
پوشه StaggeredView.dart
1import 'dart:convert';
2import 'package:flutter/material.dart';
3import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
4import '../Models/Note.dart';
5import '../Models/SqliteHandler.dart';
6import '../Models/Utility.dart';
7import '../Views/StaggeredTiles.dart';
8import 'HomePage.dart';
9
10class StaggeredGridPage extends StatefulWidget {
11 final notesViewType;
12 const StaggeredGridPage({Key key, this.notesViewType}) : super(key: key);
13 @override
14 _StaggeredGridPageState createState() => _StaggeredGridPageState();
15}
16
17class _StaggeredGridPageState extends State {
18
19 var noteDB = NotesDBHandler();
20 List> _allNotesInQueryResult = [];
21 viewType notesViewType ;
22
23@override
24 void initState() {
25 super.initState();
26 this.notesViewType = widget.notesViewType;
27 }
28
29@override void setState(fn) {
30 super.setState(fn);
31 this.notesViewType = widget.notesViewType;
32 }
33
34 @override
35 Widget build(BuildContext context) {
36 GlobalKey _stagKey = GlobalKey();
37 if(CentralStation.updateNeeded) { retrieveAllNotesFromDatabase(); }
38 return Container(child: Padding(padding: _paddingForView(context) , child:
39 new StaggeredGridView.count(key: _stagKey,
40 crossAxisSpacing: 6, mainAxisSpacing: 6,
41 crossAxisCount: _colForStaggeredView(context),
42 children: List.generate(_allNotesInQueryResult.length, (i){ return _tileGenerator(i); }),
43 staggeredTiles: _tilesForView() ,
44 ),
45 )
46 );
47 }
48
49 int _colForStaggeredView(BuildContext context) {
50 if (widget.notesViewType == viewType.List) { return 1; }
51 // for width larger than 600, return 3 irrelevant of the orientation to accommodate more notes horizontally
52 return MediaQuery.of(context).size.width > 600 ? 3 : 2 ;
53 }
54
55 List _tilesForView() { // Generate staggered tiles for the view based on the current preference.
56 return List.generate(_allNotesInQueryResult.length,(index){ return StaggeredTile.fit( 1 ); }
57 ) ;
58}
59
60EdgeInsets _paddingForView(BuildContext context){
61 double width = MediaQuery.of(context).size.width;
62 double padding ;
63 double top_bottom = 8;
64 if (width > 500) {
65 padding = ( width ) * 0.05 ; // 5% padding of width on both side
66 } else {
67 padding = 8;
68 }
69 return EdgeInsets.only(left: padding, right: padding, top: top_bottom, bottom: top_bottom);
70}
71
72
73 MyStaggeredTile _tileGenerator(int i){
74 return MyStaggeredTile( Note(
75 _allNotesInQueryResult[i]["id"],
76 _allNotesInQueryResult[i]["title"] == null ? "" : utf8.decode(_allNotesInQueryResult[i]["title"]),
77 _allNotesInQueryResult[i]["content"] == null ? "" : utf8.decode(_allNotesInQueryResult[i]["content"]),
78 DateTime.fromMillisecondsSinceEpoch(_allNotesInQueryResult[i]["date_created"] * 1000),
79 DateTime.fromMillisecondsSinceEpoch(_allNotesInQueryResult[i]["date_last_edited"] * 1000),
80 Color(_allNotesInQueryResult[i]["note_color"] ))
81 );
82 }
83
84 void retrieveAllNotesFromDatabase() {
85 // queries for all the notes from the database ordered by latest edited note. excludes archived notes.
86 var _testData = noteDB.testSelect();
87 _testData.then((value){
88 setState(() {
89 this._allNotesInQueryResult = value;
90 CentralStation.updateNeeded = false;
91 });
92 });
93 }
94}
مشاهده بدون نقص کدها
این نما به کاشی‌هایی (Tiles) برای اکران یادداشت‌ها نیاز دارااست. آن کاشی که ما برای نما پیاده سازی می کنیم بایستی تیتر و محتوای یادداشت را به طور پیش‌اکران ارائه نماید. برای مدیر ارتفاع متعدد متن یادداشت از یک کتابخانه (+) ‌جهت ساخت و ساز نمای متنی با پیشرفت خود کار به کارگیری می کنیم. کافی میباشد محدودیت خط را تعریف‌و‌تمجید کنیم تا ویجت به طور اتوماتیک توسعه یابد و محتوا را تا جایی که بدین محدودیت می رسد، اکران دهد.
 
همچون segue در iOS و Intent در اندروید، برای ناوبری میان ورقه‌ها در فلاتر از Navigator استعمال میکنیم.
 
صفحه قبل 1 ... 7 8 9 10 11 12 صفحه بعد