در این مطلب با آموزش برنامه نویسی اندروید بوسیله زامارین (Xamarin) و با زبان سی شارپ در خدمت شما هستیم. امروزه استفاده از تلفن های هوشمند بسیار مورد توجه قرار گرفته است و معمولاً کسی در کوچه و پارک و جمع های خانوادگی نیست که یک گوشی هوشمند به دستش نباشد. به همین خاطر تصمیم گرفتم آموزش برنامه نویسی اندروید بوسیله زامارین (Xamarin) به صورت رایگان و در قالب متنی برای دوستان آماده کنم.
در این قسمت قصد دارم که به معرفی تکنیکی سیستم عامل اندروید بپردازم. سیستم عامل اندروید سیستم عاملی است که روز به روز به تعداد کاربرانش افزوده می شود. این سیستم عامل به خاطر ظاهر ساده و برنامه هایی که زیاد است بسیار محبوب می باشد.
پلتفرم اندروید یکی از موفقترین پلتفرم های چند سال اخیر به حساب می آید. این پلتفرم سرویس ها و ویژگی های بسیاری برای برنامه نویسان فراهم آورده است تا بتوانند برنامه های بسیار قوی برای موبایل تولید نمایند. شکل زیر یک نمای کلی از پلتفرم اندروید و بخش های آن را نمایش می دهد.
همان گونه که در شکل می بینید، اندروید یک سیستم عامل بر مبنای لینوکس است که در اصل برای دستگاه های قابل حمل و گوشی های هوشمند و تبلت ها می باشد. ورژن آخر اندروید برمبنای کرنل لینوکس نسخه 3.x می باشد. (کرنل 2.6 برای نسخه های قبل از اندروید 4.0 بود.)
یادگیری برنامه نویسی برای متخصصین حوزه کامپیوتر این روزها یک الزام به حساب می آید. از جمله محبوب ترین زبان های برنامه نویسی دنیا می توانیم به زبان برنامه نویسی سی شارپ ، زبان برنامه نویسی جاوا ، زبان برنامه نویسی پایتون ، زبان برنامه نویسی سی پلاس پلاس و زبان برنامه نویسی SQL ( لازمه هر زبان دیگری ) و زبان برنامه نویسی PHP اشاره کنیم.
برای آموزش برنامه نویسی می توانید با خیال راحت در قالب دوره های آموزش برنامه نویسی سایت توسینسو ، آموزش سی شارپ ، آموزش جاوا ، آموزش پایتون ، آموزش جنگو ، آموزش PHP ، آموزش جاوا اسکریپت ، آموزش برنامه نویسی اندروید ، آموزش SQL و آموزش MySQL را بصورت جامع و حرفه ای آموزش ببینید.
کتابخانه های متنوعی در اندروید موجود می باشند که در شکل تعدادی از آنها نمایش داده شده اند. این مجموعه ی کتابخانه های بومی با زبان C/C++ نوشته شده اند طراحی و پیاده سازی شده است. که این کتابخانه ها سرویس های متنوعی را فراهم می نمایند. این کتابخانه عموماً از جامعه متن باز (open souce community) گرفته شده اند.
برنامه های اندروید درون ماشین مجازی Dalvik یا (Dalvik VM) اجرا می شوند که این ماشین مجازی شبیه به ماشین مجازی جاوا می باشد با این تفاوت که ماشین مجازی Dalvik برای دستگاه های با حافظه محدود و قدرت پردازشی پایین تر بهینه سازی شده اند. برنامه های اندروید ابتدا با استفاده از کامپایلر جاوا به بایت کد های جاوا کامپایل می شوند. اما این برنامه ها هنگام کامپایل یک مرحله اضافه دیگری را نیز طی می کنند و آن مرحله این است که بایت کدهای جاوا به بایت کدهای Dalvilk تبدیل می شوند تا برای اجرا در ماشین مجازی Dalvik مناسب باشد. شکل زیر تفاوت کامپایل برنامه های جاوا و اندروید را نمایش می دهد.
Dalvik با کتابخانه های هسته اندروید نوشته شده است. این کتابخانه ها مانند هیچکدام از پلتفرم های جاوا (JSE, JEE, JME) عمل نمی کنند بلکه به شکل یک پلتفرم ترکیبی از پلتفرم های گفته شده کار می کنند. پلتفرم اندروید بسیار شبیه به پلتفرم JSE می باشد با این تفاوت که کامپوننت های وابسته به رابط کاربری مانند AWT و Swing را ندارد. فریمورک کاربردی اندروید (AAF) یک سری ابزار ها برای ساخت رابط کاربری فراهم می نماید.
Application Framework بخشی از پلتفرم اندروید می باشد که برای برنامه نویسان بسیار آشنا می باشد. این فریمورک مجموعه ای از کتابخانه های جاوا می باشد و به شما اجازه می دهد که رابط کاربری بسازید، با دستگاه های مختلف مانند دوربین ارتباط برقرار کنید، منابع کاربردی مختلف را لود کرده و با آنها کار کنید و بسیاری از وظایف و task های مفید را اجرا نمایید.
در قسمت بالای پشته ای که نشان دادیم برنامه های سمت کاربر قرار دارد. این برنامه ها بخش هایی هستند که نتایج و مقادیر را به کاربر تحویل می دهند. اندروید در داخل خود دارای برنامه هایی است که کاربرد های پایه را به همراه خود دارد. این کاربردهای پایه مانند مدیریت مخاطبین، استفاده از تلفن، چک کردن ایمیل و وب گردی می باشد که اندروید در خود آنها را دارد. کلید موفقیت اندروید داشتن شمار بسیار زیاد برنامه های مختلف می باشد که توسط آن کاربران می توانند فیلم های گرفته شده با گوشی را ویرایش کنند و یا با دوستان خود ارتباط داشته باشند و بسیاری از کاربرد های دیگر که این برنامه ها برای کاربران فراهم کرده اند.
برنامه هایی که برای نصب در اختیار کاربران قرار می گیرند دارای فرمت .apk می باشند. یک پکیج (بسته) اندروید نتیجه کامپایل یک برنامه اندروید است که در یک فایل .apk بسته بندی شده است. یک بسته اندروید شامل همه کد ها و فایل های مورد نیزا برای اجرای برنام اندروید می باشد. که شامل موارد زیر است:
بسته های اندروید می توانند به طور مستقیم از ایمیل ها و یا URL ها و یا کارت های حافظه نصب شوند. این بسته ها همچنین می توانند به صورت غیر مستقیم از فروشگاه های برنامه مانند Google Play نیز نصب شوند.
همه برنامه های اندروید یک فایل مانیفست دارند(AndroidManifest.xml) که این فایل به پلتفرم اندروید هر چیزی را که لازم است تا برنامه با موفقیت اجرا شود را می گوید. که این موارد لازم عبارتست از:
و چیزهایی مثل آن. برای مثال وقتی می خواهید برنامه ای را نصب کنید، سیستم عامل مجوز های مورد نیاز برنامه را به شما اعلان می کند(که البته هیشکی نمیخونه و فقط دنبال دکمه install هستیم D:) اندروید این اطلاعات و مجوز ها را از فایل مانیفست می خواند.در این قسمت در باره ی معماری سیستم عامل اندروید مطالبی را بیان نمودیم. در مطالب بعدی بیشتر به جنبه نرم افزاری و برنامه نویسی برای این سیستم عامل خواهیم پرداخت.
در قسمت قبل به بررسی معماری اندروید و بسته های نرم افزاری مربوط به این سیستم عامل صحبت کردیم. حال در این قسمت به ادامه بحث در باره ی این سیستم عامل می پردازیم.
مشخص کردن ورژن پلتفرم اندروید گاهی اوقات گیج کننده است. اما نسخه اندروید به شکل یک شماره ورژن، سطح API و یک نام مستعار نسخه تعیین می شود و این ترتیب گاهی اوقات به هم می خورد. شماره ورژن مشخصص کننده ی نسخه پلتفرم می باشد. در برخی اوقات ورژن جدید برای اضافه کردن قابلیت های جدید است و در برخی اوقات برای درست کردن خطاها می باشد.
سطح API نمایانگر مجموعه قابلیت های هر نسخه می باشد. هر چه که سطح API بالاتر می رود قابلیت های جدیدتری به برنامه نویسان ارائه می شود. تصویر زیر ورژن های پلتفرم های مختلف را با تاریخ ارایه نمایش می دهد. برای این که تفاوت بین نسخه های مختلف را بهتر درک کنید و ویژگی های هر نسخه را بدانید به این لینک مراجعه نمایید.مقایسه نسخه های مختلف اندروید
در ادامه در باره ی برنامه های اندروید صحبت خواهیم کرد. برنامه های اندروید از انواع گوناگونی از کلاس ها و منابع تشکیل شده اند که به بحث در باره ی این کلاس ها می پردازیم.
اصلی ترین بخش یک برنامه اندروید یک activity است. یک activity عملی را فراهم می کند که کاربر آن عمل را اجرا می کند مانند لیست کردن مخاطبین، افزودن مخاطب جدید و نمایش نقاط و محل ها بر روی نقشه. یک برنامه از چندین Activity تشکیل شده است. کاربر با استفاده از ویوها با activity ها ارتباط برقرار می کند. اگر شما با الگوی طراحی MVC) Model-View-Controller) آشنا باشید می توان گفت که Activity ها همان Controller ها می باشند. چرخه حیات activity ها را می توان در قالب حالت ها و گذرها و رویداد ها بررسی کرد. دیاگرام زیر یک نمای گرافیکی از چرخه حیات یک activity را نمایش می دهد.
حالت های یک activity با توجه به دیاگرام قبل به شرح زیر است:
در طی گذرها بین حالات یک سری رویدادها بر روی activity فراخوانی می شوند. این رویداد ها این امکان را فراهم می کنند که برنامه نویسان انواع گوناگونی از پردازش ها را انجام دهند. این رویدادها عبارتند از:
onCreate این رویداد زمانی فراخوانی می شود که یک activity ساخته می شود، معمولا این رویداد زمانی است که کاربر برنامه ای را اجرا می کند. از پردازش های معمولی که در هنگام این رویداد انجام می شود می توان به موارد زیر اشاره کرد:
onStart بعد از رویداد های onCreate , onRestart و دقیقا قبل از این که یک activity به کاربر نمایش داده شود این رویداد صدا زده می شود و از پردازش های معمول این رویداد اختصاص منابع به activity است.
چیزی که ممکن است که برای برنامه نویسان تازه کار اندروید مبهم مانده باشد این است که فریمورک چگونه جهت قرار گرفتن (افقی یا عمودی بودن) دستگاه را هندل می کند. به طور پیشفرض وقتی که جهت قرارگیری دستگاه از حالت ایستاده به حالت خوابیده تغییر می کند اندروید activity های جاری را نابود و دوباره سازی می کند تا بتواند به نمایش آنها کمک کند. اگر این کار به شکل برنامه ریزی نشده انجام گیرد می تواند در سرعت و پردازش برنامه اختلال ایجاد کند. در صورت نیاز این رفتار می تواند بازنویسی شود و activity ها نگه داشته شوند.
سرویس ها بخش هایی هستند که در پس زمینه اجرا می شوند و عملیات بلند مدت را انجام می دهند و واسط کاربری مستقیم ندارند. سرویس ها ممکن است داده ها را به داخل کش لود کنند، آهنگ ها را پخش می کند یا پردازش های دیگری را اجرا می کند.
فراهم کننده های محتوا دسترسی به repository مرکزی مانند مخاطبین را مدیریت می کند. یک فراهم کننده ی محتوا بخشی از یک برنامه کاربردی است که معمولا یک رابط کاربری برای مدیریت داده هایش فراهم می کند. یک رابط استاندارد اجازه می دهد که برنامه های دیگر به repository اش دسترسی داشته باشد.
گیرنده های broadcast بخش هایی هستند که پردازش های از نوع broadcast را اجرا می کند. Broadcastها معمولا توسط سیستم فراخوانی می شوند و برای رویدادهایی مانند کمبود باتری، عکس گرفتن و یا روشن کردن بلوتوث به کار گرفته می شوند. ممکن است که برنامه ها نیز بخواهند که broadcast بفرستند. یک فراهم کننده محتوا ممکن است که وقتی که داده ای مثل یک مخاطب آپدیت شود broadcast بفرستد. گیرندگان broadcast ممکن است به طور غیرمستقیم باعث آپدیت وضعیت ها شوند.
هرچیزی که شما در روی یک برنامه اندرویدی می بینید یک ویو است. دکمه ها، لیبل ها، text boxها، و دکمه های رادیویی همه مثال هایی از ویوها هستند. ویوها با استفاده از انواع مختلف گروه های ویو در یک سلسله مراتب سازماندهی می شوند. یک گروه ویو یک نوع مخصوص از ویو است که چیدمان بقیه ویوها را در صفحه نمایش درست می کند.
ویوها و گروه ویوها می توانند از طریق دو متد متفاوت ساخته شوند. برنامه نویسی یا اعلانی. وقتی که از راهکار برنامه نویسی استفاده می کنید یک برنامه نویس یک API را برای ساختن و قرار دادن هر کدام از ویو ها فراخوانی می نمایید. اما وقتی که از راهکار اعلانی استفاده می کنید، برنامه نویس فایل های layout xml مربوط به این که چگونه ویوها باید چیده شوند را می سازد. متد اعلانی مزایای زیر را دارد:
با این که متد اعلانی برای بسیاری از کارها قابل ترجیح است در عمل هردو عمل لازم هستند و باید باشند.
ندروید یک مجموعه ی بسیار بزرگی از ویجت هایی که می تواند توسط کاربر استفاده شود تا برنامه هایی قوی ساخته شود. همه ی این ویجت ها نوعی از ویو ها هستند که می توانند با استفاده از انواع مختلف گروه های ویو ترکیب شده و layoutهای پیچیده تری بسازند. همه ی ویجت های واسط کاربری می توانند در بسته andriod.widget در درون فریمورک برنامه یافت شوند.در این بخش به بررسی نسخه های مختلف اندروید و همچنین عناصری که در سیستم عامل اندروید وجود دارد پرداختیم. به امید خداوند در بخش های آینده جنبه های برنامه نویسی این سیستم عامل را شرح خواهیم داد
در مطالب گذشته به بررسی سیستم عامل اندروید و بخش های مختلف آن پرداختیم. در این مطلب به بررسی Layout ها خواهیم پرداخت و از مطالب دیگر به طور رسمی شروع به برنامه نویسی اندروید خواهیم کرد.
فریمورک برنامه (Application Framework) تعدادی از زیرکلاس های گروه ویو دارد که هرکدام یک راه منحصر به فرد و مفید برای سازماندهی محتوا فراهم می کنند. دیاگرام زیر شکل layoutهای عمومی را نشان می دهد که هرکدام می توانند برای نیازهای خاص مورد استفاده قرار گیرند.
در ادامه به توضیح هرکدام از layout ها خواهیم پرداخت.
برای سناریوهای پیچیده تر اندروید به layout ها اجازه می دهد که به شکل تودرتو قرار گیرند. Layout هایی که به صورت عمقی تودرتو هستند باعث افت کارایی خواهند شد و تا حد امکان نباید از آنها استفاده کرد.
برای layoutهایی که از یک منبع داده پویا(Dynamic Data Source) استفاده می کنند فریمورک برنامه مجموعه کلاس هایی را فراهم کرده است که از کلاس AdapterView مشتق شده اند.
در دیاگرام بالا دو عدد از معروف ترین adapter 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 یا شناسه عددی یکتا باشد. این شناسه می تواند به عنصر موجود در ویو ارجاع شود و هرگاه که بخواهیم عملی را از کد برنامه بر روی عنصر مورد نظر انجام دهیم، از شناسه آن عنصر استفاده خواهد شد. در فایل XML هر شناسه به صورت یک نام رشته ای می باشد. برای مثال خط کد زیر را در نظر بگیرید.
Android:id=”@+id/searchButton”
در این مثال اپراتور @ به پارسر می گوید که از این رشته برای منبع شناسه استفاده شود. علامت + به پارسر می گوید که این یک نام جدید برای عنصر می باشد که باید به فایل منبع R.java اضافه شود. فایل منبع برای هرکدام از شناسه ها ثابت های عددی تعریف می کند تا بتوان به آنها ارجاع داد.
Layoutهای xml به سادگی می توانند در درون یک برنامه در حال اجرا لود شوند. این عمل معمولا در متد onCraete() یک activity با استفاده از متد setContentView() اجرا شود. برای مثال خط کد زیر را در نظر بگیرید.
setContentView(R.layout.main)
Intentها پیامهایی هستند که بین بخش های مختلف یک برنامه اندروید رد و بدل می شوند. این پیام ها به منظور درخواست اجرای یک عمل خاص ارسال می شوند. Intent ها ممکن است برای انجام کارهای زیر استفاده شوند.
ساختن یک برنامه اندروید چیزی بیشتر از نوشتن چند خط کد است. یک برنامه قوی موبایل نیاز به منابعی مانند فایل های عکس و صوت، انیمیشن ها ، منوها و قالب های مفید است. فریمورک برنامه API هایی را فراهم می کند که این API ها می توانند برای لود و استفاده کردن از منابع گفته شده در برنامه اندروید به کار روند.
در درون برنامه، منابع با استفاده از یک ثابت عددی شناخته شده و ارجاع داده می شوند. این ثابت عددی زمانی که منبع به برنامه افزوده شد و کامپایل شد به صورت اتوماتیک به منبع تخصیص داده می شود. این ثابت های عددی در یک فایل سورس جاوا با نام 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 بپردازیم و ببینیم که این برنامه چگونه نوشتن برنامه اندروید را با #C و NET. آسان می کند. همچنین به مزایا و معایب Xamarin.Android خواهیم پرداخت.
Xamarin نام شرکتی است که ابزارهای توسعه نرم افزار تجاری تولید می کند. این شرکت با استفاده از پروژه متن باز Mono بستری را فراهم می آورد که بتوان با استفاده از #C و NET.بتوان برنامه هایی برای اندروید و OS X و IOS ساخت. Xamarin برای ساخت برنامه های اندروید محصول Xamarin.Android را به بازار عرضه کرده است.
قبل از این که به معماری Xamarin.Android بپردازیم ابتدا به این سوال می پردازیم که چرا این نرم افزار را انتخاب کردیم؟ در ادامه لیستی از مزایا و معایب استفاده از این نرم افزار را آورده ایم:
مونو یک پیاده سازی چند پلتفرمی متن باز از کامپایلر #C است. CLRی که در مونو است برای پلتفرم های بسیاری مثل اندروید، اکثر نسخه های لینوکس، BSD، OS x، Windows، Solaris و حتی بعضی از کنسول های بازی مثل Wii, xbox360 طراحی شده است. همچنین مونو یک کامپایلر استاتیک دارد که برنامه ها را برای محیط هایی مثل IOS و PS3 کامپایل می کند.
همانطور که قبلا گفتیم برنامه های اندروید بر روی ماشین مجازی Dalvik اجرا می شوند و برنامه های مونو بر روی Mono CLR اجرا می شوند. پس برنامه Xamarin.Android چگونه اجرا می شود؟ اگر بخواهیم یک پاسخ ساده به این سوال بدهیم این است که این برنامه هم از Mono CLR و هم از ماشین مجازی Dalvik استفاده می کند. دیاگرام زیر نحوه ارتباط این دو را در حال اجرا نشان می دهد.
حال چگونه Mono CLR با ماشین مجازی Dalvik در برنامه Xamarin.Android کار می کند؟ این عمل توسط مفهومی به نام اشیاء متناظر (peer objects) و فریمورکی به نام واسط محلی جاوا (Java Native Interface) JNI انجام می شود.
JNI فریمورکی است که باعث می شود که یک کد غیر جاوا (مثل کد #C یا ++C) در ماشین مجازی جاوا، توسط کدهای جاوا صدا زده شوند و یا کدهای جاوا را صدا بزنند. بنابراین JNI یک عضو لازم در معماری Xamarin.android می باشد.
یک سری اشیای مدیریت شده در Mono CLR قرار دارند و یک سری اشیای مدیریت شده نیز در ماشین مجازی Dalvik قرار دارند و با هم کار می کنند تا توابع Xamarin.Android را اجرا کنند. به این دو سری اشیا که با هم کار می کنند را اشیا متناظر می گویند. Xamarin.Android یک مجموعه اسمبلی هایی دارد که به نام کتابخانه های bind کردن اندروید (Android Binding Libraries) شناخته می شوند. کلاس های موجود در این کتابخانه با کلاس های جاوا که در فریمورک برنامه اندروید وجود دارند مرتبط هستند به طوری که متد های موجود در این کلاس ها به عنوان یک wrapper برای فراخوانی متدهای موجود در کلاس های جاوا به کار می روند.
زمانی که شما از کلاس های C# استفاده می کنید که این کلاس ها از کلاس های کتابخانه bind کردن اندروید ارث برده اند و برنامه ای با این کلاس می سازید. در زمان build کردن برنامه کلاس های پروکسی جاوا ساخته می شوند. کلاس های پروکسی جاوا همان کلاس هایی هستند که کلاس های C# و متدهای override شده آن را به کلاس ها و متد های جاوا wrap می کنند. دیاگرام زیر نحوه ارتباط اشیا متناظر را نشان می دهد.
برنامه Xamarin.Android فایل های apk را تولید می کند که علاوه بر دارا بودن فایل هایی که قبلا گفته شد فایل های اضافه زیر را نیز دارا می باشد:
قسمت اصلی Xamarin.Android این است که که چگونه APIهای اندروید را به #C مقید(Bind) کنند. در نرم افزار Xamarin.Android سعی شده است که طوری عمل شود که برنامه نویسی که در حال برنامه نویسی برای اندروید است و با زبان #C کار می کند راحت باشد و بتواند به راحتی برنامه خود را پیاده سازی نماید. نتیجه این تلاش برای ساده سازی برنامه نویسی اندروید ویژگی های زیر است:
چون همانگونه که گفتیم برنامه های اندروید به نوعی با ماشین مجازی اندروید اجرا می شوند و زبان پیش فرض این برنامه ها جاوا است باید بتوانیم یک همگام سازی بین طراحی بین جاوا و #C داشته باشیم برای مثال باید بتوانیم از مشخصات JavaBean به عنوان مشخصات #C استفاده کنیم که در ادامه به این مباحث پرداخته می شوند.
همان گونه که می دانید مشخصات فیلد ها در جاوا به صورت دو تابع که یکی ابتدای آن set و دیگری ابتدای آن get می باشد مانند setText() و getText() که به این متد ها setter و getter می گویند.در حالی که پیاده سازی مشخصات فیلد ها در C# به کلی تفاوت دارد. و این دو باید به یکدیگر تبدیل شوند. در ادامه به نحوه تبدیل آنها اشاره شده است:
APIهای اندروید از الگوی جاوایی برای تعریف و صدا زدن listener های هر رویداد می کنند. این درحالی است که برنامه نویسان C# به استفاده از delgate ها و eventها آشناتر هستند و با این امکانات کار می کنند. بنابراین قوانین زیر برای bind کردن از API های اندروید به C# وضع شده است:
Eventها و مشخصات (properties) فقط تحت شرایط زیر ساخته می شوند:
برنامه نویسان برای نوشتن برنامه های موبایل دو انتخاب برای IDE دارند که انتخاب ها Xamarin Studio و Visual Studio هستند.
این نرم افزار یک نسخه سفارشی شده از MonoDevelop IDE می باشد که می تواند برای برنامه نویسی برای پلتفرم های Android, IOS و OS X مورد استفاده قرار گیرد. Xamain Studio هم برای سیستم عامل ویندوز و هم برای OS X وجود دارد و دارای ویژگی های زیر است:
تصویر زیر محیط Xamarin Studio را در حالی که محیط طراحی رابط کاربری اندروید برای آن باز است را نمایش می دهد.
Xamarin برای ویژوال استودیو یک افزونه است که توسعه برنامه برای برنامه های Xamarin.Android را پشتیبانی می کند. اگر شما با نرم افزار قدرتمند ویژوال استودیو آشنایی دارید می توانید این افزونه را بر روی این نرم افزار نصب کرده و با استفاده از آن برنامه های خود را بسازید. البته گفتنی است که این نرم افزار فقط برای سیستم عامل ویندوز موجود است. تصویر زیر محیط این نرم افزار را در حالی که صفحه طراحی رابط کاربری اندروید برای آن باز است را نمایش می دهد. برنامه های نوشته شده در هر کدام از محیط های توسعه قابل استفاده در محیط دیگری نیز می باشند.
تا این قسمت مطالب بیشتر در مورد مباحث تئوری صحبت شد و به معرفی سیستم عامل و ابزار های برنامه نویسی پرداخته شد. در مطالب آینده به مباحث عملی و برنامه نویسی سیستم عامل اندروید پرداخته خواهد شد
آموزش رایگان برنامه نویسی اندروید ( Android ) قسمت5 : چگونه با زامارین استودیو کار کنیم؟ تا به حال در مورد معماری اندروید و همچنین نرم افزار 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 کلیک کنید.
در این قسمت یک صفحه ظاهر شده که روند نصب را نمایش می دهد و هر بسته که نصب شد جلوی آن یک علامت تیک زده می شود و در آخر برنامه به طور کامل نصب خواهد شد.
ما الان آماده هستیم که اولین برنامه خود را به شکل زیر بسازیم:
3. در قست C# از سمت چپ گزینه Android را انتخاب کنید و در پنجره اصلی Android Appliction را انتخاب کنید. و در قسمت Name نام پروژه را وارد نماید برای مثال نام ITProApp را انتخاب می کنیم. همچنین محل ذخیره سازی پروژه نیز نشان داده شده است که می توان آن را تغییر داد. در نهایت بر روی دکمه OK کلیک کنید.
4.نرم افزار Xamarin Studio به طور پیش فرض پوشه های solution و project را می سازد. پوشه project به طور پیش فرض شامل کلاس MainActivity.cs و فایل layout به نام Main.axml می باشد.
بعد از ساختن ITProApp پروژه در درون محیط باز خواهد شد که تصویر زیر نمای نرم افزار را بعد از ساخته شدن برنامه نشان می دهد.
نرم افزار Xamarin Studio مانند بسیاری از IDEهای مدرن از مجموعه ای از منو ها در بالای پنجره ساخته شده است که در زیر آن نوار ابزار هایی وجود دارند. در درون صفحه بخش های قابل جابه جایی برای انجام اعمال مختلف مانند بخش کار با فایل های برنامه و بخش جعبه ابزار و یا بخش مشخصات وجود دارد.
تنظیم فریمورک مقصد مشخص می کند که چه سطحی از API ها برای ساختن و تست کردن برنامه موجود است. جدول نسخه های مختلف اندروید و سطح API ها را در قسمت اول نشان دادیم. هرچقدر که ما سطح API را پایین بگیریم برای گوشی های قدیمی بیشتری برنامه قابل استفاده است ولی امکانات و ویژگی های کمتری در اختیار داریم. برای مشخص کردن فریمورک مقصد مراحل زیر را دنبال کنید:
Xamarin.Android یک نام بسته و یک آیکن پیش فرض برای برنامه ها قرار می دهد. آیکن در قسمت action bar ویوی اصلی و در بالای بقیه ویوها قابل نمایش است. برای تغییر تنظیمات پیش فرض برای آیکن مراحل زیر را دنبال کنید.
وقتی که یک برنامه بر روی دستگاه اندرویدی انتخاب می شود، سیستم عامل اندروید یک نمونه از 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 { . . . }
روش اجرا و خطایابی قسمت مهم تولید برنامه ها است چون در سرعت و دقت تولید برنامه ها تاثیر بسیاری دارد. برای اجرای برنامه ها و خطایابی آنها مراحل زیررا دنبال کنید.
2. از پنجره ی باز شده شبیه سازی که قصد دارید برنامه را با آن اجرا کنید را اجرا کنید. مثلا MonoForAndroidAPI15(emulator) را انتخاب کنید. توجه داشته باشید که باید صبر کنید تا شبیه ساز روشن شود.
نرم افزار Xamarin studio برنامه را کامپایل می کند و برای اجرا در شبیه ساز آماده می کند. روند اجرا را می توانید در داخل status bar ببینید.
3. بعد از این که شبیه ساز روشن شد صفحه اندروید آن را باز کنید و برنامه را اجرا کنید.
4. حال با قرار دادن BreakPoint در برنامه و اجرای دوباره آن می بینید که برنامه تا محل Breakpoint اجرا می شود و در محل Breakpoint متوقف می شود. مانند شکل زیر
5. حال از این قسمت برنامه را می توانید به همان حالت پیش فرض ادامه دهید و یا برای خطایابی آن را خط به خط اجرا کنید که برای این کار می توانید از نوار ابزار که تصویرش در ادامه آورده شده است استفاده نمایید.
6. همچنین برای خطایابی برنامه می توانید از پنجره های بسیاری استفاده کنید که هر کدام امکانات خاصی را در اختیار شما قرار می دهند.شما می توانید با استفاده از این پنجره ها مقدار کنونی متغیر ها و یا ترتیب فراخوانی توابع و متد ها و بسیاری از پارامتر های برنامه را ببینید.
همانطور که دیدید شبیه سازها اجرا کننده ی برنامه های نوشته شده توسط برنامه نویسان است. به غیر ازشبیه ساز هایی که به طور پیش فرض وجود دارند می توانید شبیه سازهای متفاوتی با سلیقه خودتان بسازید و یا شبیه ساز های فعلی را دستکاری کنید. برای این کار این گونه عمل می کنیم:
3. اگر به قسمت تنظیمات Target دقت کنید می بینید که در این قسمت نسخه پلتفرم اندروید و سطح API ی که در شبیه ساز استفاده شده است، مشخص شده است.
4. برای مثال از فیلد Device گزینه Nexus S را انتخاب کنید و در صوت لزوم از فیلد Target گزینه Android 4.0.3 را انتخاب کنید و Hardware Keyboard present را غیر فعال کنید و بر روی OK کلیک کنید.
5. برنامه را با شبیه ساز تغییر داده شده اجرا کنید.
شما همچنین می توانید با استفاده از پنجره Android Virtual Device Manager با استفاده از قسمت Device Definition شبیه سازهای جدیدی بسازید. برای این کار شما باید مشخصات شبیه سازی را که می خواهید بسازید را تعیین کنید. تصویر زیر نمایش دهنده گزینه های مورد نیاز برای ساخت شبیه ساز جدید را نشان می دهد.
توجه داشته باشید که با توجه به سخت افزاری که از آن استفاده می کنید ممکن است اجرا شدن شبیه سازها طول بکشد که برای حل این مشکل اگر شما یک دستگاه اندرویدی داشته باشید می توانید از آن استفاده نمایید. استفاده از دستگاه های اندروید به سادگی استفاده از شبیه سازها می باشد و شاید ساده تر. برای این که دستگاه شما برای اجرای برنامه های نوشته شده آماده شود باید مراحل زیر را دنبال کنید:
برای فعال کردن این قسمت در دستگاه های اندرویدی که نسخه سیستم عامل آنها اندروید 4.0 به بعد است مراحل زیر را دنبال کنید:
اگر کامپیوتر کاربران ویندوزی نتواند دستگاه اندرویدی را بشناسد باید خود به طور دستی راه انداز USB را بر روی کامپیوتر خود نصب کنند. البته در نسخه های جدید ویندوز اکثر دستگاه های اندرویدی شناخته شده هستند ولی اگر چنین نبود می توانید راه انداز های آنها را از اینترنت دانلود کرده و نصب کنید. بعد از این که مراحل قبل را کامل کردید. دستگاه خود را با استفاده از کابل usb به کامپیوتر متصل کرده و در برنامه Xamarin studio به جای استفاده از شبیه ساز از خود دستگاه خود استفاده کنید. و یا در برنامه Visual Studio از قستمت اجرای برنامه فلش رو به پایین را زده و مدل دستگاه خود را انتخاب نمایید.
ممکن است که یک انداختن یک نگاه اجمالی به پشت صحنه نحوه اجرای برنامه برای بسیاری جالب باشد که چگونه برنامه C# در اندروید اجرا می شود.
ابتدا از اشیای متناظر(اشیای پروکسی) شروع می کنیم. قبلا نیز اشاراتی به این اشیا داشته ایم. در داخل پوشه های برنامه به قسمت 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.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>
در کد آورده شده نکات زیر موجود است.
تا این قسمت از مطالب با کلیات نرم افزار Xamarin Studio آشنا شدیم. در قسمت های آینده به شکل رسمی تر به برنامه نویسی اندروید خواهیم پرداخت.
در مطالب گذشته در باره ی خود ساختار اندروید و برنامه نویسی آن و همچنین Xamarin صحبت کردیم. حال شروع می کنیم که یک برنامه را از ابتدا بسازیم. در این مطلب به بررسی و ساخت مکانیزم ذخیره سازی اطلاعات در برنامه می پردازیم. در این مطلب خواهید دید که از همان کتابخانه های دات نت برای ذخیره سازی استفاده خواهیم کرد. راهکارهای ذخیره سازی داده به دو دسته تقسیم می شوند. وب سرویس ها و ذخیره سازی محلی.
اگرچه بسیاری از برنامه های موبایل به وب سرویس ها وابسته هستند اما ما در این مطلب بر روی ذخیره سازی محلی تمرکز خواهیم داشت. راهکارهای ذخیره سازی محلی مختلفی وجود دارند. SQLite یک موتور پایگاه داده تراکنشی سبک است که در پلتفرم اندروید موجود است. SQLite به طور گسترده در موبایل ها استفاده شده است هم در اندروید و هم در IOS. اگر شما می خواهید که با بانک اطلاعاتی ارتباط داشته باشید و اطلاعات خود را در آن ذخیره کنید SQLite می تواند در موبایل راه حل خوبی باشد.
اما ما در این آموزش فعلا به ذخیره سازی فایلی می پردازیم. به دو روش می توان از ذخیره سازی فایلی استفاده کرد. دو راه استانداردی که برای ذخیره سای داده های دارای ساختار در فایل متنی وجود دارد عبارتست از xml و Json. فایل های xml طولانی هستند و وب سرویس هایی که بر پایه SOAP و WSDL هستند از این استاندارد استفاده می کنند. حجم فایل هایی که به شکل json ذخیره شده اند از فایل هایی که به شکل xml ذخیره شده اند کمتر می باشد و Json در وب سرویس های RESTful کاربرد دارد. ما در این بخش از Json استفاده خواهیم کرد.
اولین کلاسی که باید آن را بسازیم، کلاسی است که فوکوس برنامه بر روی آن است. این کلاس به نوعی کلاس ساختار داده های برنامه است و entity های برنامه با این قالب ذخیره می شوند. کلاسی که در این قسمت می خواهیم بسازیم دارای فیلد های زیر است:
کلاس entity کلاسی است که موارد گفته شده را داشته باشد. برای ساخت این کلاس مراحل زیر را دنبال کنید:
برای این که فیلدهای مختلف کلاس 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); }
حال به پیاده سازی توابع موجود در اینترفیس می پردازیم. برای این کار به روش زیر عمل می کنیم.
اکنون در داخل کلاسی که شما ساخته بودید متدهای موجود در اینترفیس ظاهر خواهند شد. این کلاس در شکل زیر آمده است.
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 را در یک پوشه ذخیره خواهیم کرد. به گونه ای که نام هر فایل با استفاده از 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(); }
ما به یک 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); } }
این تابع مقادیر 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 به شکل درست ذخیره شد آن را به کش برنامه اضافه خواهد کرد.
این تابع یک تابع ساده است که با وجود کش در برنامه پیاده سازی آن بسیار آسان است. کار این تابع به این شکل است که یک id می گیرد و entity متناظر آن id را برمی گرداند. این تابع این کار را با استفاده از کش انجام می دهد. که تابع زیر این کار را انجام می دهد.
public ITProEntity GetEntity(int id) { var entity = _entities.Find(p => p.Id == id); return entity; }
این تابع نیز یک عدد صحیح به عنوان id گرفته و entity مورد نظر را از داخل فایل های json و همچنین از داخل کش حذف می کند. کد این تابع به این شکل است:
public void DeleteEntity(ITProEntity entity) { File.Delete(GetFilename(entity.Id.Value)); _entities.Remove(entity); }
تا این جای برنامه فقط سرویس چهار عمل اصلی CRUD را با استفاده از فایل ها نوشتیم. در ادامه به ساختن ویو ها خواهیم پرداخت که از این کلاس استفاده کند.
تا قبل از این بخش مباحث اندروید به بررسی ساختار اندروید و نرم افزار Xamarin و همچنین نحوه ساخت یک مکانیز ذخیره سازی برای اندروید بود. ما تا قبل از این بخش به طور رسمی وارد برنامه نویسی اندروید نشده ایم. اما در این بخش می خواهیم به ساختن رابط کاربری (UI) بپردازیم. توضیحاتی که در این بخش ارائه خواهد شد با همان پروژه ITProApp خواهد بود.
وقتی که یک پروژه می سازیم به طور پیش فرض یک Layout و activity ساخته می شود. برای این که فایل های مورد نظر خودمان را بسازیم به جای حذف فایل های گفته شده آنها را تغییر نام داده و کد های اضافی را حذف می کنیم. بنابراین مراحل زیر را دنبال کنید:
[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 ها به شرح زیر می باشند.
برای این که کنترل بیشتری روی layout ها داشته باشیم می توانیم خودمان layout های سفارشی بسازیم. که ما در پروژه خود از این نوع کنترل ها خواهیم ساخت. برای ساخت layout جدید در پنجره ی Solution به مسیر Resources//Layout بروید بر روی پوشه Layout کلیک راست کرده و گزینه Add| New File را انتخاب کنید و در پنجره ی ظاهر شده از قسمت Android گزینه Android Layout را انتخاب نمایید و برای نامه آن ItproListItem را انتخاب می کنیم سپس پنجره را تایید کنید. راه های متفاوتی برای ساختنLayout مورد نظر وجود دارد ولی ما از RelativeLayout استفاده خواهیم کرد. Layoutی که قرار است ما بسازیم شبیه دیاگرام شکل زیر است.
قسمت های تشکیل دهنده ی دیاگرام بالا به شرح زیر است:
در گام اول طراحی دیاگرام بالا باید یک گروه ویو به نام 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 (vertical را از داخل جعبه ابزار به داخل صفحه قرار می دهیم. برای اضافه کردن این ویجت به صفحه باید کمی دقت کنید که این ویجت را به سمت راست ویجت عکس ببرید تا زمانی که گوشه ی آن آبی شود سپس کلیک موس را رها کنید. بعد از اضافه کردن این ویجت در قسمت Layout-Relative Layout مقدار Layout_centerVertical را برابر true قرار دهید.
برای این کار یک کنترل 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 استفاده کنید.
قبل از این که یک 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 بکنیم این اطلاعات حذف خواهند شد. همچنین دیگر برنامه ها نیز به راحتی می توانند از این برنامه ها استفاده نمایند.
برنامه های اندرویدی باید یک سری مجوزها داشته باشند تا بتوانند اعمال خاصی را انجام دهند. یکی از این اعمال نوشتن در حافظه خارجی دستگاه است. شما باید این مجوز ها را در فایل AndroidManifest.xml به برنامه بدهید. مجوزها هنگام نصب برنامه به کاربر نشان داده می شوند.
برای دادن این مجوزها به برنامه باید این گونه عمل کنیم که اگر از برنامه ویژوال استودیو برای برنامه نویسی استفاده می کنید بر روی نام پروژه کلیک راست کرده و از منوی ظاهر شده properties را انتخاب می کنیم و از قسمت Android manifest در قسمت required permissions مجوز های مورد نظر را تیک بزنید با این کار مجوز های مورد نظر به فایل AndroidManifest.xml اضافه خواهد شد.
اما اگر برای برنامه نویسی از xamarin studio استفاده می کنید بر روی نام پروژه کلیک راست کرده و گزینه options را انتخاب کرده و در قسمت Android Application از قسمت Required permissions مجوز های مورد نظر خود را انتخاب کنید.
برای ساخت این adapter سفارشی اینگونه عمل می کنیم:
یک کلاس به برنامه اضافه می کنیم و نام آن را ITProListViewAdapter قرار می دهیم و کلاس را public معرفی می کنیم و همچنین این کلاس باید از کلاس <BaseAdapter<ITProEntity ارث بری داشته باشد. با این کار adapter ما ساخته می شود. حال باید constructor را تعریف کنیم.
وقتی که یک نمونه از این کلاس ساخته می شود برای این که ملزومات اجرای این کلاس فراهم شود باید در زمان ساخته شدن نمونه از این کلاس این ملزومات را به کلاس داده برای این کاراز constructor کلاس استفاده می کنیم. ما برای اجرا به یک activity نیاز داریم که یک activity در داخل کلاس معرفی می کنیم و در داخل constructor آن را مقداردهی می کنیم. که کد آن به شکل زیر خواهد بود
private readonly Activity _context; public ITProListViewAdapter(Activity context) { _context = context; }
قسمت هایی که در این کلاس وجود دارد و باید آن ها را پیاده سازی کنیم چند عدد تابع و property هستند. که به توضیح آنها می پردازیم:
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; } }
از داخل همه متدهایی که باید برای 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 شناخته می شود را پر می کند.
آخرین قدمی که برای استفاده از 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 نماییم.
منو ها و اکشن ها می توانند در داخل یک فایل xml تعریف شوند. که این فایل های xml مربوط به منو ها باید در مسیر پوشه Resources/menu مربوط به پروژه قرار بگیرند. شما می توانید که منو ها را با فراخوانی API ها نیز بسازید. ما منوهای خود را در همان برنامه که قبلا نیز به ساخت آن پرداخته بودیم خواهیم ساخت. کار ساخت منوها در اندروید را ب استفاده از فایل های xml خواهیم گفت. نام فایل xml ساخته شده برای صفحه اصلی در این برنامه 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 که در قسمت قبلی ساختیم تبدیل به یک منو شود باید از تابع 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 کاری انجام نداده ایم. این قسمت در مطالب بعدی مورد استفاده قرار خواهد
در قسمت های قبلی مراحل ساخت یک برنامه ساده موبایل را با استفاده از برنامه Xamarin توضیح دادیم و در ادامه نیز می خواهیم این برنامه را کامل تر کنیم.در این مطلب قصد دارم که اعمال حذف و اضافه و بروزرسانی داده ها را شرح دهم.
برای ساخت این 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 در نظر می گیریم که به ترتیب نام آنها به این شکل خواهد بود.
چیزی که ما می خواهیم طراحی کنیم به این شکل می باشد.
روش طراحی شکل بالا هم به گونه ای است که به ترتیب یک Text View گذاشته و متن آن را تغییر می دهیم و به دنبال آن یک EditText از انواع گفته شده قرار می دهیم و مقادیر Id و نوع آنها را تغییر می دهیم.
عنصر EditText یک ویژگی به نام InputType دارد که رفتار کنترل را مشخص می کند که چه داده ای می توان در آن وارد کرد. برای مثال وقتی که ما ویجت های شرح و آدرس را اضافه می کنیم گزینه Multiline را از جعبه ابزار انتخاب می کنیم. که این انتخاب ما باعث می شود که کد زیر به صورت اتوماتیک برای آن ویجت تولید شود.
<EditText p1:inputType="textMultiLine" p1:layout_width="fill_parent" p1:layout_height="wrap_content" p1:id="@+id/descrEditText" />
مشخصه InputType را می توان از پنجره ی properties نیز تغییر داد ولی نکته ای که باید به آن توجه داشت این است که مقادیری که این مشخصه دریافت می کند را می توان با هم ترکیب کرد و به صورت ترکیبی به کار برد. برای مثال InputType در هرکدام از عناصر گفته شده به این شکل است:
بعد از این که 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 های دیگر را نیز اجرا نماییم. برای این کار ما از تابع 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 استفاده کرده ایم که بعدا کد داخل این توابع را بیان خواهیم کرد.
در برخی مواقع اتفاق می افتد که ما می خواهیم برخی از کاربردها و اکشن های برنامه غیرفعال باشند. مثلا ما می خواهیم که کاربرنتواند برخی آیتم ها را حذف کند. برای این کار ما باید این عمل غیر فعال کردن را در داخل متد 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 یک آیتم را فعال یا غیرفعال نمود.
ما برای این که کد زیاد در داخل متد onOptionItemSelected قرار ندهیم و کل منطق ذخیره را در داخل آن ننویسیم یک تابع جدید به نامه SaveItpro() ساختیم که این تابع باید کارهای زیر را انجام دهد.
اعتبارسنجی ورودی به این معنی است که آیا کاربر داده درست وارد کرده است یا خیر که اگر ورودی درست وارد نکرده بود باید به کاربر خطا داد و تا آن را درست نماید. برای مثال در این برنامه فیلد نام نباید خالی باشد برای این کار باید فیلد نام را اعتبارسنجی نماییم. برای اعتبارسنجی یک فیلد از فیلد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 جاری می شود.
در داخل این تابع باید دو عمل انجام شود. 1.رکورد موجود حذف شود. 2.activity بسته شود.
protected void DeleteItpro() { ItproData.Service.DeleteEntity(entity); Finish(); }
در انجام بعضی از دستورات کاربر باید مطمئن شویم که کاربر سهوا این کار را انجام نداده و از انجام آن مطمئن است. یکی از این کارها حذف داده ها می باشد. عموما برای این کار بعد از این که کاربر دستور حذف داده ها را می دهد یک سوال از او پرسیده می شود و در صورت تایید کاربر داده حذف می شود. حال ما می خواهیم بدانیم این سوال را در اندروید چگونه باید از کاربر بپرسیم. برای این کار از کلاس های AlertDialog و AlertDialog.Builder در اندروید استفاده می کنیم. این کلاس ها به شما اجازه می دهند که یک کادر سوال بسازید که گزینه های مختلفی برای انتخاب دارند و با انتخاب هر کدام از گزینه ها کار بخصوصی انجام خواهد شد. برای ساخت این کادر سوال باید مراحل زیر را انجام دهیم.
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() قرار می دهیم.
اگر ما عمل Save و یا Delete را در برنامه انجام دهیم تعداد داده های موجود کم یا زیاد خواهد شد. برای همین باید لیستی که داده ها را نمایش می دهد را بازسازی کنیم که اگر داده ای حذف شده باشد آن را حذف کند و اگر داده جدیدی ساخته شده است آن را به لیست اضافه کند. برای این کار باید به adapter بگوییم که داده ها تغییر کرده اند و خود را بروز کند برای این کار در متد OnResume مربوط به Activity باید کد زیر را بنویسیم.
protected override void OnResume (){ base.OnResume (); _adapter.NotifyDataSetChanged (); }
تا این قسمت از مطالب نحوه ذخیره سازی و خواندن اطلاعات و نمایش آن با استفاده از ویجت های اندروید در Xamarin آموزش داده شد. امیدوارم توانسته باشم کاری کنم که کاربران با مقدمات برنامه نویسی اندروید آشنا شوند. پس از این قسمت تکنیک هایی را به زبان جاوا در باره ی برنامه نویسی اندروید خواهیم گفت که با توجه به این نکته که در اندروید تفاوت زیادی نیست می توانید با کمی بررسی آن ها را در زبان C# و Xamarin هم پیاده بکنید.
بنیانگذار توسینسو و برنامه نویس
مهدی عادلی، بنیان گذار TOSINSO. کارشناس ارشد نرم افزار کامپیوتر از دانشگاه صنعتی امیرکبیر و #C و جاوا و اندروید کار می کنم. در زمینه های موبایل و وب و ویندوز فعالیت دارم و به طراحی نرم افزار و اصول مهندسی نرم افزار علاقه مندم.
زمان پاسخ گویی روز های شنبه الی چهارشنبه ساعت 9 الی 18
فقط به موضوعات مربوط به محصولات آموزشی و فروش پاسخ داده می شود