مهاجرت از جاوا به فلاتر

اوایل سال 97 بود که به شدت درگیر جاوا بودم. با جاوا اپلیکیشن‌های اندرویدی طراحی می‌کردم و خیلی هم ازش راضی بودم. از قبل یه چیزهایی راجب برنامه نویسی کراس پلتفرم شنیده بودم و صحبتایی که راجبش می‌شد که آینده در دست زبان‌ها و فریم‌ ورک‌های کراس پلتفرم هست و از اینجور داستان‌ها. اما سابقه 2 ساله‌ایی که در حوزه جاوا داشتم اجازه نمیداد تا برنامه نویسی نیتیو رو بیخیال بشم و برم سمت کراس پلتفرم‌ها. خردادماه بود که اسم فلاتر رو خیلی اتفاقی شنیدم. تصمیم گرفتم نصبش کنم و ببینم آیا اونطوری که واقعا میگن هست یا نه. با یه سیستم کاملا ضعیف(i3 - RAM 6) می‌خواستم این کار رو انجام بدم. فلاتر، من رو حدودا 1 هفته از کار و زندگی انداخت تا تونستم بالاخره نصبش کنم(به دلیل کندی سیستم و اشتباهاتی که در طول نصب انجام می‌دادم و تحریم و ...). خوبی فلاتر این بود که قرار نبود برم تویه یه IDE دیگه، و من می‌خواستم تویه همون Android Studio بمونم.فلاتر رو نصب کردم، اولین پروژه هم اومد بالا:سلام دنیا:)ساختاری که در نگاه اول دیدم رو نه میشد گفت خیلی متفاوت و نه میشد گفت خیلی مشابه جاواست.خلاصه تصمیم گرفتم یه ذره سرچ کنم راجبش و ببینم چطوری می‌تونم باهاش یه UI طراحی کنم. اسم فلاتر رو که سرچ کردم فهمیدم از این عنوان در الکترونیک هم استفاده شده و هیچ آموزش دیگه‌ایی نبود به جز یه سری ویدیوها تویه YouTube و داکیومنت اصلی فلاتر. عالی شد:)) من می‌خواستم بدونم که چطوری findViewById بزنم و یا چطوری می‌تونم برای یک دکمه رویداد کلیک(setOnClickListener) بنویسم. Constraint Layout رو چطوری اینجا پیاده کنم و برای UI هنوزم باید از xml استفاده کنم؟ من باید بیخیال مفاهیم قبلی می‌شدم اما چطوری؟فلاتر چیست؟ کسی که قصد مهاجرت داره، قطعا مقصد رو قبلا کامل شناخته و دیگه اینجا لازم نیست من بیام راجب فلاتر صحبت کنم. در هر حال:فلاتر یک فریم ورک UI برای طراحی اپلیکیشن‌هایی با ظاهر بسیار زیبا است که به صورت نیتیو برای موبایل(اندروید و ای او اس) و وب کامپایل می‌شود. درحال حاضر شما با استفاده از این فریم‌ورک می‌تونید با نوشتن یک بار کد، خروجی Android,iOS,Web,Desktop بگیرید. به همین دلیل است که به فلاتر، کراس پلتفرم میگن.در ادامه چندین مورد رو میگم که حتما کمکتون می‌کنه راحت‌تر بتونید تغییرات رو هضم کنید. قطعا شما هم اگر از جاوا به سمت فلاتر اومده باشید دنبال مواردی خواهید بود که شبیه جاوا باشند ولی اینطور نیست! پس کم کم با توجه به موارد زیر بعضی از قوانین جاوا رو فراموش کنید.1. همه چیز یک ویجت است (Everything is a Widget): شعار معروف فلاتر این است که Everything is a Widget. برای اینکه بهتر بتونم این موضوع رو براتون توضیح بدم لطفا تصویر زیر رو ببینید.در تصویر بالا هر چیزی که می‌بینید یک ویجت جدا است. اگر ویجت‌های تصویر بالا رو بخوایم به ترتیب نام ببریم:اَپ بار (AppBar):در بالای صفحه اولین قسمتی که می‌بینیم یک قسمت آبی رنگ هستش که بهش میگیم AppBar. در جاوا به این ویجت ToolBar هم میگن.متن داخل AppBar: احتمالا الان با خودتون میگید که متن داخل AppBar هم جزئی از AppBar هست و دیگه نباید این دوتا رو از هم جدا کرد! اما تویه فلاتر اینطور نیست، در فلاتر همه چیز ویجته. به این معنی که AppBar خودش یک ویجت هست و متن داخلش هم یک ویجت دیگه هست. اگر گیج شدید نگران نشید به تکه کد زیر دقت کنید.AppBar( title: Text(&quotFlutter Demo Home Page&quot), )دقت کردید؟ ما یک ویجت داریم به اسم AppBar. حالا برای اینکه متن داخل AppBar رو مشخص کنیم از خصوصیتی به نام title استفاده می‌کنیم. title از ما یک ویجت می‌خواد تا عنوان AppBar رو مشخص کنه. و ما بهش ویجت Text رو میدیم. پس شد دوتا ویجت، AppBar و Text. به همین آسونی:)متن Hello Worldبعد از AppBar یک متن به چشم می‌خوره. اگر یادتون باشه در جاوا هنگامی که می‌خواستیم متنی رو در قسمتی از صفحه نشون بدیم، به این صورت عمل می‌کردیم:<TextView android:layout_width=&quotwrap_content&quot android:layout_height=&quotwrap_content&quot android:text=&quotHello World&quot />در فلاتر هم یک ویجت داریم به اسم Text البته هدف من از این مقاله توضیح ویجت‌های فلاتر نیست و صرفا ویجت‌های ساده‌ایی که در تصویر بالا می‌بینید رو توضیح میدم. برای نمایش یک متن در صفحه در فلاتر به این صورت عمل می‌کنیم:Text( 'Hello World', ) باز هم ویجت! ویجت Text. هر چی جلوتر می‌ریم شعار فلاتر رو بهتر متوجه میشیم. ذکر این نکته الزامیه که دیگه شما تویه فلاتر نباید دنبال مفاهیمی مثل LinearLayout و RelativeLayout و ConstraintLayout باشید و به جای اینا باید دنبال ویجت‌هایی مثل Row و Column باشید. تا فراموش نکردم این رو هم بگم که ما تویه فلاتر چیزی به اسم Activity نداریم. آخه تویه فلاتر همه چیز ویجته.پس:Activity = Widget2. مفهوم Declarative UIمعمولا در اکثر زبان‌ها و فریم ورک‌ها، UI به صورت Imperative تعریف می‌شود. به همین دلیل ما بیشتر با این سبک برنامه نویسی آشنا هستیم. برای اینکه معنی Imperative و Declarative را بهتر متوجه بشیم به مثال زیر توجه کنید.تویه جاوا اگر یک TextView و یک Button داشته باشیم و بخوایم با کلیک روی دکمه، متن داخل تکست ویو عوض بشه به این صورت عمل کنیم: Button clickButton = findViewById(R.id.clickButton); TextView txtView = findViewById(R.id.txtView); clickButton.setOnClickListener(new Listener(){ @override public void click(View v){ txtView.setText('Im tapped&quot); } });در واقع ما می‌تونیم به Button و TextView آیدی بدیم و بعدش با استفاده از آیدی‌هاشون مقدارشون رو عوض کنیم، براشون رویدادهای مختلف بنویسیم، رنگشون رو عوض کنیم و هزارتا کار دیگه! به این میگن Imperative. اما فلاتر اینطوری نیست. فلاتر Declarative هست. در مثال زیر ما یک دکمه تعریف کرده‌ایم:class _MyHomepageState extends State<MyHomepage> { String title = &quotIm a button&quot @override Widget build(BuildContext context) { return RaisedButton( child: Text(title), onPressed: click(), ); } click(){ title = &quotIm a tapped button&quot setState(() {}); } }نکته: کد بالا کامل نیست و من برای اینکه مفهوم رو ساده‌تر برسونم فقط قسمتی از کد که نیاز هست رو قرار دادم. خب بریم سراغ توضیحات:به تعریف کلاس و extends کردن اون کاری نداریم. ما یک متغیر از نوع رشته(String) تعریف کردیم و یک مقدار به اون اختصاص دادیم. بعدش یه RaisedButton تعریف کردیم. RaisedButton همون Button هستش که در جاوا استفاده می‌کردیم. RaisedButton یک ویژگی(property) داره به نام child. با استفاده از این ویژگی یک متن داخل دکمه قرار میدیم. اگه دقت کنید ما برای قراردادن یک متن درون دکمه از ویجت Text استفاده کردیم. یادتون هست گفتم همه چیز ویجته؟ پس حتی اگر بخواین یک متن، یک ایکون و یا هر چیز دیگری داخل یک RaisedButton نمایش بدید باید از ویجت مخصوص اون استفاده کنید. ویجت Text از ما یک رشته می‌خواد، و ما به جای اینکه مستقیم بیایم و یک رشته بهش بدیم، یک متغیر رشته‌ایی تعریف کردیم و بعدش اون متغیر رشته‌ایی رو اختصاص دادیم به ویجت Text.تصویر دکمه قبل از کلیک روی آنخب حالا هنگامی که روی دکمه کلیک کنیم، متن دکمه تغییر می‌کنه. بیاین بررسی کنیم. RaisedButton یک ویژگی داره به اسم onPressed. این ویژگی از ما یک متد می‌خواد تا داخل اون متد تعریف کنیم که قراره چه اتفاقاتی بیفته. خب حالا ما یک متد Button تعریف کردیم و اون رو اختصاص دادیم به onPressed. پس هر وقت روی RaisedButton کلیک بشه عملا متد Button فراخوانی میشه. اما درون این متد چه اتفاقی میفته؟ متغیر title که در واقع به عنوان متن داخل دکمه استفاده می‌شد مقدارش عوض میشه. اما مشکل اینه که با تغییر مقدار title متن داخل دکمه عوض نمیشه، چون قبلا تمام صفحه رندر شده، و هنگامی که دکمه قرار بوده روی صفحه نمایش داده بشه مقدار متغیر title برابر بوده با "Im a button". در اینجا می‌رسیم به یک دستور کلیدی در فلاتر به اسم setState. هنگامی که از این دستور استفاده می‌کنیم باعث میشه که کل صفحه دوباره ساخته بشه. یعنی کل متد build صفحه که در بالا می‌بینید دوباره اجرا میشه. راحت‌تر بگم، فلاتر دستور setState رو می‌بینه و بر می‌گرده به ابتدای متد build و دوباره RaisedButton ما ساخته میشه. اما اینبار وقتی می‌خواد RaisedButton ساخته بشه، متغیر title مقدارش برابر هست با "Im a tapped button" بنابراین این دفعه مقدار درون RaisedButton تغییر کرده. یادتون هست وقتی می‌خواستیم یک RecyclerView تعریف کنیم یک Adapter براش تعریف می‌کردیم و لیست داده‌هایی که قرار بود به صورت لیست نشون بدیم رو به Adapter می‌دادیم تا درون RecyclerView قرار بده؟ حالا اگر داده‌های لیست رو تغییر می‌دادیم مجبور بودیم از دستور notifyDatasetChanged استفاده کنیم. setState هم تقریبا میشه گفت کار notifyDatasetChanged رو برای کل صفحه انجام میده.3. دنبال فایل XML نگردید! قوانین UI در فلاتر خیلی متفاوتهدر جاوا شما نیازه تا UI مدنظرتون رو تویه یک فایل xml طراحی کنید و بعد View‌های خودتون رو در فایل جاوا findViewById کنید. ولی در فلاتر شما نیازی به اینکار ندارید و تمام تعاریف رو می‌تونید درون یک فایل انجام بدید. مثلا یک دکمه تعریف می‌کنید و همونجا رویداد کلیکش رو هم تعریف می‌کنید. اگر تکه کدی که بالاتر توضیح دادم رو ببینید چگونگی این کار رو متوجه می‌شوید. هر چند به مرور که حجم پروژه زیاد می‌شه نیاز هست که لایه UI از لایه Logic جدا بشه ولی باز هم به شکل راحت‌تری نسبت به جاوا این امر امکان پذیر هستش.4. آسون شدن کارهابرای جلوگیری از طولانی شدن مقاله فقط یک مثال ساده می‌زنم. حتما تویه جاوا قبلا قصد ساخت یک لیست رو داشتید. فرض کنید یک مبتدی بخواد یک لیست تویه جاوا طراحی کنه:اول باید تفاوت ListView و CustomListView و RecyclerView رو بفهمیم. با فرض اینکه می‌خوایم از RecyclerView استفاده کنیم به قدم بعدی میریم.باید تویه فایل xml مربوط به اکتیویتی یک ریسایکلرویو تعریف کنیم. یک فایل xml بسازیم برای UI آیتم‌های ریسایکلرویو.یک Adapter بسازیم و 3 متدی که مربوط به RecyclerView.Adapter هستند رو override کنیم.در فایل جاوا مربوط به اکتیویتی، ریسایکلر ویو رو findViewById می‌زنیم و لیست داده‌ها رو آماده می‌کنیم و بعدش داده‌ها رو به Adapter پاس می‌دیم و در نهایت شی مربوط به Adapter رو به ریسایکلرویو اختصاص میدیم.بدون در نظر گرفتن مرحله اول، 4 مرحله وجود داره که هرکدوم رو اشتباه انجام بدیم باعث می‌شه که لیست ساخته نشه و درست کار نکنه. حالا بیاید یه لیست تویه فلاتر بسازیم:ListView.builder( itemCount: 20, itemBuilder: (context, index) { return Text('$index'); })به همین راحتی یک لیست ساختیم. این چیزیه که خیلی منو به وجد اورد! بازهم تکرار می‌کنم هدف من در این مقاله توضیح کد نیست و صرفا یک سری مقایسه‌های ساده می‌خوام انجام بدم. نتیجه کد بالا به این صورت است:می‌بینید چقدر آسون شده پیاده سازی UI؟ همچنین یه قابلیت فوق العاده دیگه هم هست به اسم Hot Reload که باعث می‌شه سرعت دِوِلوپ پرژتون به طرز شگفت انگیزی افزایش پیدا کنه. بریم ببینیم Hot Reload چیه ...5. قابلیت Hot Reloadبه لطف قابلیت Hot Reload شما به راحتی می‌تونید نتیجه کدهاتون رو در حالی که اپلیکیشن شما در حالت اجرا هست، ببینید. هر کدی چه در UI چه در Logic تغییر کنه فقط با یک Hot Reload ساده در کمتر از 1 ثانیه می‌تونید نتیجه رو ببینید. مثلا فرض کنید می‌خواید رنگ یک دکمه رو تغییر بدید، یا می‌خواید در رویداد کلیک دکمه، یک کدی رو تغییر بدید. خب کاری نداره تغییرات مدنظر رو انجام بدید و اپلیکیشن رو Hot Reload کنید. می‌بینید که به طرز شگفت انگیزی برنامه با اینکه در حالت اجراست تغییرات شما رو اعمال می‌کنه و شما دیگه نیازی نیست تا صبر کنید تا برنامه به صورت کامل ری استارت بشه. پس دیگه ما نیازی به Layout Preview که در جاوا داشتیم نداریم و همه چیز به صورت لایو انجام میشه. اگر یک برنامه نویس رو دیدید که صفحه مانیتورش مثل تصویر زیر هست، به احتمال 90 درصد با فلاتر کار می‌کنه :)6. هرکاری ویجت مخصوص به خودش رو دارهدرک شعار فلاتر که میگه Everything is a widget خیلی مهمه. شما برای انجام هرکاری باید ویجت مربوط به اون کار رو اضافه کنید. مثلا می‌خواید دکمه رو از طرفین فاصله بدید، در جاوا:<Button ... android:layout_margin=&quot20dp&quot />در فلاتر:Padding( padding: EdgeInsets.all(10), child: RaisedButton( ), ),همنطور که در بالا می‌بینید ما یک دکمه داریم. برای اینکه بتونیم دکمه رو از طرفین فاصله بدیم باید از یک ویجت به اسم Padding استفاده کنیم. پس اول یک ویجت Padding می‌سازیم و بعدش دکمه رو به عنوان فرزند اون قرار میدیم. در نهایت میزان فاصله رو تنظیم می‌کنیم. پس باید به این نکته توجه کنید که برای هر کاری باید از ویجت مخصوص خودش استفاده کرد.7. قلب پروژه رو بشناسیموقتی ساختار یک پروژه فلاتر رو بررسی می‌کنیم می‌رسیم به یک فایل بسیار بی‌اعصاب به اسم pubspec.yaml . اگر با فایل‌های yaml آشنا باشید می‌‌دونید که این فایل‌ها برای کارهای پیکربندی کاربرد دارند. شما اگر یه space اضافه تویه این فایل‌ها بزارید، با خطا مواجه میشید. اما کاربرد فایل pubspec.yaml چیه؟افزودن dependencyیادتونه تویه جاوا موقعی می‌خواستیم یه کتابخونه یا به اصطلاح dependency رو به پروژه اضافه کنیم چیکار می‌کردیم؟ مثلا می‌خواستیم با APIایی در بک‌اند ارتباط برقرار کنیم و یک سری داده‌ها رو دریافت کنیم از سرور. به عنوان مثال retrofit یا volley رو اضافه می‌کردیم به پروژه. چطوری؟ وارد فایل build.gradle می‌شدیم و به این صورت عمل می‌کردیم:dependencies{ implementation 'com.squareup.retrofit2:retrofit:v.v.v' }تویه فلاتر هم تقریبا به همین شکل هست. شما ابتدا وارد سایت pub.dev میشید و نام پکیج مدنظرتون رو سرچ می‌کنید. بعدش یک نام و یک ورژن به شما میده. وارد فایل pubspec.yaml میشید و در قسمت dependencies نام پکیج رو اضافه می‌کنید. به این شکل:dependencies: flutter: sdk: flutter http: ^0.13.3اون قسمتی که نوشته :flutter و sdk:flutter، اینا به صورت دیفالت هستن و نباید تغییرشون بدید. در بالا نام پکیج ما http و ورژن اون 0.13.3 هست.افزودن assetsقطعا شما تویه پروژتون یک‌سری فونت‌ها، عکس‌ها و آیکون‌هایی استفاده می‌کنید. شما باید یک دایرکتوری تویه ریشه پروژتون بسازید و همه‌ی این فایل‌ها رو درون اون قرار بدید و در نهایت اون دایرکتوری اصلی رو به pubspec.yaml معرفی کنید. برای اینکه دقیقا متوجه بشید چطوری عکس و فونت اضافه کنید لطفا به لینک‌هایی که گذاشتم مراجعه کنید.فایل pubspec.yaml استفاده‌های دیگه‌ایی هم داره که توضیح کاملش رو اینجا میزارم.8. به Drawable و Mipmap بِدرود بگوییدتویه فلاتر ما فقط یک مفهوم داریم، اون هم asset هست. و دیگه لازم نیست درگیر این مسائل بشید که mipmap چیه و drawable چیه. همه‌‌ی عکس‌ها و آیکون‌هاتون رو می‌تونید تویه یک دایرکتوری(دایرکتوری assets رو خودتون باید بسازید) قرار میدین و اون رو به pubspec.yaml معرفی می‌کنید و بقیه کارها رو می‌سپارید به فلاتر.9. من به چشم خویشتن دیدم که Intent می‌رود :))تایتل رو یه ذره متفاوت زدم تا انرژیتون نیُفته:) یادتونه تویه جاوا وقتی می‌خواستیم از یک اکتیویتی بریم به یک اکتیویتی دیگه چیکار می‌کردیم؟ به این صورت:Intent myIntent = new Intent(CurrentActivity.this, NextActivity.class); startActivity(myIntent); // یا به طور خلاصه startActivity(new Intent(CurrentActivity.this,NextActivity.class));اما تویه فلاتر ما دیگه هیچ کاری با Intent نداریم و به جاش یه کلاس داریم به اسم Navigator. وقتی می‌خوایم از یک ویجت(به جای اکتیویتی بگید ویجت) به ویجت دیگه بریم باید به اینصورت عمل کنیم:Navigator.push( context, MaterialPageRoute(builder: (context) => NextWidget()));در کد بالا گفته شده که می‌خوایم از context(صفحه‌) جاری بریم به NextWidget. این کلاس Navigator متدهای زیادی داره. مثلا یادتونه وقتی می‌خواستیم برگردیم به صفحه قبل چیکار می‌کردیم؟ بیاید دستوراتش رو مقایسه کنیم:// Java finish(); // Flutter Navigator.pop(); این فکر کنم تنها جایی هست که دستور جاوا از فلاتر کوتاه تره D:برای آشنایی بیشتر با کلاس Navigator می‌تونید به این لینک مراجعه کنید.آینده فلاترآینده تکنولوژی‌ها رو بهتره پیش بینی نکنیم. ولی خب فلاتر و زبان‌های کراس پلتفرم(یک کد، چند خروجی) در اکثر مواقع باعث کاهش هزینه‌ها شده و باعث میشن که اکثر شرکت‌ها تمایل به همکاری با برنامه نویس‌هایی داشته باشند که به کراس پلتفرم‌ها مسلطند. البته که کراس پلتفرم‌ها مشکلاتی رو هم به همراه دارند. فلاتر از سال 2017 تا الان یعنی سال 2021 پیشرفت چشم‌گیری داشته، کلی آپدیتش کردن و اصطلاحا خیلی بهش رسیدن. قطعا فلاتر جزئی از پلن‌های آینده گوگل هست اما...اگر خدا بخواد در مقاله‌ بعدی قراره راجب روی دیگه‌ی سکه صحبت کنم یعنی نقاطی که هنوز فلاتر جای کار داره و باید بهبود پیدا کنند. البته شما که این مقاله رو می‌خونید احتمالا تصمیمتون رو گرفتید که وارد فلاتر بشید ولی خب مقاله‌ی بعدی بهتون کمک می‌کنه که کامل‌تر این فریم‌ورک رو بشناسید و بتونید تفکیک کنید که تویه چه پروژه‌ایی باید ازش استفاده بشه و تویه چه پروژه‌ایی نه!ببخشید که طولانی شد ممنون که تا پایان همراه بودید و امیدوارم که این مقاله مورد توجهتون قرار گرفته باشه.