مهدی عادلی فر
بنیانگذار توسینسو و برنامه نویس

آموزش برنامه نویسی اندروید با زامارین (Xamarin) | رایگان

در این مطلب با آموزش برنامه نویسی اندروید بوسیله زامارین (Xamarin) و با زبان سی شارپ در خدمت شما هستیم. امروزه استفاده از تلفن های هوشمند بسیار مورد توجه قرار گرفته است و معمولاً کسی در کوچه و پارک و جمع های خانوادگی نیست که یک گوشی هوشمند به دستش نباشد. به همین خاطر تصمیم گرفتم آموزش برنامه نویسی اندروید بوسیله زامارین (Xamarin) به صورت رایگان و در قالب متنی برای دوستان آماده کنم.

دوره های شبکه، برنامه نویسی، مجازی سازی، امنیت، نفوذ و ... با برترین های ایران
سرفصل های این مطلب
  1. معرفی معماری اندروید
    1. پلتفرم اندروید
    2. لینوکس(Linux)
    3. کتابخانه های بومی (Native libraries)
    4. فرایند اجرای برنامه های اندروید(Android Runtime)
    5. بخش Application Framework
    6. برنامه ها (Applications)
    7. پکیج اندروید (APK)
    8. مانیفست برنامه The Application manifest
  2. معرفی معماری اندروید
  3. نسخه های اندروید
    1. برنامه های اندروید
    2. فعالیت ها Activities
    3. رویدادهای یک activity
    4. سرویس ها
    5. فراهم کننده های محتوا Content Providers
    6. گیرنده های broadcast
    7. ویوها و گروه ویوها
    8. ساخت ویو در حالت برنامه نویسی و اعلانی
    9. ویجت های واسط کاربری
  4. معرفی معماری اندروید
    1. Layoutهای عمومی
    2. Layout های وفق پذیر(Adapter)
    3. فایل های xml مربوط به layout ها
    4. ارتباط عناصر و نام مشخصه ها
    5. شناسه ها (id)
    6. استفاده از layout های xml در activity ها
    7. Intent ها
    8. منابع (Resources)
    9. فایل R.java
  5. Xamarin چیست؟
    1. مزایای استفاده از Xamarin.Android
    2. مشکلات استفاده از Xamarin.Andriod
    3. Mono چیست؟
    4. مونو و Dalvik با یکدیگر
    5. واسط محلی جاوا (JNI)
    6. اشیای متناظر(Peer objects)
    7. بسته بندی برنامه های Xamarin.Android
    8. طراحی bindingهای اندروید
    9. طراحی فنی برای اندروید با #C
    10. مشخصات #C
    11. دلیگیت ها Delegate
    12. محیط های توسعه
    13. Xamarin Studio
    14. Xamrin برای Visual Sudio
  6. آموزش برنامه نویسی اندروید رایگان قسمت 5 : شروع کار با Xamarin
    1. نصب Xamarin.Android
    2. ساختن برنامه
    3. محیط Xamarin Studio
    4. تنظیم فریمورک مقصد
    5. قرار دادن آیکن برنامه و مشخص کردن نام بسته
    6. activity اولیه
    7. اجرا کردن و خطایابی برنامه
    8. ساختن و سفارشی سازی شبیه سازها
    9. خطایابی با دستگاه های اندرویدی
    10. فعال کردن USB debugging
    11. نصب راه انداز USB
    12. پشت صحنه برنامه
    13. اشیای متناظر (Peer object)
    14. فایل AndroidManifest.xml
  7. ساختار ذخیره اطلاعات
    1. ساخت کلاس Entity
    2. ساخت اینترفیس ذخیره سازی
    3. پیاده سازی سرویس ذخیره سازی
    4. دانلود Json.NET
    5. پیاده سازی متد های ItproJsonService
    6. پیاده سازی caching
    7. پیاده سازی تابع SaveEntity
    8. پیاده سازی تابع GetEntity
    9. پیاده سازی DeleteEntity
  8. طراحی رابط کاربری
    1. ساختن layout مربوط به ListView
    2. طراحی صفحه به شکل دیاگرام بالا
    3. افزودن یک ویجت LinearLayout
    4. افزودن کلاس های TextView مربوط به نام و آدرس
    5. ساخت لیستی از آیتم های موجود برای نمایش
    6. instance اشتراکی برای IITProDataService
    7. مجوزها Permissions
    8. ساخت ITProListViewAdapter
    9. پیاده سازی Constructor
    10. پیاده سازی سایر قسمت های کلاس adapter
    11. پیاده سازی ()GetView
    12. استفاده از ITProListViewAdapter برای نمایش اطلاعات
  9. ساخت منوی اصلی
    1. ساخت فایل xml مربوط به منو
    2. کد فراخوانی منو از فایل xml
    3. مدیریت انتخاب آیتم های یک منو
  10. نمایش اطلاعات Entity
    1. ساخت layout مربوط به ItproDetail
    2. کارکردن با InputType و انواع ورودی ها
    3. ساخت اکتیویتی ItproDetail
    4. مقید کردن متغیر ها به کنترل ها
    5. حرکت بین activity ها
  11. ذخیره و حذف
    1. غیرفعال کردن اکشن Delete
    2. نوشتن تابع SaveItpro()
    3. نوشتن تابع DeleteItpro()
    4. نشان دادن پیام موفقیت
    5. بازسازی ItproListActivity

معرفی معماری اندروید

در این قسمت قصد دارم که به معرفی تکنیکی سیستم عامل اندروید بپردازم. سیستم عامل اندروید سیستم عاملی است که روز به روز به تعداد کاربرانش افزوده می شود. این سیستم عامل به خاطر ظاهر ساده و برنامه هایی که زیاد است بسیار محبوب می باشد.

آموزش رایگان برنامه نویسی اندروید | آموزش برنامه نویسی اندروید

پلتفرم اندروید

پلتفرم اندروید یکی از موفقترین پلتفرم های چند سال اخیر به حساب می آید. این پلتفرم سرویس ها و ویژگی های بسیاری برای برنامه نویسان فراهم آورده است تا بتوانند برنامه های بسیار قوی برای موبایل تولید نمایند. شکل زیر یک نمای کلی از پلتفرم اندروید و بخش های آن را نمایش می دهد.

آموزش برنامه نویسی اندروید | آموزش زبان برنامه نویسی اندروید

لینوکس(Linux)

همان گونه که در شکل می بینید، اندروید یک سیستم عامل بر مبنای لینوکس است که در اصل برای دستگاه های قابل حمل و گوشی های هوشمند و تبلت ها می باشد. ورژن آخر اندروید برمبنای کرنل لینوکس نسخه 3.x می باشد. (کرنل 2.6 برای نسخه های قبل از اندروید 4.0 بود.)

کتابخانه های بومی (Native libraries)

کتابخانه های متنوعی در اندروید موجود می باشند که در شکل تعدادی از آنها نمایش داده شده اند. این مجموعه ی کتابخانه های بومی با زبان C/C++ نوشته شده اند طراحی و پیاده سازی شده است. که این کتابخانه ها سرویس های متنوعی را فراهم می نمایند. این کتابخانه عموماً از جامعه متن باز (open souce community) گرفته شده اند.

فرایند اجرای برنامه های اندروید(Android Runtime)

برنامه های اندروید درون ماشین مجازی Dalvik یا (Dalvik VM) اجرا می شوند که این ماشین مجازی شبیه به ماشین مجازی جاوا می باشد با این تفاوت که ماشین مجازی Dalvik برای دستگاه های با حافظه محدود و قدرت پردازشی پایین تر بهینه سازی شده اند. برنامه های اندروید ابتدا با استفاده از کامپایلر جاوا به بایت کد های جاوا کامپایل می شوند. اما این برنامه ها هنگام کامپایل یک مرحله اضافه دیگری را نیز طی می کنند و آن مرحله این است که بایت کدهای جاوا به بایت کدهای Dalvilk تبدیل می شوند تا برای اجرا در ماشین مجازی Dalvik مناسب باشد. شکل زیر تفاوت کامپایل برنامه های جاوا و اندروید را نمایش می دهد.

آموزش برنامه نویسی موبایل | آموزش برنامه نویسی اندروید

Dalvik با کتابخانه های هسته اندروید نوشته شده است. این کتابخانه ها مانند هیچکدام از پلتفرم های جاوا (JSE, JEE, JME) عمل نمی کنند بلکه به شکل یک پلتفرم ترکیبی از پلتفرم های گفته شده کار می کنند. پلتفرم اندروید بسیار شبیه به پلتفرم JSE می باشد با این تفاوت که کامپوننت های وابسته به رابط کاربری مانند AWT و Swing را ندارد. فریمورک کاربردی اندروید (AAF) یک سری ابزار ها برای ساخت رابط کاربری فراهم می نماید.

بخش Application Framework

Application Framework بخشی از پلتفرم اندروید می باشد که برای برنامه نویسان بسیار آشنا می باشد. این فریمورک مجموعه ای از کتابخانه های جاوا می باشد و به شما اجازه می دهد که رابط کاربری بسازید، با دستگاه های مختلف مانند دوربین ارتباط برقرار کنید، منابع کاربردی مختلف را لود کرده و با آنها کار کنید و بسیاری از وظایف و task های مفید را اجرا نمایید.

برنامه ها (Applications)

در قسمت بالای پشته ای که نشان دادیم برنامه های سمت کاربر قرار دارد. این برنامه ها بخش هایی هستند که نتایج و مقادیر را به کاربر تحویل می دهند. اندروید در داخل خود دارای برنامه هایی است که کاربرد های پایه را به همراه خود دارد. این کاربردهای پایه مانند مدیریت مخاطبین، استفاده از تلفن، چک کردن ایمیل و وب گردی می باشد که اندروید در خود آنها را دارد. کلید موفقیت اندروید داشتن شمار بسیار زیاد برنامه های مختلف می باشد که توسط آن کاربران می توانند فیلم های گرفته شده با گوشی را ویرایش کنند و یا با دوستان خود ارتباط داشته باشند و بسیاری از کاربرد های دیگر که این برنامه ها برای کاربران فراهم کرده اند.

پکیج اندروید (APK)

برنامه هایی که برای نصب در اختیار کاربران قرار می گیرند دارای فرمت .apk می باشند. یک پکیج (بسته) اندروید نتیجه کامپایل یک برنامه اندروید است که در یک فایل .apk بسته بندی شده است. یک بسته اندروید شامل همه کد ها و فایل های مورد نیزا برای اجرای برنام اندروید می باشد. که شامل موارد زیر است:

  • برنامه های اجرایی Dalvik که همان فایل های .dex هستند.
  • منابع
  • کتابخانه های بومی
  • مانیفست برنامه

بسته های اندروید می توانند به طور مستقیم از ایمیل ها و یا URL ها و یا کارت های حافظه نصب شوند. این بسته ها همچنین می توانند به صورت غیر مستقیم از فروشگاه های برنامه مانند Google Play نیز نصب شوند.

مانیفست برنامه The Application manifest

همه برنامه های اندروید یک فایل مانیفست دارند(AndroidManifest.xml) که این فایل به پلتفرم اندروید هر چیزی را که لازم است تا برنامه با موفقیت اجرا شود را می گوید. که این موارد لازم عبارتست از:

  • حداقل سطح API مورد نیاز برنامه
  • ویژگی های سخت افزاری و نرم افزاری مورد نیاز برنامه
  • مجوزهای مورد نیاز برنامه
  • صفحه ابتدایی برای شروع وقتی که برنامه اجرا می شود.
  • کتابخانه هایی که به جز AAF برای برنامه لازم است.

و چیزهایی مثل آن. برای مثال وقتی می خواهید برنامه ای را نصب کنید، سیستم عامل مجوز های مورد نیاز برنامه را به شما اعلان می کند(که البته هیشکی نمیخونه و فقط دنبال دکمه install هستیم D:) اندروید این اطلاعات و مجوز ها را از فایل مانیفست می خواند.در این قسمت در باره ی معماری سیستم عامل اندروید مطالبی را بیان نمودیم. در مطالب بعدی بیشتر به جنبه نرم افزاری و برنامه نویسی برای این سیستم عامل خواهیم پرداخت.

معرفی معماری اندروید

در قسمت قبل به بررسی معماری اندروید و بسته های نرم افزاری مربوط به این سیستم عامل صحبت کردیم. حال در این قسمت به ادامه بحث در باره ی این سیستم عامل می پردازیم.

نسخه های اندروید

آموزش برنامه نویسی اندروید | آموزش برنامه نویسی موبایل

مشخص کردن ورژن پلتفرم اندروید گاهی اوقات گیج کننده است. اما نسخه اندروید به شکل یک شماره ورژن، سطح API و یک نام مستعار نسخه تعیین می شود و این ترتیب گاهی اوقات به هم می خورد. شماره ورژن مشخصص کننده ی نسخه پلتفرم می باشد. در برخی اوقات ورژن جدید برای اضافه کردن قابلیت های جدید است و در برخی اوقات برای درست کردن خطاها می باشد.

سطح API نمایانگر مجموعه قابلیت های هر نسخه می باشد. هر چه که سطح API بالاتر می رود قابلیت های جدیدتری به برنامه نویسان ارائه می شود. تصویر زیر ورژن های پلتفرم های مختلف را با تاریخ ارایه نمایش می دهد. برای این که تفاوت بین نسخه های مختلف را بهتر درک کنید و ویژگی های هر نسخه را بدانید به این لینک مراجعه نمایید.مقایسه نسخه های مختلف اندروید

آموزش برنامه نویسی اندروید | آموزش برنامه نویسی موبایل

برنامه های اندروید

در ادامه در باره ی برنامه های اندروید صحبت خواهیم کرد. برنامه های اندروید از انواع گوناگونی از کلاس ها و منابع تشکیل شده اند که به بحث در باره ی این کلاس ها می پردازیم.

فعالیت ها Activities

اصلی ترین بخش یک برنامه اندروید یک activity است. یک activity عملی را فراهم می کند که کاربر آن عمل را اجرا می کند مانند لیست کردن مخاطبین، افزودن مخاطب جدید و نمایش نقاط و محل ها بر روی نقشه. یک برنامه از چندین Activity تشکیل شده است. کاربر با استفاده از ویوها با activity ها ارتباط برقرار می کند. اگر شما با الگوی طراحی MVC) Model-View-Controller) آشنا باشید می توان گفت که Activity ها همان Controller ها می باشند. چرخه حیات activity ها را می توان در قالب حالت ها و گذرها و رویداد ها بررسی کرد. دیاگرام زیر یک نمای گرافیکی از چرخه حیات یک activity را نمایش می دهد.

آموزش برنامه نویسی اندروید | آموزش برنامه نویسی موبایل

حالت های یک activity با توجه به دیاگرام قبل به شرح زیر است:

  • Running در این حالت activity ساخته شده است و آماده ارتباط و تعامل با کاربر می باشد.
  • Paused ویوی activity توسط یک activity دیگر به صورت موقت بلوکه شده است.
  • Stopped در این حالت activity توسط کاربر قابل دیدن نیست. Activity هنوز از بین نرفته است و در پس زمینه موجود است اما اجازه پردازش به آن داده نمی شود.
  • Destroyed این حالت مربوط به زمانی است که یک پردازش به اجبار متوقف و یا به اصطلاح kill می شود.

رویدادهای یک activity

در طی گذرها بین حالات یک سری رویدادها بر روی activity فراخوانی می شوند. این رویداد ها این امکان را فراهم می کنند که برنامه نویسان انواع گوناگونی از پردازش ها را انجام دهند. این رویدادها عبارتند از:

onCreate این رویداد زمانی فراخوانی می شود که یک activity ساخته می شود، معمولا این رویداد زمانی است که کاربر برنامه ای را اجرا می کند. از پردازش های معمولی که در هنگام این رویداد انجام می شود می توان به موارد زیر اشاره کرد:

  • ساختن ویوها
  • مقداردهی متغیرها
  • اختصاص منابع بلندمدت

onStart بعد از رویداد های onCreate , onRestart و دقیقا قبل از این که یک activity به کاربر نمایش داده شود این رویداد صدا زده می شود و از پردازش های معمول این رویداد اختصاص منابع به activity است.

  • onResume قبل از این که یک activity آماده اجرا و تعامل با کاربر شود اجرا می شود این رویداد صدا زده می شود. از پردازش های معمول این رویداد می توان به اجرا شدن ویجت های رابط کاربری و یا استارت شدن انیمیشن ها و ویدیو ها و یا استارت شدن گوش دادن به آپدیت های GPS می باشد.
  • onPause وقتی که یک ویوی activity به صورت موقتی بلاک می شود و منتظر ورودی نیست این رویداد فراخوانی می شود. از پردازش های معمول در هنگام صدا زدن این رویداد ذخیره آپدیت های ذخیره نشده ، pause کردن ویدیو ها و انیمیشن ها و توقف گوش کردن به GPS می باشد.
  • onStop وقتی که ویوی یک activity دیگر به کاربر نمایش داده نمی شود این رویداد اجرا می شود و معمولا در این زمان منابع آزاد می شود.
  • onRestart زمانی که یک activity به پیش زمینه برمی گردد. معمولا وقتی این اتفاق می افتد که کاربر دکمه back را می زند. معمولا در این رویداد اختصاص منابع صورت می گیرد.
  • onDestroy این رویداد قبل از نابود شدن یک activity صدا زده می شود. که معمولا در این هنگام منابع اختصاص داده شده پس گرفته می شود.

چیزی که ممکن است که برای برنامه نویسان تازه کار اندروید مبهم مانده باشد این است که فریمورک چگونه جهت قرار گرفتن (افقی یا عمودی بودن) دستگاه را هندل می کند. به طور پیشفرض وقتی که جهت قرارگیری دستگاه از حالت ایستاده به حالت خوابیده تغییر می کند اندروید activity های جاری را نابود و دوباره سازی می کند تا بتواند به نمایش آنها کمک کند. اگر این کار به شکل برنامه ریزی نشده انجام گیرد می تواند در سرعت و پردازش برنامه اختلال ایجاد کند. در صورت نیاز این رفتار می تواند بازنویسی شود و activity ها نگه داشته شوند.

سرویس ها

سرویس ها بخش هایی هستند که در پس زمینه اجرا می شوند و عملیات بلند مدت را انجام می دهند و واسط کاربری مستقیم ندارند. سرویس ها ممکن است داده ها را به داخل کش لود کنند، آهنگ ها را پخش می کند یا پردازش های دیگری را اجرا می کند.

فراهم کننده های محتوا Content Providers

فراهم کننده های محتوا دسترسی به repository مرکزی مانند مخاطبین را مدیریت می کند. یک فراهم کننده ی محتوا بخشی از یک برنامه کاربردی است که معمولا یک رابط کاربری برای مدیریت داده هایش فراهم می کند. یک رابط استاندارد اجازه می دهد که برنامه های دیگر به repository اش دسترسی داشته باشد.

گیرنده های broadcast

گیرنده های broadcast بخش هایی هستند که پردازش های از نوع broadcast را اجرا می کند. Broadcastها معمولا توسط سیستم فراخوانی می شوند و برای رویدادهایی مانند کمبود باتری، عکس گرفتن و یا روشن کردن بلوتوث به کار گرفته می شوند. ممکن است که برنامه ها نیز بخواهند که broadcast بفرستند. یک فراهم کننده محتوا ممکن است که وقتی که داده ای مثل یک مخاطب آپدیت شود broadcast بفرستد. گیرندگان broadcast ممکن است به طور غیرمستقیم باعث آپدیت وضعیت ها شوند.

ویوها و گروه ویوها

هرچیزی که شما در روی یک برنامه اندرویدی می بینید یک ویو است. دکمه ها، لیبل ها، text boxها، و دکمه های رادیویی همه مثال هایی از ویوها هستند. ویوها با استفاده از انواع مختلف گروه های ویو در یک سلسله مراتب سازماندهی می شوند. یک گروه ویو یک نوع مخصوص از ویو است که چیدمان بقیه ویوها را در صفحه نمایش درست می کند.

ساخت ویو در حالت برنامه نویسی و اعلانی

ویوها و گروه ویوها می توانند از طریق دو متد متفاوت ساخته شوند. برنامه نویسی یا اعلانی. وقتی که از راهکار برنامه نویسی استفاده می کنید یک برنامه نویس یک API را برای ساختن و قرار دادن هر کدام از ویو ها فراخوانی می نمایید. اما وقتی که از راهکار اعلانی استفاده می کنید، برنامه نویس فایل های layout xml مربوط به این که چگونه ویوها باید چیده شوند را می سازد. متد اعلانی مزایای زیر را دارد:

  • • تفکیک بهتری از جدا کردن منطق پردازشی برنامه از طراحی دیداری را فراهم می کنند.
  • • اجازه می دهد که چندین layout ساخته شود و با استفاده از یک پایه کد از چندین دستگاه یا چندین پیکربندی پشتیبانی می کند.
  • • ابزارهای توسعه برنامه مانند Android Studio و پلاگین اندروید برای Eclipse اجازه می دهند که واسط کاربری را همانگونه که ساخته اید ببینید بدون این که نیاز باشد که برنامه بعد از هربار تغییر کامپایل و اجرا شود.

با این که متد اعلانی برای بسیاری از کارها قابل ترجیح است در عمل هردو عمل لازم هستند و باید باشند.

ویجت های واسط کاربری

ندروید یک مجموعه ی بسیار بزرگی از ویجت هایی که می تواند توسط کاربر استفاده شود تا برنامه هایی قوی ساخته شود. همه ی این ویجت ها نوعی از ویو ها هستند که می توانند با استفاده از انواع مختلف گروه های ویو ترکیب شده و layoutهای پیچیده تری بسازند. همه ی ویجت های واسط کاربری می توانند در بسته andriod.widget در درون فریمورک برنامه یافت شوند.در این بخش به بررسی نسخه های مختلف اندروید و همچنین عناصری که در سیستم عامل اندروید وجود دارد پرداختیم. به امید خداوند در بخش های آینده جنبه های برنامه نویسی این سیستم عامل را شرح خواهیم داد

معرفی معماری اندروید

در مطالب گذشته به بررسی سیستم عامل اندروید و بخش های مختلف آن پرداختیم. در این مطلب به بررسی Layout ها خواهیم پرداخت و از مطالب دیگر به طور رسمی شروع به برنامه نویسی اندروید خواهیم کرد.

Layoutهای عمومی

فریمورک برنامه (Application Framework) تعدادی از زیرکلاس های گروه ویو دارد که هرکدام یک راه منحصر به فرد و مفید برای سازماندهی محتوا فراهم می کنند. دیاگرام زیر شکل layoutهای عمومی را نشان می دهد که هرکدام می توانند برای نیازهای خاص مورد استفاده قرار گیرند.

وب سایت توسینسو

در ادامه به توضیح هرکدام از layout ها خواهیم پرداخت.

  • layout خطی(linear) این layout همه ی فرزندان خود را به یک ترتیب خطی افقی و یا عمودی سازماندهی می کند و در صورت نیاز یک اسکرول بار برای آن می سازد. از این layout زمانی استفاده می شود که بخواهیم ویجت ها را به صورت افقی یا عمودی بچنیم.
  • layout نسبی (Relative) این layout فرزند را با توجه به یکدیگر و یا پدر آن شی سازماندهی می کند. از این layout زمانی استفاده می شود که مکان ویجت ها با توجه به ارتباط با اشیا دیگر مشخص می شود(مثلا در سمت چپ یک شی).
  • layout جدولی این layout اشیا را به صورت جدولی در سطر و ستون ها مرتب می کند و زمانی از این layout استفاده می شود که ویجت ها باید به صورت جدولی قرار بگیرند. این layout زمانی استفاده می شود که اشیا باید در چندین ستون قرار گیرند.

برای سناریوهای پیچیده تر اندروید به layout ها اجازه می دهد که به شکل تودرتو قرار گیرند. Layout هایی که به صورت عمقی تودرتو هستند باعث افت کارایی خواهند شد و تا حد امکان نباید از آنها استفاده کرد.

Layout های وفق پذیر(Adapter)

برای layoutهایی که از یک منبع داده پویا(Dynamic Data Source) استفاده می کنند فریمورک برنامه مجموعه کلاس هایی را فراهم کرده است که از کلاس AdapterView مشتق شده اند.

وب سایت توسینسو

در دیاگرام بالا دو عدد از معروف ترین adapter layoutها آورده شده است.

  • • List View: محتوایی را که از منبع داده دریافت می کند را در یک شکل تک ستونی اسکرول دار نمایش می دهد.
  • • Grid View: محتوایی را که از منبع داده دریافت کرده است را در یک شبکه گرید از سطر ها و ستون ها قرار می دهد.

فایل های xml مربوط به layout ها

برای این که رابط کاربری UI را با استفاده از متد اعلانی بسازیم، اندروید یک لغتنامه xml را به همراه تگ هایی فراهم می کند که این تگ ها هر کدام مشخص کننده ی انواع مختلف اشیا هستند که یک ویو را تشکیل می دهند. اگر بخواهیم این فایل های xml مربوط به layout ها را واضح تر بیان کنیم این فایل ها شبیه به همان فایل های html در صفحات وب و یا فایل های xaml در تکنولوژی WPF مایکروسافت می باشند که فقط برای ساختن رابط کاربری به کار می روند. مثال زیر یک ویوی ساده را نشان می دهد که با استفاده از layout خطی یک ورودی search و یک دکمه seach را در خود دارد.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk
/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:text="Enter Search Criteria"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/searchCriteriaTextView" />
<Button
android:text="Search"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/searchButton" />
</LinearLayout>

ارتباط عناصر و نام مشخصه ها

ارتباط نام عناصر و مشخصه ها به نام کلاس ها و متد ها در برنامه توسط فریمورک انجام می شود و نیازی به مقید کردن آن ها نیست. در مثال قبل نام عناصر LinearLayout, TextView, Button نام کلاسی در فریمورک برنامه است. همچنین به طور مشابه در عنصر Button مشخصه android:text به تابع setText() در کلاس Button مربوط می شود.

شناسه ها (id)

هر ویو می تواند دارای یک ID یا شناسه عددی یکتا باشد. این شناسه می تواند به عنصر موجود در ویو ارجاع شود و هرگاه که بخواهیم عملی را از کد برنامه بر روی عنصر مورد نظر انجام دهیم، از شناسه آن عنصر استفاده خواهد شد. در فایل XML هر شناسه به صورت یک نام رشته ای می باشد. برای مثال خط کد زیر را در نظر بگیرید.

Android:id=”@+id/searchButton”

در این مثال اپراتور @ به پارسر می گوید که از این رشته برای منبع شناسه استفاده شود. علامت + به پارسر می گوید که این یک نام جدید برای عنصر می باشد که باید به فایل منبع R.java اضافه شود. فایل منبع برای هرکدام از شناسه ها ثابت های عددی تعریف می کند تا بتوان به آنها ارجاع داد.

استفاده از layout های xml در activity ها

Layoutهای xml به سادگی می توانند در درون یک برنامه در حال اجرا لود شوند. این عمل معمولا در متد onCraete() یک activity با استفاده از متد setContentView() اجرا شود. برای مثال خط کد زیر را در نظر بگیرید.

setContentView(R.layout.main)

Intent ها

Intentها پیامهایی هستند که بین بخش های مختلف یک برنامه اندروید رد و بدل می شوند. این پیام ها به منظور درخواست اجرای یک عمل خاص ارسال می شوند. Intent ها ممکن است برای انجام کارهای زیر استفاده شوند.

  • • شروع یک activity با امکان دریافت نتیجه
  • • شروع و توقف یک سرویس
  • • اعلان شرایطی مثل کمبود باتری و یا تغییر منطقه زمانی
  • • درخواست اجرای یک عمل از یک برنامه دیگر مثل درخواست از برنامه نقشه که یک نقطه مورد نظر را نشان دهد و یا از برنامه دوربین درخواست شود که یک عکس گرفته و آن را ذخیره نماید.

منابع (Resources)

ساختن یک برنامه اندروید چیزی بیشتر از نوشتن چند خط کد است. یک برنامه قوی موبایل نیاز به منابعی مانند فایل های عکس و صوت، انیمیشن ها ، منوها و قالب های مفید است. فریمورک برنامه API هایی را فراهم می کند که این API ها می توانند برای لود و استفاده کردن از منابع گفته شده در برنامه اندروید به کار روند.

فایل R.java

در درون برنامه، منابع با استفاده از یک ثابت عددی شناخته شده و ارجاع داده می شوند. این ثابت عددی زمانی که منبع به برنامه افزوده شد و کامپایل شد به صورت اتوماتیک به منبع تخصیص داده می شود. این ثابت های عددی در یک فایل سورس جاوا با نام R.java قرار دارد. مثال زیر یک کلاس فایل R.java را در یک برنامه ساده نشان می دهد.

public final class R {
public static final class attr {
}
public static final class drawable {
public static final int icon=0x7f020000;
}
public static final class id {
public static final int myButton=0x7f050000;
public static final int searchButton=0x7f050002;
public static final int searchCriteriaTextView=0x7f050001;
}
public static final class layout {
public static final int main=0x7f030000;
public static final int search=0x7f030001;
}
public static final class string {
public static final int app_name=0x7f040001;
public static final int hello=0x7f040000;
}
}

تا به اینجا به بررسی سیستم عامل اندروید و برنامه های آن پرداختیم. در مطالب آینده سعی خواهد شد که برنامه نویسی اندروید با استفاده از زبان C# و با ابزار Xamarin.Android آموزش داده شود. بیان دیدگاه های دوستان می تواند در کیفیت این مطالب بسیار موثر باشد.

Xamarin چیست؟

در قسمت های قبل در باره ی پلتفرم اندروید صحبت شد و یک دید کلی از این سیستم عامل به دست آوردیم. حال قصد داریم که در باره ی Xamarin صحبت کنیم. ما می خواهیم در ادامه به بررسی Xamarin بپردازیم و ببینیم که این برنامه چگونه نوشتن برنامه اندروید را با #C و NET. آسان می کند. همچنین به مزایا و معایب Xamarin.Android خواهیم پرداخت.

وب سایت توسینسو

Xamarin نام شرکتی است که ابزارهای توسعه نرم افزار تجاری تولید می کند. این شرکت با استفاده از پروژه متن باز Mono بستری را فراهم می آورد که بتوان با استفاده از #C و NET.بتوان برنامه هایی برای اندروید و OS X و IOS ساخت. Xamarin برای ساخت برنامه های اندروید محصول Xamarin.Android را به بازار عرضه کرده است.

وب سایت توسینسو

قبل از این که به معماری Xamarin.Android بپردازیم ابتدا به این سوال می پردازیم که چرا این نرم افزار را انتخاب کردیم؟ در ادامه لیستی از مزایا و معایب استفاده از این نرم افزار را آورده ایم:

مزایای استفاده از Xamarin.Android

  • استفاده از مهارت های #C و NET. برنامه نویسان و مهندسان نرم افزار وقت و انرژی بسیاری برای یادگیری ویژگی های زبان #C و نحوه استفاده از آن و همچنین فریمورک NET. صرف کرده اند. با این که جاوا با زبان های شی گرا شباهت های بسیاری دارد ولی اگر یک برنامه نویس #C بخواهد همان برنامه ای که می تواند در زبان #C بنویسد را در زبان جاوا بنویسد وقت و انرژی بسیار زیادی را می طلبد. حال اگر کسانی که به زبان #C برنامه تولید می کنند بخواهند برای موبایل ها برنامه تولید کنند باید آن برنامه را به زبان جاوا تولید کنند. ولی با استفاده از این نرم افزار به راحتی می توان با استفاده از همان مهارت های #C برنامه اندروید تولید نمود و دیگر لازم نیست که سختی یادگیری زبان جاوا را تحمل کرد.
  • قابلیت تولید برنامه در چندین پلتفرم با این که نرم افزار Xamarin.Android اجازه نمی دهد که یک برنامه بسازید که در همه پلتفرم های اندروید، IOSو WP8 اجرا شود اما این قابلیت را فراهم می آورد که از بخش بسیار بزرگی از کدتان را در هریک از پلتفرم های گفته شده دوباره استفاده کنید. در کل کدهای مربوط به UI و کدهایی که مربوط به قابلیت های دستگاه است را باید برای هر پلتفرم جدا بنویسید ولی کدهایی مانند منطق سرویس های مشتری، اعتبارسنجی کاربران، کش کردن داده ها و ذخیره سازی داده ها می تواند برای همه ی پلتفرم ها یکسان باشد که باعث صرفه جویی در زمان خواهد شد.

مشکلات استفاده از Xamarin.Andriod

  • دارا بودن لایسنس Xamarin.Android همانند Xamarin.IOS و Xamarin.OS x ابزارهای تجاری هستند و باید خریداری شوند. البته در کشور ما این مشکل حادی نیست.
  • انتظار برای آپدیت در اکثر مواقع وقتی که یک نسخه از اندروید به بازار عرضه می شود مدت زمانی طول می کشد که شرکت Xamarin نرم افزار خود را آپدیت کند تا این نرم افزار با آخرین نسخه اندروید سازگار باشد.
  • کارایی (performance) و مدیریت حافظه گاهی اوقات گفته می شود که استفاده از زبان #C برای توسعه برنامه های اندروید سرعت را کاهش می دهد ولی هنوز اندازه گیری و ارزیابی درستی از این قضیه به عمل نیامده است.

Mono چیست؟

مونو یک پیاده سازی چند پلتفرمی متن باز از کامپایلر #C است. CLRی که در مونو است برای پلتفرم های بسیاری مثل اندروید، اکثر نسخه های لینوکس، BSD، OS x، Windows، Solaris و حتی بعضی از کنسول های بازی مثل Wii, xbox360 طراحی شده است. همچنین مونو یک کامپایلر استاتیک دارد که برنامه ها را برای محیط هایی مثل IOS و PS3 کامپایل می کند.

مونو و Dalvik با یکدیگر

همانطور که قبلا گفتیم برنامه های اندروید بر روی ماشین مجازی Dalvik اجرا می شوند و برنامه های مونو بر روی Mono CLR اجرا می شوند. پس برنامه Xamarin.Android چگونه اجرا می شود؟ اگر بخواهیم یک پاسخ ساده به این سوال بدهیم این است که این برنامه هم از Mono CLR و هم از ماشین مجازی Dalvik استفاده می کند. دیاگرام زیر نحوه ارتباط این دو را در حال اجرا نشان می دهد.

وب سایت توسینسو

حال چگونه Mono CLR با ماشین مجازی Dalvik در برنامه Xamarin.Android کار می کند؟ این عمل توسط مفهومی به نام اشیاء متناظر (peer objects) و فریمورکی به نام واسط محلی جاوا (Java Native Interface) JNI انجام می شود.

واسط محلی جاوا (JNI)

JNI فریمورکی است که باعث می شود که یک کد غیر جاوا (مثل کد #C یا ++C) در ماشین مجازی جاوا، توسط کدهای جاوا صدا زده شوند و یا کدهای جاوا را صدا بزنند. بنابراین JNI یک عضو لازم در معماری Xamarin.android می باشد.

اشیای متناظر(Peer objects)

یک سری اشیای مدیریت شده در Mono CLR قرار دارند و یک سری اشیای مدیریت شده نیز در ماشین مجازی Dalvik قرار دارند و با هم کار می کنند تا توابع Xamarin.Android را اجرا کنند. به این دو سری اشیا که با هم کار می کنند را اشیا متناظر می گویند. Xamarin.Android یک مجموعه اسمبلی هایی دارد که به نام کتابخانه های bind کردن اندروید (Android Binding Libraries) شناخته می شوند. کلاس های موجود در این کتابخانه با کلاس های جاوا که در فریمورک برنامه اندروید وجود دارند مرتبط هستند به طوری که متد های موجود در این کلاس ها به عنوان یک wrapper برای فراخوانی متدهای موجود در کلاس های جاوا به کار می روند.

زمانی که شما از کلاس های C# استفاده می کنید که این کلاس ها از کلاس های کتابخانه bind کردن اندروید ارث برده اند و برنامه ای با این کلاس می سازید. در زمان build کردن برنامه کلاس های پروکسی جاوا ساخته می شوند. کلاس های پروکسی جاوا همان کلاس هایی هستند که کلاس های C# و متدهای override شده آن را به کلاس ها و متد های جاوا wrap می کنند. دیاگرام زیر نحوه ارتباط اشیا متناظر را نشان می دهد.

وب سایت توسینسو

بسته بندی برنامه های Xamarin.Android

برنامه Xamarin.Android فایل های apk را تولید می کند که علاوه بر دارا بودن فایل هایی که قبلا گفته شد فایل های اضافه زیر را نیز دارا می باشد:

  • کدهای C# که در قالب اسمبلی ها در پوشه assembly ذخیره شده اند.
  • بسته ی Runtime مونو که به صورت کتابخانه های محلی نگه داشته می شوند.

طراحی bindingهای اندروید

قسمت اصلی Xamarin.Android این است که که چگونه APIهای اندروید را به #C مقید(Bind) کنند. در نرم افزار Xamarin.Android سعی شده است که طوری عمل شود که برنامه نویسی که در حال برنامه نویسی برای اندروید است و با زبان #C کار می کند راحت باشد و بتواند به راحتی برنامه خود را پیاده سازی نماید. نتیجه این تلاش برای ساده سازی برنامه نویسی اندروید ویژگی های زیر است:

  • وقتی برنامه نویس در حال استفاده از API های اندروید است در محیط توسعه(IDE) خود می تواند همانگونه که برای کتابخانه های .NET خاصیت Code completation وجود دارد برای APIها نیز این خاصیت را داشته باشد.
  • مثال ها و مستندات بسیاری از اندروید به زبان جاوا وجود دارند که به راحتی می تواند به کد #C تبدیل شده و مورد استفاده قرار گیرند.

طراحی فنی برای اندروید با #C

چون همانگونه که گفتیم برنامه های اندروید به نوعی با ماشین مجازی اندروید اجرا می شوند و زبان پیش فرض این برنامه ها جاوا است باید بتوانیم یک همگام سازی بین طراحی بین جاوا و #C داشته باشیم برای مثال باید بتوانیم از مشخصات JavaBean به عنوان مشخصات #C استفاده کنیم که در ادامه به این مباحث پرداخته می شوند.

مشخصات #C

همان گونه که می دانید مشخصات فیلد ها در جاوا به صورت دو تابع که یکی ابتدای آن set و دیگری ابتدای آن get می باشد مانند setText() و getText() که به این متد ها setter و getter می گویند.در حالی که پیاده سازی مشخصات فیلد ها در C# به کلی تفاوت دارد. و این دو باید به یکدیگر تبدیل شوند. در ادامه به نحوه تبدیل آنها اشاره شده است:

  • مشخصاتی که هم قابلیت خواندن و هم قابلیت نوشتن دارند از مشخصاتی ساخته شده اند که هم setter و هم getter داشته اند.
  • مشخصاتی که فقط خواندنی هستند از مشخصات جاوایی که فقط getter داشته اند ساخته شده است.
  • مشخصاتی که فقط نوشتنی هستند از مشخصات جاوایی که فقط setter داشته اند ساخته شده است.
  • برای آرایه ها مشخصاتی ساخته نشده است.

دلیگیت ها Delegate

APIهای اندروید از الگوی جاوایی برای تعریف و صدا زدن listener های هر رویداد می کنند. این درحالی است که برنامه نویسان C# به استفاده از delgate ها و eventها آشناتر هستند و با این امکانات کار می کنند. بنابراین قوانین زیر برای bind کردن از API های اندروید به C# وضع شده است:

  • وقتی که یک listerner اندرویدی یک مقدار void برمی گرداند، یک event بر مبنای EventHandler برای آن ساخته می شود.
  • وقتی که نوع بازگشتی یک listener اندرویدی voidنباشد برای آن یک Delegate با همان مقدار برگشت دهنده ساخته می شوند.

Eventها و مشخصات (properties) فقط تحت شرایط زیر ساخته می شوند:

  • متدهای اجرای رویداد های (event Handling method) اندروید یک پیشوند دارند مثل setOnClickListener
  • اجرا کننده ی رویداد اندروید مقدار بازگشتی void دارد.
  • اجرا کننده رویداد اندروید فقط یک پارامتر ورودی دارد.

محیط های توسعه

برنامه نویسان برای نوشتن برنامه های موبایل دو انتخاب برای IDE دارند که انتخاب ها Xamarin Studio و Visual Studio هستند.

Xamarin Studio

این نرم افزار یک نسخه سفارشی شده از MonoDevelop IDE می باشد که می تواند برای برنامه نویسی برای پلتفرم های Android, IOS و OS X مورد استفاده قرار گیرد. Xamain Studio هم برای سیستم عامل ویندوز و هم برای OS X وجود دارد و دارای ویژگی های زیر است:

  • خاصیت Code Completation
  • هایلایت کردن سینکس ها به صورت هوشمند
  • خاصیت Code Navigatio
  • توضیحات (tooltip) برای کدها
  • قابلیت خطایابی برنامه های موبایل وقتی که برنامه روی شبیه ساز و یا خود دستگاه اجرا می شود.
  • قابلیت ارتباط با source control ها مانند Git

تصویر زیر محیط Xamarin Studio را در حالی که محیط طراحی رابط کاربری اندروید برای آن باز است را نمایش می دهد.

وب سایت توسینسو

Xamrin برای Visual Sudio

Xamarin برای ویژوال استودیو یک افزونه است که توسعه برنامه برای برنامه های Xamarin.Android را پشتیبانی می کند. اگر شما با نرم افزار قدرتمند ویژوال استودیو آشنایی دارید می توانید این افزونه را بر روی این نرم افزار نصب کرده و با استفاده از آن برنامه های خود را بسازید. البته گفتنی است که این نرم افزار فقط برای سیستم عامل ویندوز موجود است. تصویر زیر محیط این نرم افزار را در حالی که صفحه طراحی رابط کاربری اندروید برای آن باز است را نمایش می دهد. برنامه های نوشته شده در هر کدام از محیط های توسعه قابل استفاده در محیط دیگری نیز می باشند.

وب سایت توسینسو

تا این قسمت مطالب بیشتر در مورد مباحث تئوری صحبت شد و به معرفی سیستم عامل و ابزار های برنامه نویسی پرداخته شد. در مطالب آینده به مباحث عملی و برنامه نویسی سیستم عامل اندروید پرداخته خواهد شد

آموزش برنامه نویسی اندروید رایگان قسمت 5 : شروع کار با Xamarin

آموزش رایگان برنامه نویسی اندروید ( Android ) قسمت5 : چگونه با زامارین استودیو کار کنیم؟ تا به حال در مورد معماری اندروید و همچنین نرم افزار Xamarin.Android و محیط های توسعه آن صحبت کردیم در ادامه به ساختن و خطایابی برنامه های اندروید می پردازیم. ما در ابتدا یک برنامه ساده را آغاز می کنیم و رفته رفته آن را گسترش می دهیم. اما در ابتدا به نصب Xamarin.Android می پردازیم.

نصب Xamarin.Android

ما در این قسمت نصب Xamarin.Android نسخه 4.8.3 را بر روی ویندوز توضیح خواهیم داد. برای نصب Xamarin.Android مراحل زیر را دنبال کنید.

1. به سایت xamarin.com رفته و windows installer را دانلود و اجرا کنید.

2. دو صفحه اول که صفحه خوش آمد گویی و صفحه لایسنس برنامه است را رد کرده تا به صفحه product selection برسید. Installer به شما امکان نصب Xamarin.Android و Xamarin.IOS را در ویژوال استودیو می دهد همانگونه که در شکل زیر دیده می شود. ما در این بخش کاری به IOS نداریم بنابراین می توانید Xamarin.IOS را انتخاب نکنید.

وب سایت توسینسو

اکنون باید صفحه Android SDK installation را ببینید که محل نصب پیش فرض را نمایش می دهد. شما نیازی به تغییر در این صفحه ندارید پس بر روی دکمه Next کلیک کنید. تصویر زیر این صفحه را نمایش می دهد:

وب سایت توسینسو

صفحه Requirements لیست ابزارهای مورد نیاز به همراه ورژن شان را نمایش می دهد بر روی دکمه Next کلیک کنید.

وب سایت توسینسو

در این قسمت یک صفحه ظاهر شده که روند نصب را نمایش می دهد و هر بسته که نصب شد جلوی آن یک علامت تیک زده می شود و در آخر برنامه به طور کامل نصب خواهد شد.

ساختن برنامه

ما الان آماده هستیم که اولین برنامه خود را به شکل زیر بسازیم:

  1. برنامه Xamarin studio و یا ویژوال استودیو را اجرا کنید. توضیحاتی که در این قسمت ارائه می شود مربوط به Xamarin studio می باشد ولی می توان این اعمال را در ویژوال استودیو نیز انجام داد.
  2. از منوی File گزینه New| Solution را انتخاب کنید. با این کار پنجره ی New Solution مانند شکل زیر نمایش داده می شود.
وب سایت توسینسو

3. در قست C# از سمت چپ گزینه Android را انتخاب کنید و در پنجره اصلی Android Appliction را انتخاب کنید. و در قسمت Name نام پروژه را وارد نماید برای مثال نام ITProApp را انتخاب می کنیم. همچنین محل ذخیره سازی پروژه نیز نشان داده شده است که می توان آن را تغییر داد. در نهایت بر روی دکمه OK کلیک کنید.

4.نرم افزار Xamarin Studio به طور پیش فرض پوشه های solution و project را می سازد. پوشه project به طور پیش فرض شامل کلاس MainActivity.cs و فایل layout به نام Main.axml می باشد.

محیط Xamarin Studio

بعد از ساختن ITProApp پروژه در درون محیط باز خواهد شد که تصویر زیر نمای نرم افزار را بعد از ساخته شدن برنامه نشان می دهد.

وب سایت توسینسو

نرم افزار Xamarin Studio مانند بسیاری از IDEهای مدرن از مجموعه ای از منو ها در بالای پنجره ساخته شده است که در زیر آن نوار ابزار هایی وجود دارند. در درون صفحه بخش های قابل جابه جایی برای انجام اعمال مختلف مانند بخش کار با فایل های برنامه و بخش جعبه ابزار و یا بخش مشخصات وجود دارد.

تنظیم فریمورک مقصد

تنظیم فریمورک مقصد مشخص می کند که چه سطحی از API ها برای ساختن و تست کردن برنامه موجود است. جدول نسخه های مختلف اندروید و سطح API ها را در قسمت اول نشان دادیم. هرچقدر که ما سطح API را پایین بگیریم برای گوشی های قدیمی بیشتری برنامه قابل استفاده است ولی امکانات و ویژگی های کمتری در اختیار داریم. برای مشخص کردن فریمورک مقصد مراحل زیر را دنبال کنید:

  1. پروژه ITProApp را در داخل solution به همین نام در Solution pad انتخاب می کنیم.
  2. بر روی پروژه کلیک راست کرده و گزینه Option را انتخاب کنید.
  3. از قسمت Build گزینه General را انتخاب کنید.
  4. از قسمت Target framework فریمورک مقصد را انتخاب کرده و بر روی دکمه OK کلیک کنید. نکته ای که باید در اینجا به آن متذکر شد این است که اگر می خواهید با استفاده از شبیه ساز برنامه های نوشته شده خود را اجرا کنید باید ورژن اندروید آن از حداقل ورژنی که در این پنجره دیده می شود پایین تر نباشد زیرا که در این صورت برنامه اجرا نخواهد شد. برای استفاده از دستگاه واقعی اندرویدی نیز باید این کار را انجام داد. این پنجره در شکل زیر نمایش داده شده است.
وب سایت توسینسو

قرار دادن آیکن برنامه و مشخص کردن نام بسته

Xamarin.Android یک نام بسته و یک آیکن پیش فرض برای برنامه ها قرار می دهد. آیکن در قسمت action bar ویوی اصلی و در بالای بقیه ویوها قابل نمایش است. برای تغییر تنظیمات پیش فرض برای آیکن مراحل زیر را دنبال کنید.

  1. با استفاده از windows explorer ویندوز (همون MyComputer خودمون) یک فایل عکس png مانند ic_app.png را به محل برنامه در پوشه ITProApp\\ITProApp\\Resurces\\drawable کپی کنید.
  2. از داخل برنامه Xamarin Studio به داخل پوشه Resources\\dawable رفته و روی پوشه کلیک راست کرده و گزینه Add Files را انتخاب کنید.
  3. از پنجره ی باز شده به محلی که فایل را در مرحله اول کپی کردید بروید و فایل را انتخاب کنید. اکنون باید در داخل برنامه در داخل پوشه drawable عکس مورد نظر را ببینید. مانند شکل زیر
وب سایت توسینسو
  1. بر روی پروژه ITProApp کلیک راست کنید و گزینه Option را انتخاب کنید.
  2. در قسمت Build گزینه Android Applicaiton را انتخاب کنید.
  3. نام Package را به ITProApp تغییر دهید. این کار باعث می شود که وقتی پکیج برنامه ساخته می شود نامش ITProApp.apk باشد.
  4. در قسمت Application icon مقدار @drawable/ic_app را وارد کنید و بر روی دکمه OK کلیک کنید.

activity اولیه

وقتی که یک برنامه بر روی دستگاه اندرویدی انتخاب می شود، سیستم عامل اندروید یک نمونه از activity اصلی برنامه می سازد. این activity اصلی را کاربر مشخص می کند. وقتی که بسته برنامه ای را می سازید activity اصلی برنامه در داخل فایل AndroidManifest.xml مشخص شده است. قطعه زیر از فایل AndroidManifest.xml به سیستم عامل می گوید که کدام یک از activityها به عنوان activity اصلی برنامه است و باید اول از همه اجرا شود:

<activity android:label="ITProApp"
android:name="itproapp.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

Xamarin.Android متدهایی برای مشخص کردن activity اصلی با استفاده از Attribute های .Net فراهم می کند. این Attribute های .NET در زمان build شدن برنامه فایل AndroidManifest.xml را می سازند. با این کار دیگر نیازی نیست که نگران این باشید که به طور مستقیم فایل AndroidManifest.xml را دستکاری کنید. برای این کار بالای آن activity که به عنوان activity اصلی برنامه است از attribute زیر استفاده می کنیم. توجه داشته باشید که برای هر activity که مقدار MainLauncher آن true باشد به عنوان activity اصلی شناخته می شود.

[Activity (Label = "ITPr0App", MainLauncher = true)]
public class MainActivity : Activity
{
. . .
}

اجرا کردن و خطایابی برنامه

روش اجرا و خطایابی قسمت مهم تولید برنامه ها است چون در سرعت و دقت تولید برنامه ها تاثیر بسیاری دارد. برای اجرای برنامه ها و خطایابی آنها مراحل زیررا دنبال کنید.

  1. فرایند خطایابی را با کلیک بر روی دکمه Start در نوار ابزار یا زدن دمه F5 و یا از منوی Run گزینه Start Debugging را انتخاب کنید. دکمه Start و نوار ابزار آن در شکل زیر نشان داده شده اند.
وب سایت توسینسو

2. از پنجره ی باز شده شبیه سازی که قصد دارید برنامه را با آن اجرا کنید را اجرا کنید. مثلا MonoForAndroidAPI15(emulator) را انتخاب کنید. توجه داشته باشید که باید صبر کنید تا شبیه ساز روشن شود.

وب سایت توسینسو

نرم افزار Xamarin studio برنامه را کامپایل می کند و برای اجرا در شبیه ساز آماده می کند. روند اجرا را می توانید در داخل status bar ببینید.

3. بعد از این که شبیه ساز روشن شد صفحه اندروید آن را باز کنید و برنامه را اجرا کنید.

4. حال با قرار دادن BreakPoint در برنامه و اجرای دوباره آن می بینید که برنامه تا محل Breakpoint اجرا می شود و در محل Breakpoint متوقف می شود. مانند شکل زیر

وب سایت توسینسو

5. حال از این قسمت برنامه را می توانید به همان حالت پیش فرض ادامه دهید و یا برای خطایابی آن را خط به خط اجرا کنید که برای این کار می توانید از نوار ابزار که تصویرش در ادامه آورده شده است استفاده نمایید.

وب سایت توسینسو

6. همچنین برای خطایابی برنامه می توانید از پنجره های بسیاری استفاده کنید که هر کدام امکانات خاصی را در اختیار شما قرار می دهند.شما می توانید با استفاده از این پنجره ها مقدار کنونی متغیر ها و یا ترتیب فراخوانی توابع و متد ها و بسیاری از پارامتر های برنامه را ببینید.

وب سایت توسینسو

ساختن و سفارشی سازی شبیه سازها

همانطور که دیدید شبیه سازها اجرا کننده ی برنامه های نوشته شده توسط برنامه نویسان است. به غیر ازشبیه ساز هایی که به طور پیش فرض وجود دارند می توانید شبیه سازهای متفاوتی با سلیقه خودتان بسازید و یا شبیه ساز های فعلی را دستکاری کنید. برای این کار این گونه عمل می کنیم:

  1. از منوی اصلی برنامه از منوی Tools گزینه Open Android Emulator Manager را انتخاب کنید
  2. در پنجره ای که باز می شود شبیه سازی را که می خواهید تغییر دهید را انتخاب کنید و بر روی دکمه Edit کلیک کنید تا پنجره زیر نمایش داده شود
وب سایت توسینسو

3. اگر به قسمت تنظیمات Target دقت کنید می بینید که در این قسمت نسخه پلتفرم اندروید و سطح API ی که در شبیه ساز استفاده شده است، مشخص شده است.

4. برای مثال از فیلد Device گزینه Nexus S را انتخاب کنید و در صوت لزوم از فیلد Target گزینه Android 4.0.3 را انتخاب کنید و Hardware Keyboard present را غیر فعال کنید و بر روی OK کلیک کنید.

5. برنامه را با شبیه ساز تغییر داده شده اجرا کنید.

شما همچنین می توانید با استفاده از پنجره Android Virtual Device Manager با استفاده از قسمت Device Definition شبیه سازهای جدیدی بسازید. برای این کار شما باید مشخصات شبیه سازی را که می خواهید بسازید را تعیین کنید. تصویر زیر نمایش دهنده گزینه های مورد نیاز برای ساخت شبیه ساز جدید را نشان می دهد.

وب سایت توسینسو

خطایابی با دستگاه های اندرویدی

توجه داشته باشید که با توجه به سخت افزاری که از آن استفاده می کنید ممکن است اجرا شدن شبیه سازها طول بکشد که برای حل این مشکل اگر شما یک دستگاه اندرویدی داشته باشید می توانید از آن استفاده نمایید. استفاده از دستگاه های اندروید به سادگی استفاده از شبیه سازها می باشد و شاید ساده تر. برای این که دستگاه شما برای اجرای برنامه های نوشته شده آماده شود باید مراحل زیر را دنبال کنید:

  1. فعال کردن USB debugging روی دستگاه
  2. نصب راه انداز USB دستگاه مورد نظر

فعال کردن USB debugging

برای فعال کردن این قسمت در دستگاه های اندرویدی که نسخه سیستم عامل آنها اندروید 4.0 به بعد است مراحل زیر را دنبال کنید:

  1. برای دستگاه های اندروید 4.2 به بالا یک مرحله اضافی دیگر نیز وجود دارد. گزینه Developer options در ابتدا مخفی است. برای نمایش آن به قسمت Settings/About phone رفته و بر روی Build number هفت بار بزنید(اینجا کلیک نداریم با دست هفت بار لمس کنید) در این صورت یک گزینه به به قسمت settings اضافه می شود که Developer Option نام دارد.
  2. به قسمت Settings/Developer options بروید
  3. گزینه USB debugging را فعال کنید.

نصب راه انداز USB

اگر کامپیوتر کاربران ویندوزی نتواند دستگاه اندرویدی را بشناسد باید خود به طور دستی راه انداز USB را بر روی کامپیوتر خود نصب کنند. البته در نسخه های جدید ویندوز اکثر دستگاه های اندرویدی شناخته شده هستند ولی اگر چنین نبود می توانید راه انداز های آنها را از اینترنت دانلود کرده و نصب کنید. بعد از این که مراحل قبل را کامل کردید. دستگاه خود را با استفاده از کابل usb به کامپیوتر متصل کرده و در برنامه Xamarin studio به جای استفاده از شبیه ساز از خود دستگاه خود استفاده کنید. و یا در برنامه Visual Studio از قستمت اجرای برنامه فلش رو به پایین را زده و مدل دستگاه خود را انتخاب نمایید.

پشت صحنه برنامه

ممکن است که یک انداختن یک نگاه اجمالی به پشت صحنه نحوه اجرای برنامه برای بسیاری جالب باشد که چگونه برنامه C# در اندروید اجرا می شود.

اشیای متناظر (Peer object)

ابتدا از اشیای متناظر(اشیای پروکسی) شروع می کنیم. قبلا نیز اشاراتی به این اشیا داشته ایم. در داخل پوشه های برنامه به قسمت ITProApp\\ITProApp\\obj\\Debug\\android\\src\\itproapp بروید و با استفاده از notepad فایل MainActivity.java را باز کنید. کد زیر قسمت های کلیدی این فایل را نمایش می دهد.چ

package itproapp;
public class MainActivity extends android.app.Activity implements
mono.android.IGCUserPeer
{
. . .
public void onCreate (android.os.Bundle p0)
{
n_onCreate (p0);
}
private native void n_onCreate (android.os.Bundle p0);
. . .
}


به بخش های زیر توجه کنید:

  • کلاس MainActivity از android.app.Activity مشتق می شود که همان چیزی است که انتظارش را داشتیم.
  • یک متد پروکسی به نام onCreate() ساخته شده است که متد بومی n_onCreate() را فرخوانی می کند که این متد به متد onCreate() موجود در C# اشاره می کنمد که override شده است.
  • کلاس MainActivity یک بلاک شروع کننده استاتیک و یک constructor دارد که ارتباط بین کلاس جاوا و کلاس C# متناظر را برقرار می کند.

فایل AndroidManifest.xml

اگر در همان پوشه ای که فایل MainActivity.java را باز کردیم فایل AndroidManifest.xml را با استفاده از notepad باز کنیم متنی مانند متن زیر نمایش داده می شود.

<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1" android:versionName="1.0"
package="ITProApp.ITProApp">
<uses-sdk android:minSdkVersion="15" />
<application android:label="ITProApp"
android:name="mono.android.app.Application"
android:debuggable="true">
<activity android:label="ITPros"
android:name="poiapp.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"
/>
</intent-filter>
</activity>
. . .
</application>
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

در کد آورده شده نکات زیر موجود است.

  • SDK مقصد 15 تنظیم شده است در عنصر <uses-sdk/>
  • Activity اولیه در داخل عنصر <category/> مشخص شده است.

تا این قسمت از مطالب با کلیات نرم افزار Xamarin Studio آشنا شدیم. در قسمت های آینده به شکل رسمی تر به برنامه نویسی اندروید خواهیم پرداخت.

ساختار ذخیره اطلاعات

در مطالب گذشته در باره ی خود ساختار اندروید و برنامه نویسی آن و همچنین Xamarin صحبت کردیم. حال شروع می کنیم که یک برنامه را از ابتدا بسازیم. در این مطلب به بررسی و ساخت مکانیزم ذخیره سازی اطلاعات در برنامه می پردازیم. در این مطلب خواهید دید که از همان کتابخانه های دات نت برای ذخیره سازی استفاده خواهیم کرد. راهکارهای ذخیره سازی داده به دو دسته تقسیم می شوند. وب سرویس ها و ذخیره سازی محلی.

اگرچه بسیاری از برنامه های موبایل به وب سرویس ها وابسته هستند اما ما در این مطلب بر روی ذخیره سازی محلی تمرکز خواهیم داشت. راهکارهای ذخیره سازی محلی مختلفی وجود دارند. SQLite یک موتور پایگاه داده تراکنشی سبک است که در پلتفرم اندروید موجود است. SQLite به طور گسترده در موبایل ها استفاده شده است هم در اندروید و هم در IOS. اگر شما می خواهید که با بانک اطلاعاتی ارتباط داشته باشید و اطلاعات خود را در آن ذخیره کنید SQLite می تواند در موبایل راه حل خوبی باشد.

اما ما در این آموزش فعلا به ذخیره سازی فایلی می پردازیم. به دو روش می توان از ذخیره سازی فایلی استفاده کرد. دو راه استانداردی که برای ذخیره سای داده های دارای ساختار در فایل متنی وجود دارد عبارتست از xml و Json. فایل های xml طولانی هستند و وب سرویس هایی که بر پایه SOAP و WSDL هستند از این استاندارد استفاده می کنند. حجم فایل هایی که به شکل json ذخیره شده اند از فایل هایی که به شکل xml ذخیره شده اند کمتر می باشد و Json در وب سرویس های RESTful کاربرد دارد. ما در این بخش از Json استفاده خواهیم کرد.

ساخت کلاس Entity

اولین کلاسی که باید آن را بسازیم، کلاسی است که فوکوس برنامه بر روی آن است. این کلاس به نوعی کلاس ساختار داده های برنامه است و entity های برنامه با این قالب ذخیره می شوند. کلاسی که در این قسمت می خواهیم بسازیم دارای فیلد های زیر است:

  • Id
  • Name
  • Description
  • Address
  • Latitude
  • Longitude

کلاس entity کلاسی است که موارد گفته شده را داشته باشد. برای ساخت این کلاس مراحل زیر را دنبال کنید:

  1. در Xamarin Studio در قسمت Solution pad بر روی نام پروژه کلیک راست کرده و گزینه New File Add| را انتخاب کنید. با انتخاب این گزینه تصویر زیر ظاهر می شود.
وب سایت توسینسو
  1. در قسمت سمت چپ بر روی گزینه General کلیک کرده و در سمت راست بر روی گزینه Empty Class(C#) کلیک کنید.
  2. نامی برای این کلاس مشخص کنید. این نام قرار است که نام Entity های شما نیز باشد. سپس بر روی دکمه OK کلیک کنید. ما نام این فایل را ITProEntity می گذاریم.

برای این که فیلدهای مختلف کلاس Entity را بسازید باید همه آن ها را به شکل properties مشخص کنید. به کد پیاده سازی این کلاس دقت کنید.

 public class ITProEntity
    {
        public int? Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public string Address { get; set; }
        public double? Latitude { get; set; }
        public double? Longitude { get; set; }
    }

دقت داشته باشید که فیلد های Latitude و Longitude می توانند null باشند یعنی مقدار دهی نشوند. به همین منظور بعد از نوع داده آنها علامت ؟ استفاده شده است.

ساخت اینترفیس ذخیره سازی

برای این که عملیات ذخیره سازی را پیاده کنیم یک اینترفیس استاندارد برای آن نیاز داریم. این اینترفیس باید عملیات اساسی CRUD (Create, Read, Update, Delete) را در خود داشته باشد. همچنین می خواهیم یک مکانیزم caching ساده را نیز پیاده سازی کنیم. عملیات کشینگ باعث می شود که تعداد خواندن داده از فایل کم شده و در نتیجه سرعت و کارایی برنامه بالاتر می رود. برای ساختن اینترفیس مورد نظر از بخش Solution pad بر روی نام پروژه کلیک راست کرده و گزینه New File را انتخاب کنید. و از صفحه ظاهر شده Empty Interface را انتخاب کرده و نام آن را تعیین کنید و بر روی دکمه OK کلیک نمایید.

بعد از این که اینترفیس مورد نظر ساخته شد، متدهایی را که عمل کش کردن و CRUD را پشتیبانی کنند را در درون اینترفیس قرار می دهیم. برای کش کردن ما به یک ساختمان داده collection داریم که فقط خواندنی باشد و فقط از داخل اعمال CRUD بتوانیم عناصر آن را حذف و اضافه کنیم. برای این کار از اینترفیس IReadOnlyList استفاده می کنیم. کد اینترفیس که می سازیم به شکل زیر است:

using System.Collections.Generic;

    public interface IITProDataService
    {
        IReadOnlyList<ITProEntity> ITPros { get; }
        void RefreshCache();
        ITProEntity GetEntity(int id);
        void SaveEntity(ITProEntity entity);
        void DeleteEntity(ITProEntity entity);
    }

پیاده سازی سرویس ذخیره سازی

حال به پیاده سازی توابع موجود در اینترفیس می پردازیم. برای این کار به روش زیر عمل می کنیم.

  1. کلاسی را می سازیم و نام آن را ItproJsonService می گذاریم.
  2. مشخص می کنیم که این کلاس ، اینترفیس ساخته شده را پیاده سازی نماید.
  3. نشانگر موس را روی نام اینترفیس در کلاس قرار داده و کلیک راست کرده و از منوی باز شده گزینه ی Refactor و سپس Implement interface را انتخاب می کنیم.

اکنون در داخل کلاسی که شما ساخته بودید متدهای موجود در اینترفیس ظاهر خواهند شد. این کلاس در شکل زیر آمده است.

public class ItproJsonService : IITProDataService
    {
        public ItproJsonService()
        {
        }

        public IReadOnlyList<ITProEntity> ITPros
        {
            get { throw new NotImplementedException(); }
        }

        public void RefreshCache()
        {
            throw new NotImplementedException();
        }
        public ITProEntity GetEntity(int id)
        {
            throw new NotImplementedException();
        }
        public void SaveEntity(ITProEntity entity)
        {
            throw new NotImplementedException();
        }
        public void DeleteEntity(ITProEntity entity)
        {
            throw new NotImplementedException();
        }
       
    }

قدم بعدی نوشتن منطق متدها است. اما قبل از این که پیاده سازی این متد ها را شروع کنیم چون قرار است که از json برای ذخیره سازی استفاده کنیم پس باید کتابخانه آن را دانلود و نصب کنیم.

دانلود Json.NET

برای دانلود Json.NET برای پروژه موجود مراحل زیر را دنبال کنید.

  1. در داخل پروژه بر روی component package کلیک راست کنید و گزینه Get More Components را انتخاب کنید.
  2. در پنجره ی باز شده در قسمت جستجو عبارت json.net را وارد کنید(مانند شکل زیر)
وب سایت توسینسو
  1. اگر ارتباط اینترنت برقرار باشد در قسمت سمت راست نتیجه جستجو ظاهر می شود. از این قسمت Json.NET را انتخاب کرده و گزینه Add to App را انتخاب کنید. با این کار کتابخانه Json.NET دانلود شده و به پروژه شما اضافه خواهد شد. بعد از دانلود شدن این کتاب خانه بر روی آن کلیک راست کرده و گزینه Edit Component را انتخاب کرده و Add to Project را انتخاب کنید. البته در نظر داشته باشید که نرم افزار xamarin قبل از انجام این مراحل از شما مشخصات حساب کاربری xamarin را می خواهد. برای حل این مشکل از پنجره ی باز شده روی لینک create account کلیک کنید و یک account بسازید و سپس به ادمه کارهای گفته شده بپردازید.

پیاده سازی متد های ItproJsonService

اکنون آماده ایم تا به ساختن متدهای موجود در کلاس بپردازیم. برنامه ما به این گونه است که فایل های متنی Json را در یک پوشه ذخیره خواهیم کرد. به گونه ای که نام هر فایل با استفاده از ID آن شخص ساخته می شود. مثل itpro<id>.json. کلاس ItproJsonService باید از محل پوشه ذخیره سازی فایل های آگاه باشد.

برای سادگی این کار یک متیر خصوصی متنی تعریف می کنیم و مسیر ذخیره سازی را در آن قرار می دهیم. مسیر پوشه ذخیره سازی در زمان ساخته شدن شی از کلاس به constructor ارسال می شود. همچنین constructor باید چک کند که چنین پوشه ای وجود دارد یا خیر و اگر وجود نداشت آن را بسازد. همچنین می خواهیم در داخل برنامه مکانیزم کش را نیز داشته باشیم. برای این کار در داخل constructor متد RefreshCache() را فراخوانی می نماییم. کد زیر کد مربوط به constructor برنامه است.

 private readonly string _storagePath;

        public ItproJsonService(string storagePath)
        {
            _storagePath = storagePath;

            if (!Directory.Exists(_storagePath))
                Directory.CreateDirectory(_storagePath);
            RefreshCache();
        }

پیاده سازی caching

ما به یک Collection خصوصی برای پیاده سازی کش نیازمندیم که تابع RefreshCache() نیز برای لود کردن داده ها به داخل این Collection به کار خواهد رفت. برای این کار کد زیر را به داخل کلاس ItproJsonService اضافه کنید. این نکته را در نظر داشته باشید که در بالای این کلاس namespaceی به نام System.Collections.Generic را قرار داده باشید (using کرده باشید)

private List<ITProEntity> _entities= new List<ITProEntity>();

برای این که این لیستی که ساخته ایم به صورت فقط خواندنی باشد و در داخل برنامه نتوان مقداری به آن اضافه یا از آن کم کنیم و همانگونه که در داخل interface آورده ایم باید لیست readonly داشته باشیم کد زیر را نیز به کلاس خود اضافه خواهیم کرد.

public IReadOnlyList<ITProEntity> Entities{
get { return _entities; }
}

حال باید به پیاده سازی تابع RefreshCache() بپردازیم. همانطور که قبلا هم گقتیم این تابع مقادیر ذخیره شده را به داخل لیست ساخته شده لود می کند. این کار در زمانی که کلاس سرویس ما ساخته می شود. همچنین وقتی که تابع SaveEntity() و یا تابع DeleteEntity() ساخته می شود، کش برنامه باید تغییر نماید. ابتدا نگاهی می اندازیم به این نکته که از داخل یک فایل متنی json یک شی .NET بسازیم. برای این کار ابتدا کل فایل Json را در داخل یک متغیر string می خوانیم. سپس تابع JsonConvert.DeserializeObject<> را فراخوانی می کنیم که از داخل متن Json یک شی بسازد. کد زیر این کار را انجام می دهد.

string entityString = File.ReadAllText (filename);
ITProEntity entity= JsonConvert.DeserializeObject<ITProEntity> (entityString );

برای این که همه مقادیر را داخل کش بریزیم باید پوشه حاوی فایل های json را بگیریم و هر entity را داخل کش بریزیم. که کد زیر این عمل را نشان می دهد. که باید توجه داشت که در داخل کلاس باید از namespace به نام System.IO استفاده کنید.

 
public void RefreshCache()
{
_entities.Clear ();
			string[] filenames = Directory.GetFiles (_storagePath, "*.json");
			foreach (string filename in filenames) {
				string entityString = File.ReadAllText (filename);
				ITProEntity entity= JsonConvert.DeserializeObject<ITProEntity> (entityString )
					;
				_entities.Add (entity);
			}
}

پیاده سازی تابع SaveEntity

این تابع مقادیر entityجدید و یا موجود را ذخیره می کند. بنابراین این تابع انجام دهنده دو عدد از عملیات CRUD است. Create, update را با این تابع پیاده سازی می کنیم. در حالی که entity جدیدی داشته باشیم تابع SaveEntity باید یک Id جدید به فیلد id مربوط به entity بدهد. همانطور که قبلا هم گفتیم اگر فیلد id هر entity برابر مقدار null باشد آن entity یک entity جدید است. برای اختصاص دادن id جدید اول کش را چک می کنیم که مقداری دارد یا خیر.

اگر هیچ مقداری در کش نبود به این معنی است که entity که در حال ثبت آن هستیم اولین entity برنامه است پس به id آن مقدار 1 می دهیم و در غیراینصورت به بزرگترین id موجود در کش یک مقدار اضافه کرده و برابر id جدید قرار می دهیم. کد زیر تابع GetNextId را نمایش می دهد که برای تخصیص id می باشد.

if (_entities.Count == 0)
                return 1;
			return _entities.Max(p => p.Id.Value) + 1;

برای این که نام فایل ها را با استفاده از id آنها بدست آوریم تابعی به نام GetFilename() تعریف می کنیم که یک عدد صحیح گرفته و یک رشته که همان نام فایل است را برمی گرداند. کد زیر این تابع را نشان می دهد.

private string GetFilename(int id)
{
return Path.Combine(_storagePath,"entity" + id.ToString() + ".json");
}

تابع Path.Combine را در نظر بگیرید. این تابع برای ساختن مسیر فایل استفاده می شود. این تابع اگر کاراکتر نادرستی در مسیر فایل و خود فایل وجود داشته باشد اعلام خطا می کند. حال به منطق اصلی تابع SaveEntity می پردازیم. ما در این تابع می خواهیم یک شی .NET را به یک متن Json تبدیل کنیم.

این کار برعکس همان چیزی است که در تابع RefreshCache() می باشد. عملیات ذخیره سازی به این شکل است که ابتدا شی .NET را به متن Json تبدیل می کنیم. این کار توسط تابع SerializeObject انجام می شود. بعد از این کار فایل متنی را ذخیره می کنیم. قطعه کد زیر بدنه تابع SaveEntity را نمایش می دهد.

 public void SaveEntity(ITProEntity entity)
        {
			Boolean newEntity= false;
			if (!entity.Id.HasValue) {
				entity.Id = GetNextId ();
				newEntity= true;
			}
			string entityString= JsonConvert.SerializeObject (entity);
			File.WriteAllText (GetFilename (entity.Id.Value), entityString);
			// update cache if file save was successful
			if (newEntity)
				_entities.Add(entity);

        }

این تابع بعد از این که یک entity به شکل درست ذخیره شد آن را به کش برنامه اضافه خواهد کرد.

پیاده سازی تابع GetEntity

این تابع یک تابع ساده است که با وجود کش در برنامه پیاده سازی آن بسیار آسان است. کار این تابع به این شکل است که یک id می گیرد و entity متناظر آن id را برمی گرداند. این تابع این کار را با استفاده از کش انجام می دهد. که تابع زیر این کار را انجام می دهد.

public ITProEntity GetEntity(int id)
        {
            var entity = _entities.Find(p => p.Id == id);
            return entity;
        }

پیاده سازی DeleteEntity

این تابع نیز یک عدد صحیح به عنوان id گرفته و entity مورد نظر را از داخل فایل های json و همچنین از داخل کش حذف می کند. کد این تابع به این شکل است:

 public void DeleteEntity(ITProEntity entity)
        {
			File.Delete(GetFilename(entity.Id.Value));
            _entities.Remove(entity);
        }

تا این جای برنامه فقط سرویس چهار عمل اصلی CRUD را با استفاده از فایل ها نوشتیم. در ادامه به ساختن ویو ها خواهیم پرداخت که از این کلاس استفاده کند.

طراحی رابط کاربری

تا قبل از این بخش مباحث اندروید به بررسی ساختار اندروید و نرم افزار Xamarin و همچنین نحوه ساخت یک مکانیز ذخیره سازی برای اندروید بود. ما تا قبل از این بخش به طور رسمی وارد برنامه نویسی اندروید نشده ایم. اما در این بخش می خواهیم به ساختن رابط کاربری (UI) بپردازیم. توضیحاتی که در این بخش ارائه خواهد شد با همان پروژه ITProApp خواهد بود.

ساختن layout مربوط به ListView

وقتی که یک پروژه می سازیم به طور پیش فرض یک Layout و activity ساخته می شود. برای این که فایل های مورد نظر خودمان را بسازیم به جای حذف فایل های گفته شده آنها را تغییر نام داده و کد های اضافی را حذف می کنیم. بنابراین مراحل زیر را دنبال کنید:

    1. فایل main.axml را در مسیر Resources//Layout را انتخاب کنید.
    2. بر روی این فایل کلیک راست کرده و با استفاده از گزینه Rename نام آن را به ITProList.axml تغییر دهید.
    3. بر روی این فایل دابل کلیک کنید و آن را باز کنید.
    4. دکمه Hello World را حذف کنید.
    5. فایل MainActivity.cs را انتخاب کرده و نام آن آن را به ITProListActivity.cs تغییر دهید.
    6. این فایل را باز کنید. در داخل این فایل یک کلاس وجود دارد که نام آن را به ItproListActivity تغییر دهید.
    7. مقدار Layout ID ارجاع شده را در قسمت SetContentView() به Resources.Layout.ITProList تغییر دهید. کد های مربوط به برنامه Hello World را حذف کنید. کلاس شما باید به شکل زیر باشد.
[Activity (Label = "ITProApp", MainLauncher = true)]
public class ItproListActivity : Activity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
SetContentView (Resource.Layout.ITProList );
}
}

حال باید یک ویجت ListView از جعبه ابزار(Toolbox) به برنامه اضافه کنیم. جعبه ابزار برنامه ویجت های مورد نیاز شما را دارد. در جعبه ابزار قسمتی هم برای جستجو وجود دارد که در صورتی که تعداد ویجت ها زیاد است می توانید از این قسمت آنها را جستجو کنید. از داخل جعبه ابزار ListView را انتخاب کرده و آن را به داخل قسمت طراحی رابط کاربری بکشید. حال اگر این ویجت را در قسمت طراحی انتخاب کنید می توانید مشخصات آن را در پنجره ی Properties ببینید.

همچنین در پنجره ی Properties می توانید مشخصات و ویژگی های هر ویجت را تغییر دهید. ListView را انتخاب کرده و نام ID آن را در پنجره ی properties به itproListView تغیر دهید. در قسمت layout- view group مقادیر width و height را به match_parent تغییر دهید. این کار باعث می شود که ListView همه صفحه را بگیرد. حال به بررسی قسمت طراحی رابط کاربری می پردازیم. این پنجره از دو قسمت Content و Source ساخته شده است.

در قسمت Content همه عناصری را که طراحی کرده ایم می بینید و در قسمت Source محتویات فایل xml آن را مشاهده خواهید کرد. اگر شما بخواهید که با استفاده از کد xml رابط کاربری خود را طراحی کنید می توانید در قسمت Source این کار را انجام دهید. حال به ویجت ListView برمی گردیم. پلتفرم اندروید چند layout پیش فرض برای ListView ارایه کرده است. که این Layout ها به شرح زیر می باشند.

  • SimpleListItem1 شامل یک خط و یک فیلد caption است
  • SimpleListItem2 یک layout دو خطی است که فونت آن برای فیلد اول بزرگتر و روشن تر است.
  • TwoLineListItem یک layout دو خطی با فونت مساوی برای هر دو خط است ولی متن خط اول روشن تر است.
  • ActivityListItem یک layout یک خطی با یک عکس


برای این که کنترل بیشتری روی layout ها داشته باشیم می توانیم خودمان layout های سفارشی بسازیم. که ما در پروژه خود از این نوع کنترل ها خواهیم ساخت. برای ساخت layout جدید در پنجره ی Solution به مسیر Resources//Layout بروید بر روی پوشه Layout کلیک راست کرده و گزینه Add| New File را انتخاب کنید و در پنجره ی ظاهر شده از قسمت Android گزینه Android Layout را انتخاب نمایید و برای نامه آن ItproListItem را انتخاب می کنیم سپس پنجره را تایید کنید. راه های متفاوتی برای ساختنLayout مورد نظر وجود دارد ولی ما از RelativeLayout استفاده خواهیم کرد. Layoutی که قرار است ما بسازیم شبیه دیاگرام شکل زیر است.

وب سایت توسینسو

قسمت های تشکیل دهنده ی دیاگرام بالا به شرح زیر است:

  • • یک گروه ویو(View group) به نام RelativeLayout در بالاترین سطح استفاده شده است که همه کنترل ها را در بر بگیرد. این گروه ویو گزینه های مختلفی در اختیار ما می گذارد.
  • • یک ویجت ImageView برای نمایش عکس قرار داده شده است که در سمت چپ قرار داده شده است.
  • • دو عدد ویجت TextView که برای نمایش نام و آدرس قرار داده شده اند که در سمت راست ویجت image قرار دارند. برای این که این ویجت های text درست در جای خود سازماندهی شوند از یک ویجت LinearLayout استفاده کرده ایم و ویجت های text را در داخل آن قرار داده ایم.

طراحی صفحه به شکل دیاگرام بالا

در گام اول طراحی دیاگرام بالا باید یک گروه ویو به نام RelativeLayout به داخل صفحه بیاوریم. برای این کار بعد از این که فایل ItproListItem.axml را ساختیم آن را باز می کنیم و با کلیک بر روی صفحه داخلی این فایل گروه ویو ی LinearLayout را انتخاب کرده و سپس آن را حذف می کنیم. برای حذف کردن بر روی آن کلیک راست کرده و Delete را انتخاب می نماییم.

بعد از حذف این گروه ویو از جعبه ابزار یک گروه ویو به نام RealativeLayout انتخاب کرده و به داخل صفحه طراحی بکشید. بعد از این که این گروه ویو را به داخل صفحه اضافه کردیم باید به تنظیم آن بپردازیم. برای تنظیم کردن آن به پنجره یproperties رفته و گزینه ی Padding را 5dp قرار دهید. این گزینه مشخص می کند که چه مقدار فاصله باید از حاشیه ها داشته باشیم. همچنین گزینه Layout Height را نیز به wrapcontent و گزینه ی Layout Width را به matchparent تنظیم کنید.

در گام بعدی باید که ویجت ImageView را به صفحه اضافه کنیم. برای این کار از داخل جعبه ابزار این کنترل را به درون صفحه بکشید.و در قسمت properties مقدار id آن را به id//itproImage+@ و مقادیر طول و عرض آن را به 65dp تنظیم کنید. برای تنظیم طول و عرض از قسمت Layout مقادیر minWidth و minHeight تنظیم می شود. در قسمت Layout-Relative Layout مقدار Layout_centerVertical را برابر true قرار دهید.

افزودن یک ویجت LinearLayout

یک گروه ویو LinearLayout را برای قرار دادن مقادیر نام و آدرس در صفحه قرار می دهیم. برای این کار، یک گروه ویو (LinearLayout (vertical را از داخل جعبه ابزار به داخل صفحه قرار می دهیم. برای اضافه کردن این ویجت به صفحه باید کمی دقت کنید که این ویجت را به سمت راست ویجت عکس ببرید تا زمانی که گوشه ی آن آبی شود سپس کلیک موس را رها کنید. بعد از اضافه کردن این ویجت در قسمت Layout-Relative Layout مقدار Layout_centerVertical را برابر true قرار دهید.

افزودن کلاس های TextView مربوط به نام و آدرس

برای این کار یک کنترل TextView به داخل گروه ویو LinearLayout بکشید و وقتی که آبی شد آن را رها کنید. به پنجره ی Properties رفته و مقدار textSize آن را 25sp و مقدار Text آن را به Name قرار دهید همچنین مقدار id را به id//nameText+@ تغییر می دهیم. ویجتی که اضافه کردیم برای نمایش نام بود حال به همین صورت یک ویجت TextView دیگر به داخل LinearLayout اضافه می کنیم ولی مقدار textSize آن را 15sp قرار می دهیم که اندازه متن آن کوچکتر باشد و مقدار Text آن را به Address تنظیم می کنیم و مقدار id آن را به id//addressText+@ تغییر می دهیم.

ساخت لیستی از آیتم های موجود برای نمایش

برای این کار راه های متفاوتی وجود دارد که همه ی این راه ها استفاده از Adapter ها می باشد. Adapter ها کلاس هایی هستند که از کلاس BaseAdapter مشتق می شوند و یا اینترفیس IListAdapter را پیاده سازی می کنند. برای لیست های ساده می توانید از <ArrayAdapter<T استفاده کنید.

instance اشتراکی برای IITProDataService

قبل از این که یک adapter بسازیم باید بدانیم که چگونه قرار است به به سرویس داده مان دسترسی داشته باشیم. زیرا که این سرویس داده منبع ما برای ذخیره داده های Itpro می باشد. برای این کار از الگوی طراحی singleton استفاده می کنیم. که شکل آن به این صورت است.

using System.IO;
    using Android.OS;

    public class ITProData
    {
        public static readonly IITProDataService Service = new
            ItproJsonService(Path.Combine(Environment.ExternalStorageDirectory.Path,"ITProApp"));
    }

توجه داشته باشید که ما در این برنامه از کلاس Android.OS.Environment استفاده کرده ایم. این کلاس به این منظور استفاده می شود که دایرکتوری مربوط به کارت حافظه موبایل شما را پیدا کنیم. دلیل استفاده از این دایرکتوری این است که اطلاعات ما از بین نمی رود و فقط وقتی برنامه را از روی دستگاه uninstall بکنیم این اطلاعات حذف خواهند شد. همچنین دیگر برنامه ها نیز به راحتی می توانند از این برنامه ها استفاده نمایند.

مجوزها Permissions

برنامه های اندرویدی باید یک سری مجوزها داشته باشند تا بتوانند اعمال خاصی را انجام دهند. یکی از این اعمال نوشتن در حافظه خارجی دستگاه است. شما باید این مجوز ها را در فایل AndroidManifest.xml به برنامه بدهید. مجوزها هنگام نصب برنامه به کاربر نشان داده می شوند.

برای دادن این مجوزها به برنامه باید این گونه عمل کنیم که اگر از برنامه ویژوال استودیو برای برنامه نویسی استفاده می کنید بر روی نام پروژه کلیک راست کرده و از منوی ظاهر شده properties را انتخاب می کنیم و از قسمت Android manifest در قسمت required permissions مجوز های مورد نظر را تیک بزنید با این کار مجوز های مورد نظر به فایل AndroidManifest.xml اضافه خواهد شد.

اما اگر برای برنامه نویسی از xamarin studio استفاده می کنید بر روی نام پروژه کلیک راست کرده و گزینه options را انتخاب کرده و در قسمت Android Application از قسمت Required permissions مجوز های مورد نظر خود را انتخاب کنید.

ساخت ITProListViewAdapter

برای ساخت این adapter سفارشی اینگونه عمل می کنیم:

یک کلاس به برنامه اضافه می کنیم و نام آن را ITProListViewAdapter قرار می دهیم و کلاس را public معرفی می کنیم و همچنین این کلاس باید از کلاس <BaseAdapter<ITProEntity ارث بری داشته باشد. با این کار adapter ما ساخته می شود. حال باید constructor را تعریف کنیم.

پیاده سازی Constructor

وقتی که یک نمونه از این کلاس ساخته می شود برای این که ملزومات اجرای این کلاس فراهم شود باید در زمان ساخته شدن نمونه از این کلاس این ملزومات را به کلاس داده برای این کاراز constructor کلاس استفاده می کنیم. ما برای اجرا به یک activity نیاز داریم که یک activity در داخل کلاس معرفی می کنیم و در داخل constructor آن را مقداردهی می کنیم. که کد آن به شکل زیر خواهد بود

private readonly Activity _context;

        public ITProListViewAdapter(Activity context)
        {
            _context = context;
        }

پیاده سازی سایر قسمت های کلاس adapter

قسمت هایی که در این کلاس وجود دارد و باید آن ها را پیاده سازی کنیم چند عدد تابع و property هستند. که به توضیح آنها می پردازیم:

  • Count با استفاده از این مشخصه می توان تعداد داده ها را پیدا کرد که پیاده سازی این مشخصه بر عهده برنامه نویس، یعنی شما می باشد. برای پیاده سازی این مشخصه باید تعداد entity های موجود را اعلام کنیم.
  • GetItemId: این تابع یک مقدار عددی که همان محل قرار گیری یک entity است را می گیرد و مقدار id آن را برمی گرداند.
  • پیاده سازی getter مربوط به اندیس: این کلاس می تواند اندیس محل قرار گیری یک entity را گرفته و خود آن entity را برگرداند. برای این کار باید قسمت get مربوط به مشخصه این کلاس را پیاده سازی نماییم. که پیاده سازی این قسمت به این شکل خواهد بود.


public override ITProEntity this[int position]
        {
            get { return ITProData.Service.ITPros[position]; }
        }

متدها و شکل کلی کلاسی که تاکنون پیاده سازی کرده ایم به این شکل خواهد بود.

public class ITProListViewAdapter : BaseAdapter<ITProEntity>
    {
        private readonly Activity _context;

        public ITProListViewAdapter(Activity context)
        {
            _context = context;
        }

        public override int Count
        {
            get { return ITProData.Service.ITPros.Count; }
        }

        public override ITProEntity this[int position]
        {
            get { return ITProData.Service.ITPros[position]; }
        }

        public override long GetItemId(int position)
        {
            return ITProData.Service.ITPros[position].Id.Value;
        }
    }

پیاده سازی ()GetView

از داخل همه متدهایی که باید برای adapter پیاده سازی شوند، پیاده سازی همه آنها توضیح داده شد و فقط متد GetView باقی مانده است. این متد یک View را برمی گرداند که کلاس Adapter از آن به عنوان یک سطر استفاده می نماید برای نمایش entityهای موجود. ما برای ساخت این ویو از همان ویویی که فایل layout آن را ساخته ایم یعنی ItproListItem استفاده می کنیم و از آن یک ویو می سازیم. اگر بخواهیم به ازای هر entity که داریم یک ویو بسازیم کارایی برنامه پایین خواهد آمد.

به همین منظور خود کلاس adapter در متد GetView دارای یک پارامتر ورودی است که convertView نام دارد و این همان ویویی است که بار اول مورد استفاده قرار گرفته شده است. ما در داخل متد GetView باید مقادیر ویجت هایی را که برروی ویو خود قرار داده ایم نیز مشخص می کنیم. به همین منظور باید با استفاده از تابع FindViewById تک تک ویجت ها را لود کرده و مقدار آن ها را مشخص کنیم. همچنین در برنامه ما ممکن است که فیلد آدرس دارای هیچ مقداری نباشد در این صورت نباید نشان داده شود.

برای این کار ما خصوصیت visibility مربوط به این ویو را برابر با gone قرار می دهیم. لازم به ذکر است که مقادیری که ممکن است به خصوصیت visibility بدهیم شامل Gone, visibel, invisible می باشد که اگر ما مقدار visible را قرار دهیم ویو به صورت عادی دیده خواهد شد. اما در هر دو صورت invisible و Gone ویو نشان داده نمی شود. تفاوت این دو مقدار در این است که اگر یک ویو invisible باشد جایی را که برای آن در صفحه در نظر گرفته بودیم باقی می ماند ولی در صورتی که Gone ار انتخاب کرده باشیم اینگونه نیست. در نهایت متد GetView به شکل زیر در کلاس ITProListViewAdapter پیاده سازی می شود.

public override View GetView(int position, View convertView, ViewGroup parent)
        {
            var view = convertView;
            if (view == null)
                view = _context.LayoutInflater.Inflate(Resource.Layout.ItproListItem, null);
            var entity = ITProData.Service.ITPros[position];
			view.FindViewById<TextView> (Resource.Id.nameText).Text=entity.Name;
            if(string.IsNullOrEmpty(entity.Address))
                view.FindViewById<TextView>(Resource.Id.addressText).Visibility=ViewStates.Gone;
            else
            view.FindViewById<TextView>(Resource.Id.addressText).Text = entity.Address;
            return view;
        }

این تابع به ازای هر enitity صدا زده می شود و مقادیر مربوط به آن را که با اندیس position شناخته می شود را پر می کند.

استفاده از ITProListViewAdapter برای نمایش اطلاعات

آخرین قدمی که برای استفاده از adapter در برنامه باید برداشته شود این است که از آن برای ListView استفاده شود. برای این کار در فایل ITProListActivity دو متغیر زیر را تعریف می کنیم.

ListView _poiListView;
POIListViewAdapter _adapter;

حال در متد OnCreate باید یک نمونه از ITProListViewAdapter بسازیم و آن را به Listview متصل کنیم برای این کار تابع OnCreate را به این شکل می نویسیم.

 protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

           
            SetContentView(Resource.Layout.ITProList);
            _itproListView = FindViewById<ListView>(Resource.Id.itproListView);
            _adapter=new ITProListViewAdapter(this);
            _itproListView.Adapter = _adapter;
           
        }

تا اینجای کار ما توانستیم که برنامه ای برای نمایش اطلاعات از داخل فایل های ذخیره شده در کارت حافظه را نوشتیم. می توانید این برنامه را با استفاده از دستگاه های واقعی و یا شبیه ساز اجرا کنید. باید دقت داشته باشید که اگر برنامه را با شبیه ساز اجرا می کنید باید مقداری برای حجم کارت حافظه در نظر گرفته باشید. شما وقتی برنامه را اجرا می کنید به دلیل این که هنوز اطلاعاتی در داخل حافظه شما برای نمایش نیست هیچ آیتمی را در صفحه نخواهید دید :D در قسمت های آینده به شما خواهیم گفت که چگونه این اطلاعات را وارد کنید و نمایش دهید.

ساخت منوی اصلی

در بخش های قبل برای هر برنامه اندروید می توان اکشن هایی را به قسمت اکشن آن در بالای صفحه دستگاه در زیر قسمت status bar اضافه کرد. ما در این برنامه دو اکشن برای کلاس ITProListActivity ایجاد خواهیم کرد که به صورت منو در بالای صفحه نمایش داده خواهند شد. این اکشن ها عبارتند از: New که یک موجودیت (entity) جدید به وجود می آورد و دیگری Refresh که کش را بازسازی می کند و محتویات آن را از حافظه محلی می خواند. برای این که یک منو در یک activity بسازیم باید توابع زیر را override نماییم.

    1. OnCreateOptionsMenu این تابع اجازه می دهد که اکشن ها با استفاده از API ها و یا فایل های XML ساخته شوند.
    2. OnOptionsItemSelected: این تابع وقتی صدا زده می شود که برروی منوی اکشن ها کلیک شود. برای این که مشخص کنیم که وقتی هرکدام از گزینه ها کلیک شد چه عملی انجام شود باید از این تابع استفاده کنیم.

ساخت فایل xml مربوط به منو

منو ها و اکشن ها می توانند در داخل یک فایل xml تعریف شوند. که این فایل های xml مربوط به منو ها باید در مسیر پوشه Resources/menu مربوط به پروژه قرار بگیرند. شما می توانید که منو ها را با فراخوانی API ها نیز بسازید. ما منوهای خود را در همان برنامه که قبلا نیز به ساخت آن پرداخته بودیم خواهیم ساخت. کار ساخت منوها در اندروید را ب استفاده از فایل های xml خواهیم گفت. نام فایل xml ساخته شده برای صفحه اصلی در این برنامه ItproListViewMenu.xml می باشد. برای ساخت این منو به شکل زیر عمل می کنیم.

  1. بر روی پوشه ی Resources در قسمت پروژه کلیک راست کرده و گزینه Add|New Folder را انتخاب می کنیم.
  2. از کادر ظاهر شده نام پوشه مورد نظر را menu می گذاریم. با این کار یک پوشه به نام menu در داخل پوشه Resources ساخته می شود. توجه داشته باشید که همه ی فایل های xml مربوط به منوها در برنامه در این پوشه نگهداری می شوند.
  3. برروی پوشه menu کلیک راست کرده و گزینه Add|New File را انتخاب می کنیم.
  4. از پنجره ی ظاهر شده گزینه XML file را انتخاب می کنیم. و نام آن را ItproListViewMenu.xml قرار می دهیم. با این کار فایل مورد نظر شما در پوشه مورد نظر ساخته می شود. حال باید منو ها و گزینه های هر منو را در داخل آن تعریف کنیم.

متاسفانه xamarin قالب از پیش تعریف شده ای برای تعریف منو ها ندارد و ابزاری هم برای ساخت و تولید کد مربوط به منوها در خود ندارد برای همین شما باید این قالب را از داخل مستندات اندروید که داخل اینترنت موجود می باشد پیدا کنید. کد زیر نحوه تعریف دو اکشن new و refresh را نمایش می دهد.

<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/actionNew"
android:icon="@drawable/ic_new"
android:title="New"
android:showAsAction="ifRoom" />
<item android:id="@+id/actionRefresh"
android:icon="@drawable/ic_refresh"
android:title="Refresh"
android:showAsAction="ifRoom" />
</menu>

به این نکته توجه داشته باشید که ما برای هرکدام از آیتم های منوی خود یک آیکن در نظر گرفته ایم که محل آن در پوشه ی drawable می باشد. که نام های آنها icnew و icrefresh می باشد.

کد فراخوانی منو از فایل xml

برای این که از فایل xml که در قسمت قبلی ساختیم تبدیل به یک منو شود باید از تابع OnCreateOptionsMenu که در داخل activity قرار دارد استفاده کنیم و آن را override نماییم. کلاس activity یک متد MenuInflater دارد که فایل های xml مربوط به منو ها را خوانده و آنها را تبدیل به منو می نماید بنابراین ما نیز برای ساختن منوی خود از این متد استفاده خواهیم کرد. کد زیر نحوه پیاده سازی منو را شرح می دهد.

 public override bool OnCreateOptionsMenu(IMenu menu)
        {
            MenuInflater.Inflate(Resource.Menu.ItproListViewMenu,menu);
            return base.OnCreateOptionsMenu(menu);
        }

مدیریت انتخاب آیتم های یک منو

وقتی که یکی از آیتم های منو انتخاب می شوند تابع OnOptionsItemSelected فراخوانی می شود. این تابع در داخل کلاس activity قرار دارد. این تابع یک ورودی از اینترفیس IMenu دارد. ما باید داخل این تابع بررسی کنیم که کدام یک از آیتم ها انتخاب یا کلیک شده است و با توجه به آن عمل مورد نظر را انجام دهیم. برای این که بدانیم کدام یک از آیتم های منو ها انتخاب شده اند از فیلد ItemId که در پارامتر ورودی تابع قرار دارد استفاده می کنیم. این فیلد همان Id تعریف شده در قسمت Resource را به ما می دهد. کد زیر نحوه پیاده سازی این تابع را نشان می دهد.

 public override bool OnOptionsItemSelected(IMenuItem item)
        {
            switch (item.ItemId)
            {
                case Resource.Id.actionNew:
                    // place holder for creating new entity
                    return true;
                case Resource.Id.actionRefresh:
                    ITProData.Service.RefreshCache();
                    _adapter.NotifyDataSetChanged();
                    return true;
                default:
                    return base.OnOptionsItemSelected(item);
            }
        }

دقت داشته باشید که ما در این پیاده سازی عمل new کاری انجام نداده ایم. این قسمت در مطالب بعدی مورد استفاده قرار خواهد

نمایش اطلاعات Entity

در قسمت های قبلی مراحل ساخت یک برنامه ساده موبایل را با استفاده از برنامه Xamarin توضیح دادیم و در ادامه نیز می خواهیم این برنامه را کامل تر کنیم.در این مطلب قصد دارم که اعمال حذف و اضافه و بروزرسانی داده ها را شرح دهم.

ساخت layout مربوط به ItproDetail

برای ساخت این layout مانند layout های قبلی بر روی پوشه layout کلیک راست کرده و گزینه Add و سپس New File را می زنیم و سپس بر روی Android Layout کلیک می کنیم و نام فایل را IptroDetail قرار می دهیم و تایید می نماییم.به طور پیشفرض هر Layout با یک LinearLayout در داخل آن ساخته می شود یعنی View group پیشفرض آن LinearLayout است. این layout ما شامل تعدادی فیلد است که ممکن است که در بعضی دستگاه ها نیاز به اسکرول کردن نیز داشته باشد.

ItproList که قبلا آن را ساخته بودیم به علت این که viewGroup اصلی آن یک ListView است به راحتی امکان اسکرول کردن را به ما می دهد ولی در این layout ما باید که از یک ScrolView استفاده کنیم. در ادامه کار ما ViewGroup مربوط به LinearLayout را از layout حذف می کنیم. برای این کار می توانیم آن را از صفحه موبایلی که به طور پیشفرض نمایش داده می شود حذف کنیم و یا به قسمت کد xml رفته و تگ مربوط به LinearLayout را یکجا حذف کنیم.

بعد از حذف آن از قسمت جعبه ابزار یک ScrolView را به صفحه می آوریم. و بر روی آن یک LinearLayout از نوع Vertical قرار می دهیم. اکنون آماده ایم که فیلد های خود را اضافه کرده و تنظیم کنیم. ما برای برچسب و لیبل گذاری هرکدام از فیلد ها از TextView استفاده می کنیم و برای خود فیلد ها از EditText استفاده خواهیم کرد. ما می خواهیم به داده های نام و شرح و آدرس که فیلد کلاس آنها قبلا تعریف شده بود مقداری نسبت بدهیم. برای این کار برای هرکدام از این متغیر ها یک Edti text در نظر می گیریم که به ترتیب نام آنها به این شکل خواهد بود.

  • nameEditText Plain text
  • descrEditText Multiline Text
  • addrEditText Multiline Text

چیزی که ما می خواهیم طراحی کنیم به این شکل می باشد.

وب سایت توسینسو

روش طراحی شکل بالا هم به گونه ای است که به ترتیب یک Text View گذاشته و متن آن را تغییر می دهیم و به دنبال آن یک EditText از انواع گفته شده قرار می دهیم و مقادیر Id و نوع آنها را تغییر می دهیم.

کارکردن با InputType و انواع ورودی ها

عنصر EditText یک ویژگی به نام InputType دارد که رفتار کنترل را مشخص می کند که چه داده ای می توان در آن وارد کرد. برای مثال وقتی که ما ویجت های شرح و آدرس را اضافه می کنیم گزینه Multiline را از جعبه ابزار انتخاب می کنیم. که این انتخاب ما باعث می شود که کد زیر به صورت اتوماتیک برای آن ویجت تولید شود.

<EditText
p1:inputType="textMultiLine"
p1:layout_width="fill_parent"
p1:layout_height="wrap_content"
p1:id="@+id/descrEditText" />

مشخصه InputType را می توان از پنجره ی properties نیز تغییر داد ولی نکته ای که باید به آن توجه داشت این است که مقادیری که این مشخصه دریافت می کند را می توان با هم ترکیب کرد و به صورت ترکیبی به کار برد. برای مثال InputType در هرکدام از عناصر گفته شده به این شکل است:

    • nameEditText inputType="textCapWords"
    • descrEditText inputType="textMultiLine|textCapSentences"
    • addrEditText inputType="textMultiLine"

ساخت اکتیویتی ItproDetail

بعد از این که layout را طراحی کردیم نوبت به استفاده از آن می رسد. برای ساخت activity همان طور که می دانید در قسمت solution کلیک راست کرده و گزینه Add| New File و Activity را اضافه می کنیم و از پنجره ی ظاهر شده نام آن را ItproDetailActivity قرار می دهیم و تایید می کنیم. همانطور که در مطالب گذشته هم گفتیم باید برای activity ساخته شده layout مربوطه را به آن نسبت بدهیم. و برای این کار باید در متد onCreate خط کد زیر را بنویسید

SetContentView (Resource.Layout.ItproDetail);

مقید کردن متغیر ها به کنترل ها

همانطور که قبلا یاد گرفتیم باید به صورت دستی ویجت هایی را که در layout ها قرار دادیم به صورت دستی به متغیرها نسبت بدهیم تا بتوان از آن ها استفاده کرد. برای این منظوع برای هر ویجت یک متغیر از همان کلاس معرفی می کنیم و با استفاده از تابع FindViewById ویجت را به متغیر نسبت می دهیم. به متغیر های معرفی شده زیر دقت کنید.

EditText _nameEditText;
EditText _descrEditText;
EditText _addrEditText;

در مثال زیر نحوه مقید کردن متغیر ها آمده است :

_nameEditText = FindViewById<EditText> (Resource.Id.nameEditText);
_descrEditText = FindViewById<EditText> (
Resource.Id.descrEditText);
_addrEditText = FindViewById<EditText> (Resource.Id.addrEditText);

حرکت بین activity ها

وقتی برنامه ای شروع به اجرا می نماید activity اصلی آن اجرا می شود. حال ما ممکن است که چندین activity در داخل برنامه خود داشته باشیم. ما باید بتوانیم که از یک activity به activityدیگر حرکت کنیم و activity های دیگر را نیز اجرا نماییم. برای این کار ما از تابع startActivity که در داخل کلاس Activity وجود دارد استفاده می کنیم. این تابع دو نوع پارامتر ورودی می تواند دریافت کند. Intent و type. Type همان انواعی هستند که می توانیم به این تابع پاس بدهیم برای مثال اگر ما بخواهیم در activity اصلی برنامه به activiy ساخته شده یعنی همان ItproDetailActivity برویم از کد زیر استفاده می کنیم.

StartActivity(typeof(ItproDetailActivity))

کد بالا ما را به activity مورد نظر انتقال می دهد. اما در بسیاری از اوقات می خواهیم وقتی از یک activity به activity دیگری انتقال یافتیم داده هایی را نیز به همراه خود ببریم. برای این کار از intent ها استفاده می نماییم. به طور مثال فرض کنید که بر روی یک خانه از لیست کلیک کرده و می خواهید که جزئیات این لیست را مشاهده نمایید. برای این کار باید مشخص شود که در activity اول بر روی کدام یک از عناصر لیست کلیک شده است تا در activity دوم بتوان مشخصات آن را نمایش داد. اگر بخواهیم کد بالا را با استفاده از intentها بنویسیم باید این گونه عمل کنیم:

var itproDetailIntent=new Intent(this,typeof(ItproDetailActivity));
StartActivity(itproDetailIntent);

شیئی که از نوع Intent ساخته می شود دارای یک مشخصه به نام Extra است که می توان با استفاده از آن داده ها را بین activity ها منتقل کرد. برای انتقال داده ها باید بعد از ساخته شدن شی از نوع Intent از متد PutExtra مربوط به آن شی استفاده کرده ومقادیری را که می خواهیم به آن نسبت بدهیم و سپس تابع StartActivity() را فراخوانی نماییم. برای مثال به کد زیر دقت نمایید:

var itproDetailIntent=new Intent(this,typeof(ItproDetailActivity));
itproDetailIntent.PutExtra("itproId",entity.Id);
StartActivity(itproDetailIntent);

همانطور که می بینید متد PutExtra یک کلید رشته ای می گیرید که در activity مقصد با استفاده از این کلید می توان مقدار این داده را خواند.حال اگر بخواهیم که این مقادیر را در activity مقصد دریافت کنیم با توجه به این که نوع داده ارسالی چه بوده است می توانیم از متد مناسب آن استفاده نماییم. برای مثال اگر در activity مبدا ما یک مقدار عددی به تابع putExtra داده باشیم در activity مقصد باید از تابع GetIntExtra() استفاده کنیم.

این توابع در کلاس Intent قرار دارند و علاوه بر دریافت کلید رشته ای که در activity مقصد به آن داده شده بود یک مقدار پیش فرض نیز دریافت می نمایند. همچنین برای این که بدانیم از طرف activity مقصد اطلاعاتی با یک کلید خاص ارسال شده است از تابع HasExtra استفاده می کنیم. خروجی این تابع یک مقدار boolean است که اگر کلید مورد نظر مقدار داشته باشد مقدار درست و در غیر این صورت مقدار غلط برمی گرداند.ما قطعه کد زیر را برای دریافت Id در activity مربوط به ItproDetail نوشته ایم. توجه داشته باشید که این کد باید ابتدای کار activity اجرا شود بنابر این آن را در داخل تابع OnCreate برنامه می نویسیم.

 private ITProEntity entity;
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            SetContentView(Resource.Layout.ItproDetail);
            if (Intent.HasExtra("ItproId"))
            {
                int entityId = Intent.GetIntExtra("ItproId", -1);
                entity = ITProData.Service.GetEntity(entityId);
            }
            else entity=new ITProEntity();
        }

بعد از همه این توضیحات قصد داریم که اطلاعات یک entity را در ItproDetail نمایش دهیم. از ItproDetail علاوه بر نمایش اطلاعات یک Entity می توان برای افزودن و یا ویرایش اطلاعات نیز استفاده کرد. برای این کار ما با استفاده از کد بالا ابتدا چک می کنیم که کدام یک از entity ها باید لود شده و نمایش داده شود سپس با استفاده از قطعه کد زیر به bind کردن ویجت های می پردازیم و سپس توسط تابع UpdateUI آنها را در صفحه نمایش می دهیم.

این تابع به این شکل است که تک تک اطلاعات را به تک تک ویجت ها مقدار دهی می کند برای این کار باید از مشخصه text هرکدام از ویجت ها استفاده کنیم. اگر شما قبلا با کنترل های ویندوزی در C# آشنا باشید با این قسمت مشکلی نخواهید داشت. کد زیر مقادیر نوشته شده برای اکتیویتی ItproDetailActivity را تا اینجا نمایش می دهد.

namespace ItproApp
{
    using Android.App;
    using Android.OS;
    using Android.Widget;
    using ITProApp.Classes;

    [Activity(Label = "ItproDetailActivity")]
    public class ItproDetailActivity : Activity
    {
        private ITProEntity entity;
        private EditText nameText, descrText, addressText;
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            SetContentView(Resource.Layout.ItproDetail);
            if (Intent.HasExtra("ItproId"))
            {
                int entityId = Intent.GetIntExtra("ItproId", -1);
                entity = ITProData.Service.GetEntity(entityId);
            }
            else entity=new ITProEntity();
            nameText = FindViewById<EditText>(Resource.Id.nameEditText);
            descrText = FindViewById<EditText>(Resource.Id.descrEditText);
            addressText = FindViewById<EditText>(Resource.Id.addressEditText);
            UpdateUI( );
        }

        private void UpdateUI()
        {
            nameText.Text=entity.Name;
            descrText.Text = entity.Description;
            addressText.Text = entity.Address;
        }
    }
}

برای این که از activity اصلی که لیست entity های موجود را به ما نشان می دهد بتوانیم با کلیک بر روی هر entity به این قسمت وارد شویم باید این گونه عمل کنیم که وقتی روی یک عنصر از لیست کلیک شد Id آن عنصر را به عنوان پارامتر مربوط به Activity به intent ارسال نماییم. برای این کار کد زیر را در داخل تابع OnCreate اکتیویتی اصلی یعنی ItpoListActivity بنویسید:

 _itproListView.ItemClick += (sender, args) =>
            {
                var itproDetailIntent = new Intent(this, typeof(ItproDetailActivity));
                itproDetailIntent.PutExtra("itproId", args.Id);

                StartActivity(itproDetailIntent);
            };

در کد بالا یک رویداد نوشتیم که وقتی که بر روی یک آیتم از لیست کلیک شود این رویداد فراخوانی می شود. همچنین پارامتر ورودی args دارای مشخصات آیتمی که روی آن کلیک شده است می باشد که ما از مشخصه Id آیتم مورد نظر در این برنامه استفاده کرده ایم. تا این قسمت از مطالب نحوه انتقال از یک Activity به activity دیگر را نوشتیم. و همچنین امکان انتقال اطلاعات از یک activity به activity دیگر را نیز شرح دادیم. در قسمت های بعدی به مراحل اضافه یا حذف کردن اطلاعات در این برنامه خواهیم پرداخت.

ذخیره و حذف

در ادامه مطالب برنامه نویسی اندروید با استفاده از زبان C# و برنامه xamarin در خدمت شما هستیم. در ادامه مباحث به افزودن اکشن های save و delete به برنامه می پردازیم. که اکشن delete یک موجودیت رو از حافظه پاک می کند و اکشن Save یک موجودیت را در دستگاه ذخیره می نماید.

حال ببینیم برای اضافه کردن این اکشن ها به برنامه باید چه کارهایی انجام دهیم. برای این کار ابتدا باید رابط کاربری آن را بسازیم. ما برای این که این اکشن ها را به برنامه اضافه کنیم از ActionBar استفاده می کنیم. برای این کار باید یک فایل منوی جدید به نام ITproDetailMenu می سازیم و کد زیر را در درون آن قرار می دهیم.

<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/actionSave"
android:title="Save"
android:showAsAction="ifRoom" />
<item android:id="@+id/actionDelete"
android:title="Delete"
android:showAsAction="ifRoom" />
</menu>

این کد نام و تعداد منوها را تعریف می کند. همانطور که قبلا هم گفتیم برای این که بتوانیم با منو ها کار کنیم باید دستورات مربوط به منو ها را داخل متد های onCreateOptionMenu و onOptionsItemSelected بنویسیم. کد زیر این متدها را نشان می دهد.

public override bool OnCreateOptionsMenu(IMenu menu)
{
MenuInflater.Inflate(Resource.Menu.ITproDetailMenu, menu);
return base.OnCreateOptionsMenu(menu);
}
public override bool OnOptionsItemSelected (IMenuItem item)
{
switch (item.ItemId)
{
case Resource.Id.actionSave:
SaveItpro ();
return true;
case Resource.Id.actionDelete:
DeleteItpro ();
return true;
default :
return base.OnOptionsItemSelected(item);
}
}

ما برای این که کد متد onOptionsItemSelected را تمیز نگه داشته باشیم دو تابع SaveItpro و DeleteItpro استفاده کرده ایم که بعدا کد داخل این توابع را بیان خواهیم کرد.

غیرفعال کردن اکشن Delete

در برخی مواقع اتفاق می افتد که ما می خواهیم برخی از کاربردها و اکشن های برنامه غیرفعال باشند. مثلا ما می خواهیم که کاربرنتواند برخی آیتم ها را حذف کند. برای این کار ما باید این عمل غیر فعال کردن را در داخل متد onPrepareOptionMenu که در داخل کلاس activity است پیاده سازی کنیم. اگر ما کد زیر را برای متد گفته شده بنویسیم اکشن Delete غیر فعال خواهد شد.

public override bool OnPrepareOptionsMenu (IMenu menu)
{
base.OnPrepareOptionsMenu (menu);

if (!_entity.Id.HasValue) {
IMenuItem item =
menu.FindItem (Resource.Id.actionDelete);
item.SetEnabled (false);
}
return true;
}

به این نکته دقت داشته باشید که اینترفیس IMenu یک متد با نام FindItem دارد که می تواند به ارجاعات به آیتم های هر منو را در خود نگهداری کند.و به آنها دسترسی داشته باشد و همچنین می توان با استفاده از تابع SetEnabled یک آیتم را فعال یا غیرفعال نمود.

نوشتن تابع SaveItpro()

ما برای این که کد زیاد در داخل متد onOptionItemSelected قرار ندهیم و کل منطق ذخیره را در داخل آن ننویسیم یک تابع جدید به نامه SaveItpro() ساختیم که این تابع باید کارهای زیر را انجام دهد.

  1. ورودی کاربر را اعتبارسنجی نماید.
  2. مقادیر وارد شده را از ویجت های کاربر بگیرد و در داخل Entity ذخیره کند.
  3. متد SaveEntity را از ItporJsonService فرخوانی نماید.
  4. اکتیویتی ItporDetailActivity را ببندد.

اعتبارسنجی ورودی به این معنی است که آیا کاربر داده درست وارد کرده است یا خیر که اگر ورودی درست وارد نکرده بود باید به کاربر خطا داد و تا آن را درست نماید. برای مثال در این برنامه فیلد نام نباید خالی باشد برای این کار باید فیلد نام را اعتبارسنجی نماییم. برای اعتبارسنجی یک فیلد از فیلدError مربوط به editText استفاده می کنیم. در کد زیر یک گفته ایم که اگر مقدار nameEditText خالی باشد باید خطا نمایش داده شود.

var error=false;
if (String.IsNullOrEmpty (_nameEditText.Text)) {
nameEditText.Error = "مقدار نام نباید خالی باشد";
error=true;
}
else{
nameEditText.Error = null;
error=false;}
if(error)return;

با این کد هرگاه مقدار نام خالی باشد و بخواهیم عمل ذخیره سازی را انجام دهیم با پیام شکل زیر روبرو خواهیم شد و ادامه کد ذخیره اجرا نخواهد شد.

وب سایت توسینسو

در کل کد متد SaveItpro() به شکل زیر است:

 public void SaveItpro()
        {
                  var error = false;
            if (String.IsNullOrEmpty(nameEditText.Text))
            {
                nameEditText.Error = "مقدار نام نباید خالی باشد";
                error = true;
            }
            else
            {
                nameEditText.Error = null;
                error = false;
            }

            if (error) return;
            entity.Name = nameEditText.Text;
            entity.Description = descrEditText.Text;
            entity.Address = addrEditText.Text;
            ItproData.Service.SavePOI(entity);
            Finish();
        }

دقت داشته باشید که تابع Finish() باعث بسته شدن activity جاری می شود.

نوشتن تابع DeleteItpro()

در داخل این تابع باید دو عمل انجام شود. 1.رکورد موجود حذف شود. 2.activity بسته شود.

 protected void DeleteItpro()
        {
            ItproData.Service.DeleteEntity(entity);
            Finish();
        }

در انجام بعضی از دستورات کاربر باید مطمئن شویم که کاربر سهوا این کار را انجام نداده و از انجام آن مطمئن است. یکی از این کارها حذف داده ها می باشد. عموما برای این کار بعد از این که کاربر دستور حذف داده ها را می دهد یک سوال از او پرسیده می شود و در صورت تایید کاربر داده حذف می شود. حال ما می خواهیم بدانیم این سوال را در اندروید چگونه باید از کاربر بپرسیم. برای این کار از کلاس های AlertDialog و AlertDialog.Builder در اندروید استفاده می کنیم. این کلاس ها به شما اجازه می دهند که یک کادر سوال بسازید که گزینه های مختلفی برای انتخاب دارند و با انتخاب هر کدام از گزینه ها کار بخصوصی انجام خواهد شد. برای ساخت این کادر سوال باید مراحل زیر را انجام دهیم.

    1. یک نمونه از کلاس AlertDialog.Builder بسازیم.
    2. ویژگی های مختلف کادر باز شده از جمله پیامی که قرار است نشان داده شود و نوشته ی مربوط به هر دکمه و عملی که با کلیک بر روی هر دکمه قرار است انجام شود و ...
    3. فراخوانی متد Show() از شی کلاس Builder تا پیام را نمایش دهد. در برنامه ما یک کادر سوال با گزینه های تایید و لغو وجود دارد که اگر کاربر تایید کرد داده مورد نظر حذف شود.
    4. ساخت یک event handler که بعد از تایید کاربر حذف داده و بسته شدن اکتیویتی که در داخل اکشن Delete نوشته بودیم را به آنجا انتقال دهیم.
    5. افزودن منطق ساخت کادر تایید به متد DeleteItpro() که کد زیر را داخل این متد می نویسیم.
protected void DeleteItpro()
        {
            AlertDialog.Builder alertConfirm =
			new AlertDialog.Builder(this);
			alertConfirm.SetCancelable(false);
			alertConfirm.SetPositiveButton("OK", ConfirmDelete);
			alertConfirm.SetNegativeButton("Cancel", delegate {});
			alertConfirm.SetMessage(String.Format("Are you sure you
			want to delete {0}?", entity.Name));
			alertConfirm.Show();

        }

نشان دادن پیام موفقیت

ما می خواهیم بعد از این که داده حذف شد خبر موفقیت آمیز بودن پیام به کاربر نمایش داده شود. در اندروید این گونه پیام ها را که فقط حالت خبری دارند و می خواهند کاربر از چیزی اطلاع یابد را با کلاس Toast نشان می دهند. این کلاس یک پیام در پایین صفحه به مدت چند ثانیه نشان می دهد. برای نمایش این پیام به این شکل عمل می کنیم:

Toast.MakeText(this,"Data deleted",ToastLength.Short).Show();

این خط کد را در قبل از خط Finish() قرار می دهیم.

بازسازی ItproListActivity

اگر ما عمل Save و یا Delete را در برنامه انجام دهیم تعداد داده های موجود کم یا زیاد خواهد شد. برای همین باید لیستی که داده ها را نمایش می دهد را بازسازی کنیم که اگر داده ای حذف شده باشد آن را حذف کند و اگر داده جدیدی ساخته شده است آن را به لیست اضافه کند. برای این کار باید به adapter بگوییم که داده ها تغییر کرده اند و خود را بروز کند برای این کار در متد OnResume مربوط به Activity باید کد زیر را بنویسیم.

protected override void OnResume (){
base.OnResume ();
_adapter.NotifyDataSetChanged ();
}

تا این قسمت از مطالب نحوه ذخیره سازی و خواندن اطلاعات و نمایش آن با استفاده از ویجت های اندروید در Xamarin آموزش داده شد. امیدوارم توانسته باشم کاری کنم که کاربران با مقدمات برنامه نویسی اندروید آشنا شوند. پس از این قسمت تکنیک هایی را به زبان جاوا در باره ی برنامه نویسی اندروید خواهیم گفت که با توجه به این نکته که در اندروید تفاوت زیادی نیست می توانید با کمی بررسی آن ها را در زبان C# و Xamarin هم پیاده بکنید.


مهدی عادلی فر
مهدی عادلی فر

بنیانگذار توسینسو و برنامه نویس

مهدی عادلی، بنیان گذار TOSINSO. کارشناس ارشد نرم افزار کامپیوتر از دانشگاه صنعتی امیرکبیر و #C و جاوا و اندروید کار می کنم. در زمینه های موبایل و وب و ویندوز فعالیت دارم و به طراحی نرم افزار و اصول مهندسی نرم افزار علاقه مندم.

نظرات