جلسه دوم: ماشین حساب فوق ساده با اندروید
در این جلسه تصمیم داریم شیوه آموزش پروژه محور را آغاز کنیم. پیشنیاز این جلسه جلسه اول آموزش اندروید استدیو می باشد. برای شروع کار ابتدا فایل ماشین حساب فوق ساده (Calc.zip) را از لینک زیر دانلود کرده و آن را Extract نمایید:
لینک دانلود سورس ماشین حساب فوق ساده با اندروید استودیو (Calc.zip) - حجم 6MB
حال Android Studio را باز کرده و از پنجره ی باز شده روی Open an existing Android Studio project کلیک کنید و پوشه ی دانلود شده و آنزیپ شده را باز کنید.
توجه: اگر پس از کلیک روی آیکن Android Studio مستقیما وارد پروژه ی قبلی می شوید و پنجره ی بالا ^ نمایش داده نمی شود بایستی از منوی File روی Close Project کلیک کنید تا از پروژه ی جاری خارج شوید. کلیک روی علامت ضربدر پنجره به معنای بستن پروژه جاری می باشد و نه به معنای خروج از پروژه.
پس مدتی (بین 2 تا 5 دقیقه) پروژه به طور کامل باز می شود. مادامی که در نوار پایین برنامه علامت Loading گردان و عباراتی با سه نقطه نمایش داده می شود یعنی اندروید استدیو در حال باز کردن فایلهاست. تا زمانی که این علامت ها محو نشده و عبارت Gradle build finished در نوار پایین نمایش داده نشده به کامپیوتر دست نزنید، چرا که تمام CPU صرف باز کردن و ساختن پروژه شده و سرعت استدیو فوق العاده پایین می باشد.
پس از باز شدن موفقت آمیز پروژه، فایل activity_main.xml را باز کنید تا کمی با نحوه ی طراحی رابط کاربری (UI) آشنا شویم.
همانطوریکه در تصویر بالا مشاهده می کنید این پروژه فوق العاده ساده بوده و از سه برچسب (TextView)، دو EditText و یک Button تشکیل شده است. در این پروژه هرگاه اعدادی را در فیلدهای num1 و num2 بنویسید و کلید را لمس کنید اعداد باهم جمع شده و نتیجه در برچسب زیر کلید نمایش داده می شود. همچنین اگر عددی در فیلدها وارد نشود مسلما باید خطای Force Close داده شود ولی با استفاده از مدیریت استثنا این خطا به دام انداخته می شود و پیغام مناسبی را به کاربر نشان می دهد. (در بخش کد به طور مفصل توضیح خواهیم داد).
اصولاً در طراحی UI های ساده، فایل xml از یک لایه والد تشکیل می شود و بقیه لایه ها در این لایه قرار می گیرند. این لایه می تواند از نوع LinearLayout ،RelativeLayout و غیره باشد که تمام این لایه ها در پنجره Palette و در قسمت Layouts قرار گرفته اند. (در حالت Design نمایش فایل xml لایه). در پروژه ی ماشین حساب فایل UI از یک RelativeLayout تشکیل شده است که در داخل آن دو عدد RelativeLayout دیگر قرار گرفته و به عمد رنگ زمینه ی این دولایه را به سبز و زرد تغییر داده ایم تا براحتی تشخیص داده شوند. در حالت عادی لایه ها شفاف هستند و فقط وظیفه ی تقسیم بندی صفحه نمایش به بخش های مختلف را بر عهده دارند.
داخل هر کدام از RelativeLayout های سبز و زرد دو شی دیگر قرار گرفته است. یکی TextView که مانند Label بوده و برای نمایش برچسب های Num 1 و Num 2 استفاده شده است و دیگری EditText که همانند TextBox در برنامه های ویندوزی وظیفه ی در یافت اطلاعات از کاربر را بر عهده دارد. در پایین لایه ها یک دکمه یا همان Button قرار دارد و در زیر آن یک TextView ی دیگر برای نمایش پاسخ.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="16dp" android:paddingRight="16dp" android:paddingTop="16dp" android:paddingBottom="16dp" android:layoutDirection="ltr" tools:context=".MainActivity"> <RelativeLayout android:id="@+id/relativeLayout1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:background="#00ff00" android:layout_centerHorizontal="true"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Num 1:" android:id="@+id/textView1" android:layout_centerVertical="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:inputType="numberSigned" android:ems="10" android:id="@+id/editText1" android:layout_alignParentTop="true" android:layout_toRightOf="@+id/textView1" android:layout_toEndOf="@+id/textView1" /> </RelativeLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/relativeLayout1" android:layout_marginTop="10dp" android:background="#ffff00" android:layout_centerHorizontal="true" android:id="@+id/relativeLayout2"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Num 1:" android:id="@+id/textView2" android:layout_centerVertical="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:inputType="numberSigned" android:ems="10" android:id="@+id/editText2" android:layout_alignParentTop="true" android:layout_toRightOf="@+id/textView2" android:layout_toEndOf="@+id/textView2" /> </RelativeLayout> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="اعداد را جمع کن" android:id="@+id/button" android:onClick="add" android:layout_below="@+id/relativeLayout2" android:layout_centerHorizontal="true" android:layout_marginTop="15dp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:text="جواب" android:id="@+id/textView3" android:layout_below="@+id/button" android:layout_marginTop="15dp" android:layout_centerHorizontal="true" /> </RelativeLayout>
اما اگر به هر کدام از این اشیا دقت کنید خواهید دید که هر یک دارای خصوصیتی می باشند. این خصوصیات را هم می توان در مد Design از پنجره ی Properties تنظیم کرد و هم بصورت دستی نوشت. تعداد این خصوصیات به قدری زیاد است که فقط با تجربه و تغییر خصوصیات و آزمایش کردن می توانید با آنها آشنا شوید و توضیح تمام آنها به یک کتاب کامل نیاز دارد. دقیقا مثل تمام تگ های HTML.
از جمله مهمترین خصوصیت هر شی خصیصه ی android:layout_width و android:layout_height می باشد. همانطوریکه از نام آنها پیداست اولی عرض شی را مشخص می کند و دومی ارتفاع آن را. مقادیر جلوی آنها می تواند match_parent به معنای پر کردن والد یا wrap_content به معنای "هم اندازه با محتوای داخل شی" و یا یک عدد با پسوند dp باشد. مثلا 10dp. دی پی واحدیست که بر اساس رزولیشن گوشی خودش را تنظیم میکند و مثلا اگر اندازه یک شی 20dp در یک گوشی قدیمی به اندازه یک عدس باشد در یک گوشی حرفه ای هم به همان اندازه است.
خصوصیت دیگر android:background می باشد که رنگ زمینه شی را مشخص میکند. خصیصه ی android:id برای هر شی یک نام منحصر به فرد ایجاد می کند که شی از طریق این نام شناخته می شود و ارتباط فایل کد Activity با اشیاء نیز از طریق همین نام صورت می پذیرد. اگر برای شی ای این خصوصیت ایجاد نشده بود می توانید بصورت دستی این خصیصه را وارد کنید و یک نام دلخواه حرفی و منحصر به فرد برای آن ایجاد نمایید. (با رعایت فرمت دقیق آن و قرار دادن /id+@ در ابتدای نام).
یکی از ویژگیهای خصیصه های XML فایل رابط کاربری این است که گویا بوده و از روی معنای لاتین آن ها براحتی میتوان مفهوم خصیصه را فهمید. مثلا به خصوصیت android:layout_below که برای شی Button بکار رفته توجه کنید، معنای این خصوصیت اینست که "این لایه باید در زیر لایه فلان قرار بگیرد" که در جلوی آن id لایه فلان که همان relativeLayout2 است قرار گرفته است. یا خصوصیت android:layout_centerHorizontal شی آخر که جواب را نمایش می دهد به معنای "لایه از نظر افقی باید در وسط والد قرار بگیرد" می باشد.
یکی دیگر از ویژگی های محیط Design اینست که از Drag & Drop پشتیبانی می کند و می توانید اشیا را از پالت کشیده و در جای مناسب در روی فرم (صفحه دستگاه) رها کنید و کد آماده را در بخش Text تحویل بگیرید.
در خصوص Button یکی از خصوصیت ها که آن را به صورت دستی وارد کرده ایم خصیصه ی android:onClick می باشد. در جلوی این خصیصه عبارت add را نوشته ایم و مفهم آن اینست که به محض لمس دکمه بایستی تابعی به نام add در فایل کد فراخوانی شود.
در اینجا توضیح برای فایل User Interface یا همان رابط کاربری تقریباً کافی به نظر می رسد و کار با بقیه خصوصیات را به عنوان تمرین به شما واگزار می کنیم. می توانید پروژه های آزمایشی ایجاد کنید و با کشیدن و رها کردن اشیا و تغییر خصوصیت آنها از پنجره ی Properties به بررسی سایر ویژگیها بپردازید و یا اینکه سورسهای اندروید را از همین سایت دانلود کنید و فایلهای XML را بررسی نمایید.
هر پروژه ی دارای رابط کاربری حداقل از یک فایل Activity با پسوند java تشکیل شده است که به محض لمس آیکن برنامه در بخش برنامه های موبایل، این فایل اجرا می شود. در شکل زیر فایل اکتیویتی پروژه ماشین حساب را ملاحظه می فرمایید. زبان برنامه نویسی این فایل جاوا می باشد. اگر با java آشنایی ندارید اصلاً نگران نباشید. ساختارهای کلی آن تقریبا مشابه با C بوده و با بررسی چند کد به ماهیت ساده و روان این زبان قدرتمند پی خواهید برد. فایل MainActivity.java را در شکل زیر ملاحظه می کنید:
هر فایل کد جاوا با عبارت package شروع می شود و در جلوی آن یک نام واحد (نام بسته) قرار گرفته است. فایل های Java از این طریق می فهمند که همگی عضو یک مجموعه هستند. تقریبا شبیه به Namespace در C. بعد از پکیج دستورات import قرار گرفته اند. این دستورات مانند include در C یا using در #C بوده و برای افزودن کتابخانه های مورد نیاز در فایل جاری اضافه شده اند. این دستورات به طور خودکار و با فشار کلید alt+Enter در روی توابع ناشناخته ایجاد می شوند. یعنی به طور مثال اگر در برنامه ی خود عبارت EditText را بنویسید، این عبارت قرمز شده و با کلیک بر روی آن و فشار Alt+Enter (پس از اعلان برنامه) دستور import android.widget.EditText بطور خودکار اضافه می شود.
بدنه ی اصلی فایل اکتیویتی که مجاز به کد نویسی در آن هستیم با عبارت public class MainActivity extends AppCompatActivity شروع می شود. public class به معنای کلاس عمومی و MainActivity هم نام کلاس (و هم نام با فایل جاری) است. عبارت extends به معنای ارث گرفتن بوده و عبارت جلوی آن نام کلاس والد است که این فایل ِ اکتیویتی ما از آن ارث بری می کند و آن AppCompatActivity می باشد. اصلاً نگران نشوید. ما هیچ کاری با کلاسها و مباحث پیچیده ی ارث بری نداریم. فقط همینقدر بدانید که Java، کارها را راحت کرده و معنای این عبارت طولانی اینست که فایل Activity ما که قرار است کدهای خود را درون آن بنویسیم فرزند کلاسی به نام AppCompatActivity است و تمام کدهای پیچیده قبلا در آن کلاس والد نوشته شده اند و ما فقط کارهای خودمان را انجام می دهیم. مسائل سیستمی در پشت پرده انجام می شود. ما براحتی می توانیم در کلاس فرزند از توابع آماده ی کلاس پدر استفاده کنیم.
یکی از این توابع به ارث برده شده تابع onCreate است. این تابع مانند تابع main در c می باشد. کار شما در زبان c اینست که کدهای خود را در تابع main می نویسید و مطمئنید وقتی روی فایل exe کلیک کردید سیستم عامل پس از آماده شدن، تابع main را اجرا می کند. در اینجا هم مسئله دقیقا به همین شکل است. فقط تفاوت جاوا با c اینست که هر گاه قرار است از این توابع به ارث برده شده استفاده کنیم باید دقیقا در خط قبل آن عبارت Override@ را بنویسیم. همانطوریکه از مفهوم این کلمه پیداست Override به معنای بازنویسی است و این یعنی ما در حال بازنویسی این تابع به ارث برده شده هستیم. باز هم نگران نباشید. تمام این کدها موقع ایجاد پروژه به صورت خودکار ایجاد می شود و ما دقیقا مانند C یا ++C برنامه نویسی خواهیم کرد.
بخشی که بعد از عبارت طولانی public class MainActivity extends AppCompatActivity و قبل از Override@ قرار دارد بهترین مکان برای تعریف متغیرهای عمومی است که باید در تمام برنامه شناخته شوند. ما در اینجا دو متغیر n1 و n2 از نوع EditText و متغیر result از نوع TextView را ایجاد کرده ایم. n1 و n2 قرار است به دو فیلد ورودی اشاره کنند و result هم به برچسب جواب.
ما یک شیوه ی راحت در برنامه نویسی جاوا داریم که کار را قابل فهم تر می کند و بدین صورت است که همیشه تابعی public به نام init بلافاصله پس از کدهای خودکار ایجاد می کنیم و آن را در خط آخر تابع onCreate فراخوانی میکنیم. از آنجایی که تابع onCreate پس از اجرای برنامه فراخوانی خواهد شد و دستورات داخل آن که مهمترین آنها setContentView برای تسخیر فایل XML و نمایش به کابر است اجرا می شود، در نهایت تابع ما که ()init نام دارد فراخوانی می شود و ما کدهای خود را درون این تابع می نویسیم. اسم این تابع مهم نیست و ما نام init را که مخفف اینیشیالایز می باشد انتخاب کرده ایم.
در این تابع متغیر های n1=(EditText)findViewById(R.id.editText1) و n2=(EditText)findViewById(R.id.editText2) و result=(TextView)findViewById(R.id.textView3) به اشیاء موجود در فایل xml پیوند زده می شوند. یعنی از این به بعد منظور از n1 همان editText1 است و result هم به textView3 (همان لیبل خروجی) اشاره می کند.
تابع بعدی تابع add می باشد. همانطوریکه از بخش xml به خاطر دارید خصوصیتی به نام android:onClick در شی Button ایجاد کرده بودیم که در جلوی آن عبارت add را نوشته بودیم. در اینجا هم تابعی عینا با همان نام (کوچک و بزرگ بودن حروف در Java مهم است) ایجاد می کنیم و نکته ی خیلی خیلی مهم اینست که حتما باید در جلوی این تابع آرگومان View v را بنویسیم. چرا که وقتی از android:onClick در یک فایل xml استفاده می کنیم به محض کلیک روی شی (Button یا هر شی دیگر) یک متغیر از نوع View به تابع موجود در Activity ارسال می شود. هر چند که ما اصلا از آن استفاده نمی کنیم و آن متغیر فقط حاوی نام شی لمس شده می باشد ولی باید در جلوی تابع آن را دریافت کنیم. نکته ی دیگر اینست که این تابع حتما باید public باشد. چرا که این تابع از یک فایل خارجی که همان فایل xml است صدا زده می شود و مثلا اگر این تابع را از نوع private تعریف کنیم توسط فایل xml تشخیص داده نشده و به محض کلیک روی دکمه، برنامه با Force Close مواجه شده و بسته می شود.
در تابع add در ابتدا دو متغیر به نام x و y از نوع int تعریف کرده ایم که اولی با دستور n1.getText().toString مقدار رشته ای EditText اول را دریافت کرده و با کمک تابع Integer.parseInt رشته را به عدد صحیح تبدیل می کند. y هم به همین صورت. خط بعدی هم کاملا گویاست و متغیری به نام z از نوع عدد صحیح تعریف کرده ایم که حاصل جمع x+y را در خود جای می دهد. در خط بعدی ابتدا مقدار z را به کمک تابع String.valueOf به رشته تبدیل کرده و سپس به عنوان یک آرگومان به تابع result.setText ارسال می کنیم که نتیجه ی آن نمایش جواب در برچسب خروجی می باشد.
اما کل ماجرا به همین عملیات ختم نمی شود. معمولا کاربران بازیگوش سعی می کنند یکبار هم که شده برنامه را با فیلدهای خالی یا علامتهای غیر معتبر تست کنند و از هنگ کردن برنامه لذت ببرند. در این طور مواقع بایستی کدهایی را که تصور می کنیم ممکن است در اثر دریافت ورودی ِ غیر معتبر با شکست مواجه شوند در داخل try قرار می دهیم و بلافصله پس از آن عبارت catch به معنای به دام انداختن را قرار می دهیم. در این صورت هر گاه به دلایل مختلف مثلاً موجود نبود فایل در برنامه هایی که با فایل سروکار دارند، موجود نبودن مموری کارت، خراب شدن ماژول دوربین، در دسترس نبودن بلوتوث به دلیل قرار داشتن در مد پرواز، در دسترس نبودن sms به همان دلیل قبلی، و هزاران مورد دیگر یکی از کدهای درون بلوک try با مشکل مواجه شود، خطای ایجاد شده به جای ارسال به هسته ی سیستم عامل اندروید به صورت یک رشته ی متنی به آرگومان e در دستور catch انتقال داده می شود که براحتی می توانیم پیغام خطا را به کاربر نشان دهیم و در ضمن برنامه نیز بسته نمی شود و ظاهر حرفه ای به خود می گیرد.
در این جلسه با مفاهیم کلی طراحی رابط کاربری UI برای یک برنامه اندروید با کامپایلر اندروید استودیو (Android Studio) آشنا شدیم. همچنین نحوه ی ارتباط بین اجزای رابط کاربری با فایل کد Activity بیان شد. این برنامه تنها از یک صفحه و دو فایل اصلی تشکیل شده است. در برنامه ی بعدی که یک کتاب یا کاتالوگ ساده با اندروید است با تعداد بیشتری اکتیویتی کار خواهیم کرد و با فایل مانیفست (AndroidManifest.xml) که وظیفه ی آن معرفی اکتیویتی ها به سیستم بوده و مجوز ها نیز در آن قرار می گیرد آشنا می شویم. همچنین مفهوم اینتنت (Intent) برای انتقال بین صفحات برنامه را معرفی می کنیم. در جلسه ی بعدی همچنین با مفهوم لیست برای ساخت فهرست کتاب آشنا می شویم، نحوه ی تغییر نسخه ی برنامه با Gradle و تغییر نسخه ی API Level اندروید را توضیح می دهیم و در آخر کار با فایل Strings و ترجمه ی برنامه به زبان های مختلف برای تغییر خودکار ظاهر برنامه بر اساس زبان گوشی را آموزش می دهیم.
صفحه اصلی