آموزشِ پروژه‌محور برنامه‌نویسیِ اندروید (درس ۲: ساختِ اولین برنامه)

نویسنده : سید ایوب کوکبی ۲۶ شهریور ۱۳۹۸
آموزشِ پروژه‌محور برنامه‌نویسیِ اندروید (درس 2: ساختِ اولین برنامه)

در این درس می‌خواهیم یک برنامۀ سادۀ اندرویدی بسازیم. نامِ برنامه GeoQuiz است. چند سوالِ جغرافیایی به شکل درست/غلط نمایش داده می‌شود و کاربر با کلیک روی دکمه‌های True یا False پاسخ می‌دهد. اگر درست باشد پیغامِ Correct و اگر نادرست باشد پیغامِ Incorrect نمایش داده می‌شود. برای شروع فقط یک سوال نمایش می‌دهیم و در درس‌های بعد سوالات بیشتری اضافه می‌کنیم.

این تصویر دارای صفت خالی alt است؛ نام پروندهٔ آن untitled.png است

برای تمرکزِ بیشتر روی اندروید و پرهیز از طولانی شدن درس‌ها سعی می‌کنم کدهایِ کاتلین را صرفاً در چارچوبِ اندروید و در حد کارراه‌اندازی توضیح دهم و آموزشِ بیشترِ این زبان را موکول کنم به انتشارِ پست‌های دیگری در اسکارپ. در حال حاضر با جستجویِ واژۀ «کاتلین» می‌توانید اطلاعاتِ اولیه‌ای دربارۀ این زبان به دست آورید. علاوه بر این هر جایی لازم بود توضیحاتِ لازم در موردِ اندروید استودیو و قابلیت‌های آن می‌دهم.

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

آشنایی با مفهومِ Activity

به هر صفحه از برنامه یک اکتیویتی گفته می‌شود؛ همان چیزی که در ویندوز به آن پنجره (window) می‌گوییم. تمامِ اکتیویتی‌ها زیرمجموعۀ کلاس Activity هستند. Activity یکی از مهم‌ترین کلاس‌ها در Android SDK است. این کلاس به همراهِ هزاران کلاسِ دیگر Android SDK را می‌سازند.

اندروید بر خلافِ بیشترِ پارادایم‌های برنامه‌نویسی که اجرای برنامه را از متدِ ()main آغاز می‌کنند از فراخوانیِ CallBack‌ها در چرخۀ حیاتِ برنامه استفاده می‌کند. به عنوان مثال هنگامِ اجرایِ یک اپلیکیشن اولین متدی که به صورتِ خودکار اجرا می‌شود ()onCreate است.

نوعِ تعامل در دستگاه‌های موبایل با کامپیوتر فرق می‌کند. مثلاً در موبایل ایمیلی برایتان آمده که داخلش یک لینک وجود دارد. با کلیک روی لینک، صفحه در مرورگر باز می‌شود. داخلِ آن صفحه تصویری وجود دارد که می‌خواهید برای دوستتان ارسال کنید. دکمۀ اشتراک را می‌زنید و از طریقِ تلگرام تصویر را برای دوستِ خود ارسال می‌کنید. در همین لحظه یک خبرِ فوری در بخشِ نوتیفیکیشن نمایش داده می‌شود. آن را باز می‌کنید واردِ اپلیکیشنِ خبر می‌شوید. ببینید از یک ایمیل شروع شد به خبر رسید. این یعنی مسیرِ مشخصی وجود ندارد. همه چیز مثلِ یک جریانِ پیوسته از اطلاعات به هم گره خورده است. شما تمامِ این مدت بینِ اکتیویتی‌ها در حرکت بودید.

مفهومِ اکتیویتی متناسب با ماهیتِ دستگاه‌های موبایلی است. وقتی از درونِ یک برنامه، برنامۀ دیگری را فرا می‌خوانید در واقع یک اکتیویتی در یک برنامۀ دیگر را باز می‌کنید. اکتیویتی نقطۀ آغازِ سفرِ کاربر در دنیایِ اندروید است. حتی صفحۀ Home Screen گوشی یک اکتیویتی در لانچرِ شماست.

اکتیویتی یک صفحۀ گرافیکی است که عناصرِ برنامه روی آن قرار می‌گیرد. معمولاً اکتیویتی‌ها کلِ صفحه را می‌پوشانند ولی همیشه اینطور نیست. گاهی مثل ویجت‌ها و برنامه‌های شناور فقط بخشِ کوچکی از صفحه را در بر می‌گیرند. هر اکتیویتی در حکمِ یک صفحه از برنامه است. مثلاً صفحۀ تنظیمات، صفحۀ لاگین، صفحۀ ثبت‌نام و … .

در هر برنامه معمولاً یک اکتیویتی اصلی (main activity) وجود دارد که در شروعِ برنامه به کاربر نشان داده می‌شود. هر اکتیویتی می‌تواند برای انجام یک سری کارها اکتیویتی دیگری را فراخوانی کند. این اکتیویتی ممکن است متعلقِ به خودِ برنامه باشد یا حتی در برنامۀ دیگری قرار داشته باشد. مثلاً با دکمۀ اشتراک می‌توانید یک صفحه از اینترنت را در برنامۀ دیگری مثل تلگرام به اشتراک بگذارید. البته هر اکتیویتی مستقل و ایزوله بوده و در کارِ اکتیویتی‌های دیگر نمی‌تواند دخالت کند.

اجزایِ برنامه

در برنامۀ GeoQuiz دو قسمت وجود دارد: activity و Layout:

activity یک نمونه از کلاسِ Activity است. هر اکتیویتی مسئولِ مدیریتِ تعاملِ کاربر با اطلاعاتِ صفحه است. با ساختِ زیرکلاس از Activity می‌خواهیم عملکردهایی که برنامۀ ما به آن نیاز دارد را پیاده‌سازی کنیم. یک برنامه ممکن است یک یا بیشتر از یک اکتیویتی داشته باشد. چیزی که ما می‌خواهیم فعلاً یک اکتیویتی بیشتر ندارد که طبیعتاً همان اکتیویتیِ اصلی است. اسمش را می‌گذاریم MainActivity؛

layout ظاهرِ برنامه و عناصری که روی آن قرار دارد را تعریف می‌کند. layout با زبانِ XML نوشته می‌شود که معمولاً برعکسِ نامِ اکتیویتی نام‌گذاری می‌شود: activity_main.xml. بنابراین هر وقت بخواهید دکمه، متن، تکست‌باکس یا هر چیزِ دیگری به صفحه اضافه کنید سروکارتان با XML است؛ کما اینکه با کدهای جاوا هم می‌توانید ویوها را بسازید. ولی معمولاً برای جداسازیِ UI از کدهای برنامه این کار را انجام نمی‌دهند. در حالِ حاضر در تیم‌های برنامه‌نویسی واسط کاربری و XML بر عهدۀ طراحانِ واسطِ کاربری است و منطقِ برنامه (کدهای جاوا و کاتلین) را توسعه‌دهندگان می‌نویسند. رابطۀ MainActivity و activity_main.xml را می‌توانید در این تصویرِ ببینید:

ساختِ پروژه در اندروید استودیو

اندروید استودیو را اجرا کنید.

پیشنهاد می‌کنم قبل از ساختِ پروژۀ جدید قابلیتِ Instant Run را غیرفعال کنید. با این قابلیت فقط بخش‌هایی که در کد تغییر کرده به گوشی یا امولاتور (Emulator) ارسال می‌شود و سرعتِ کامپایلِ بیشتر می‌شود. ولی مشکل اینجاست که این قابلیت در مواردی دردسر ایجاد کرده و ممکن است رفتارِ مورد انتظاری نداشته باشد. به همین خاطر پیشنهاد می‌کنم همین اولِ کار آن را غیرفعال کنید.

برایِ این کار از قسمتِ پایین configuration و سپس Settings را کلیک کنید. در صفحه‌ای که باز می‌شود عبارتِ Enable Instant Run را جستجو و تیکش را بردارید و OK کنید؛ تمام.

با OK کردن صفحۀ بالا به صفحۀ قبل باز می‌گردید. گزینۀ Start a new Android Studio Project و از صفحۀ بعد Empty Activity را انتخاب و Next بزنید. (راهِ ساده‌تر دابل کلیک روی Empty Activity است).

در صفحۀ پیکربندیِ پروژه نام برنامه را GeoQuiz و package name را مطابقِ تصویر و زبان را Kotlin و API Level را ۲۱ انتخاب کنید. تیکِ گزینۀ Use AndroidX artifacts را هم بزنید. (در نسخه‌هایِ جدیدِ اندروید استودیو این گزینه به صورت پیش‌فرض تیک خورده است.) در ادامه هر یک از این گزینه‌ها را بیشتر توضیح می‌دهم.

Name
ابتدا باید نامِ پروژه یعنی GeoQuiz را وارد کنید. دقت کنید نامِ پروژه با نامِ پکیج و آیدیِ متفاوت است و نیازی نیست که منحصر به فرد انتخاب شود. شما می‌توانید یک برنامه با نامِ Google Chrome در پلی استور منتشر کنید. گوگل‌پلی یا هر مارکتِ دیگری به نامِ پروژه کاری ندارد و فقط به آیدی (applicationID) آن نگاه می‌کند که در ادامه توضیح می‌دهم.

Package name
نامی است که به صورتِ پیش‌فرض برای Application ID استفاده می‌شود. در اینجا نامِ com.bignerdranch.android.geoquiz را انتخاب می‌کنیم. بسیاری از توسعه‌دهنده‌ها به اشتباه فکر می‌کنند چیزی که برنامه را به صورت منحصر به فرد مشخص می‌کند package name است؛ در حالی که application ID در فایلِ build.gradle است که آیدیِ برنامه را مشخص می‌کند. این اشتباه ناشی از آن است که اندروید استودیو هنگامِ ساختِ پروژه به صورت پیش‌فرض نام پکیج را به آیدی اختصاص می‌دهد.

package name در واقع راهی برای سازماندهیِ کدهاست و هر زمان که بخواهید می‌توانید تغییر دهید. اما applicationId که معمولاً همنامِ package name است یکبار که انتخاب شد و برنامه را در مارکت منتشر کردید دیگر نباید تغییر کند؛ چون باعث می‌شود گوگل پلی، کافه‌بازار یا هر مارکتِ دیگری آن را به عنوانِ یک برنامۀ جدید شناسایی کند. به بیانِ دیگر آیدیِ برنامه می‌تواند متفاوت از package name باشد که البته مرسوم نیست.

در نام‌گذاریِ نامِ پکیج معمولاً از ترکیبِ وارونِ آدرسِ سایت + نامِ برنامه استفاده می‌شود. مثلاً اپلیکیشنِ Adobe Reader که توسط شرکتِ ادوبی (adobe.com) ساخته شده اسمش com.adobe.reader است. برای سایت‌های فارسی می‌توانید از دامنۀ ir یا هر چیزِ دیگری استفاده کنید؛ مثلاً ir.example.myApp. البته لزومی ندارد که حتماً دامنۀ اینترنتی داشته باشید؛ حتی می‌توانید از آدرسِ ایمیلِ خود استفاده کنید؛ مثلاً com.gmail.name.appName. فعلاً کاری به این قسمت نداریم و همان چیزی که در تصویر می‌بینید را وارد کنید.

Save location
محلِ ذخیره‌سازیِ پروژه است که اگر لازم نیست تغییر ندهید.

Language
زبانی است که با آن کدِ برنامه را می‌نویسید: Java یا Kotlin. از آنجا که اقبالِ عمومی به زبانِ کاتلین زیاد شده، عاقلانه است که برنامه‌های جدید را با این زبان بسازیم. هم زبانِ زیباتری است و هم آیندۀ بهتری دارد. تا می ۲۰۱۷ تنها زبانِ برنامه‌نویسیِ اندروید، جاوا بود ولی با اعلامِ حمایتِ رسمیِ گوگل از زبانِ کاتلین در کنفرانسِ Google I/O محبوبیتِ آن افزایش یافت و ما نیز از همین زبان استفاده می‌کنیم. در صورتِ انتخابِ زبانِ جاوا نیز می‌توانید از مفاهیمِ بیان شده در این درس و درس‌های آینده استفاده کنید ولی زحمتِ تبدیلِ کدها از کاتلین به جاوا را باید خودتان بکشید.

Minimum API Level
در این فیلد می‌توانید حداقل نسخه‌ای از اندروید را که برنامۀ شما از آن پشتیبانی می‌کند مشخص کنید. با انتخاب هر نسخه درصدِ پوشش آن دستگاه در گوگل پلی نمایش داده می‌شود؛ در تصویرِ بالا ۸۵% یعنی برنامۀ تقریباً روی ۸۵ درصدِ دیوایس‌های اندروید قابلِ اجراست. این آمار بر اساسِ تعداد دستگاه‌های فعال در گوگل پلی است و ربطی به مارکت‌های داخلی ندارد. بنابراین اگر می‌خواهید برنامه‌ای را برای کاربرانِ ایرانی بسازید بهتر است آما مارکت‌های داخلی مثلِ کافه‌بازار را ملاک قرار دهید.

بخوانید  داستان برنامه‌نویس شدن یک مهندس عمران

گزینۀ instant app کدها را سریع‌تر کامپایل می‌کند که به دلایلِ پیشین غیرفعالش کردیم و اینجا نیز تیکش برداشته شده است.

گزینۀ Use androidx.* artifacts به صورتِ پیش‌فرض انتخاب شده که بهتر است به همان صورت رها کنید. androidX یک روشِ جدید برای شفافیت در نام‌گذاریِ کتابخانه‌ها است که گرچه استفاده از آن اجباری نیست ولی توصیه نمی‌کنم؛ چون اگر روزی لازم شد از یک کتابخانه بر مبنایِ آن استفاده کنید حتماً باید به androidX مهاجرت کنید. در این مورد بعداً بیشتر توضیح می‌دهم.

نکته: با توجه به پیشرفتِ سریعِ اندروید استودیو ممکن است ویزاردی که شما مشاهده می‌کنید با چیزی که اینجا می‌بینید متفاوت باشد.

آشناییِ اولیه با محیطِ اندروید استودیو

قبل از آشنایی با محیطِ اندروید استودیو اطمینان حاصل کنید که در قسمتِ پایین یعنی پنجرۀ Build مطابقِ تصویر همه چیز تیکِ سبز خورده باشد. این یعنی به درستی برنامه کامپایل شده و آمادۀ اجرا روی گوشی است. ( اندروید استودیو در هنگامِ اجرا، یکبار پروژه را به صورتِ خودکار کامپایل می‌کند).

در صورتِ بروزِ خطا، از VPN استفاده کنید. گاهی به خاطرِ محدودیتِ کاربرانِ ایرانی در دسترسی به برخی از سرورها این مشکل به وجود می‌آید. البته بعد از کامپایل پروژه تا زمانی که از کتابخانۀ جدیدی استفاده نکنید بدونِ VPN می‌توانید کدها را تغییر و کامپایل بگیرید.

در ناحیۀ چپ (پنلِ Project) می‌توانید فایل‌های پروژه را مدیریت کنید. در قسمتِ پایین پروسۀ کامپایل و Build با جزئیات نمایش داده می‌شود. وقتی همۀ تیک‌ها سبز باشد یعنی برنامه به درستی کامپایل شده و می‌توانید روی گوشی تست کنید.

فایل activity_main.xml برای طراحیِ layout یا ظاهرِ برنامه است و فایلِ MainActivity.kt ادیتور یا ویرایشگرِ کدهاست که کدِ برنامه را داخلِ آن خواهید نوشت.

در نام‌گذاریِ کلاس همانطور که می‌بینید آخرش Activity آورده شده است. این کار ضروری نیست ولی قراردادِ رایجی است که بهتر است شما نیز رعایت کنید.

اگر نوارِ خاکستریِ Tool Window در منتهی الیهِ سمتِ چپ وجود نداشت می‌توانید به دو روش باز کنید. یا از منویِ View گزینۀ Tool Window را انتخاب کنید یا مربعِ کوچکِ گوشۀ چپِ پایین در پنجرۀ اصلی را کلیک کنید. یکبار این کار را بکنید تا متوجه شوید منظورم کدام قسمت است.

ساختِ Layout برنامه

فایلِ activity_main.xml را باز کنید و از قسمتِ پایین تبِ Design را بزنید. مطابقِ قرارداد، نامِ هر layout با _activity آغاز می‌شود و در ادامه با حروفِ کوچک نامِ اکتیویتی پایان می‌یابد. مثلاً برای MainActivity از نامِ activity_main.xml و برای SplashScreenActivity از activty_splash_screen استفاده می‌شود. این روشِ نام‌گذاری در اندروید مرسوم بوده و شما نیز بهتر است از آن پیروی کنید.

پنجره‌ای که می‌بینید Layout Editor است. هر کاری در این صفحه انجام دهید؛ اعم از درگ کردن دکمه و تکست‌باکس و … همگی به کدهای XML تبدیل می‌شود که با کلیک روی تبِ Text می‌توانید مشاهده کنید.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

حتی به صورتِ مستقیم می‌توانید در تبِ Text با کدهای XML رابطِ کاربری برنامه را بسازید. اینکه از کدام روش استفاده کنید بستگی به سلیقۀ شما دارد. ولی اغلبِ توسعه‌دهندگانِ به خاطرِ انعطاف و سرعتِ بیشترِ تبِ Text آن را ترجیح می‌دهند. گوگل در هر نسخه از اندروید استودیو بهبودهای زیادی برای Layout Designer ارائه می‌کند ولی همچنان آنطور که باید با استقبالِ کاربران مواجه نشده است.

در کدِ بالا از دو ویو (View) استفاده شده: ConstraintLayout و TextView. در اندروید به هر المانِ گرافیکی یک ویو گفته می‌شود. دسته‌ای از ویوها مثل دکمه، تکست‌باکس و … که کاربر می‌تواند با آن‌ها تعامل کند ویجت و مابقی ویو خوانده می‌شوند. مرزِ دقیقی برای این تعریف وجود ندارد. به همین خاطر می‌توانید برای همۀ المان‌ها از ویو استفاده کنید.

بعضی از ویوها برای دسته‌بندی و چیدمانِ سایر ویوها به کار می‌روند. به این‌ها ViewGroup گفته می‌شود. در کدِ بالا ConstraintLayout ویوگروپی است که داخلش یک TextView قرار دارد. در قسمت‌های بعد با ContraintLayout بیشتر آشنا خواهید شد.

ConstraintLayout ویوگروپِ پیش‌فرضِ اندروید است ولی این چیزی نیست که ما دنبالش هستیم. برنامۀ ما layout ساده‌ای دارد:

  • یک LinearLayout عمودی؛
  • یک TextView؛
  • یک LinearLayout افقی؛
  • دو Button.

LinearLayout افقی دو دکمۀ True و False را در بر می‌گیرد که به همراه یک TextView درونِ LinearLayout عمودی قرار گرفته است. حال کدِ XML صفحه را بررسی کنیم:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="24dp"
        android:text="@string/question_text" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/true_button" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/false_button" />

    </LinearLayout>

</LinearLayout>

برای هر ویجتِ XML یک المان وجود دارد. یک TextView برایِ نمایشِ سوال و دو دکمۀ True و False که خود درونِ یک LinearLayout افقی و همۀ این‌ها درونِ یک LinearLayout عمودی قرار دارند. هر المانِ XML از مجموعه‌ای از Attribute (خاصیت)ها تشکیل شده که با استفاده از آن نحوۀ نمایش المان را پیکربندی می‌کنیم. اگر بخواهیم عناصرِ برنامه را به صورتِ سلسله مراتبی نشان دهیم با چنین تصویری روبرو هستیم:

به این ساختارِ سلسله‌مراتبی، View Hierarchy گفته می‌شود. در رأس Layout یک LinearLayout قرار دارد که به عنوان Root Element شناخته می‌شود. المانِ ریشه حتماً باید فضایِ نامِ “xmlns:android=”http://schemas.android.com/apk/res/android را تعریف کند. این فضایِ نام مشخص می‌کند که خواصِ سندِ جاری مربوط به اندروید هستند و این کار جلوی تداخل با خواص دیگر را می‌گیرد.

LinearLayout از کلاسِ ViewGroup که خود زیرکلاسی از View است ارث می‌برد. این ویو زمانی به کار می‌رود که بخواهیم المان‌ها را در یک ردیف یا ستون نمایش دهیم. ویوگروپ‌های دیگری مثلِ ConstraintLayout و FrameLayout نیز وجود دارند که برای چیدمان‌های پیچیده‌تر به کار می‌روند. ولی برای چیزی که ما می‌خواهیم LinearLayout انتخابِ مناسب‌تری است.

بررسی فایلِ activity_main.xml

android:layout_width و android:layout_height
دو خصیصۀ مهمی است که تقریباً هر ویجتی به آن‌ نیاز دارد. مقدارِ این خاصیت match_parent یا wrap_content است. اولی المان را به اندازۀ والد(Parent) و دومی به اندازۀ محتوا گسترش می‌دهد. برای LinearLayout ریشه مقدار طول و عرض match_parent است تا به اندازۀ کل صفحه گسترش یابد. برای بقیۀ ویجت‌ها از wrap_content استفاده کرده‌ایم.

android:gravity
محتوایِ ویو را وسط قرار می‌دهد.

android:padding
یک فاصلۀ خالی بین نوشته و حاشیۀ اطرافش ایجاد می‌کند. واحدِ dp یا density-independent را در درس‌های بعد آموزش می‌دهیم؛ فعلاً در همین حد بدانید که ۱dp روی یک گوشی با تراکم ۱۶۰dpi (اصطلاحاً mdpi) برابرِ یک پیکسل است.

android:orientation
افقی یا عمودی بودنِ LinearLayout را مشخص می‌کند. اگر افقی انتخاب کنید فرزندانِ آن به صورت افقی در کنارِ هم قرار می‌گیرند. اگر عمودی انتخاب کنید زیرِ هم و در یک ستون قرار می‌گیرند. همانطور که می‌بینید LinearLayout ریشه عمودی است و دیگری افقی. عناصر به ترتیبی که تعریف می‌کنید نمایش داده می‌شوند.

android:text
یکی از خصایت‌های مهم در TextView و Button است که متنی را به کاربر نمایش می‌دهد. دقت کنید به جای متن به یک رشته در ریسورس ارجاع داده‌ایم. در اندروید ریسورس‌های زیادی داریم که حسبِ نوعشان در فایل‌های مجزا قرار گرفته‌اند. بر همین اساس رشته‌های متنی در فایل strings.xml ذخیره می‌شوند تا از هر جایی بتوانیم به آن‌ها ارجاع دهیم.

می‌توانید متن را به صورت مستقیم هم بنویسید ولی روشِ خوبی نیست چون اگر بعدها نیاز شد آن متن را تغییر دهید باید سراسرِ کدها را برای یافتن و ویرایشِ آن متن جستجو کنید. ولی اگر به یک رشته در strings.xml ارجاع دهید کافی است همان یک رشته را تغییر دهید تا هر فایلی که به آن رشته ارجاع داده بروز شود. این موضوع برای چندزبانه کردن یا محلی‌سازی (Localization) برنامه حائز اهمیتی فراوانی است. کافی است رشته‌های موجود در فایل strings.xml را به زبان‌های دیگری ترجمه کنید. در این باره بعدها توضیح می‌دهم.

برای ساختِ ریسورس‌های متنی فایل res/values/strings.xml را باز کنید و به این صورت رشته‌های مورد نیاز را بنویسید:

<resources>
    <string name="app_name">GeoQuiz</string>
    <string name="question_text">Canberra is the capital of Australia.</string>
    <string name="true_button">True</string>
    <string name="false_button">False</string>
</resources>

هر نسخه‌ای از اندروید استودیو معمولاً چند ریسورسِ پیش‌فرض در این فایل قرار می‌دهد. مثلاً اینجا ریسورس app_name حاویِ نامِ برنامه است.

روشِ ساده‌تری نیز برای تعریفِ ریسورس‌ها وجود دارد. هنگام نوشتن مقادیرِ XML اگر ریسورسی وجود نداشته باشه رنگِ آن قرمز می‌شود و در سمتِ چپ علامتِ تعجبی با پس زمینۀ قرمز ظاهر می‌شود:

با کلیک روی گزینۀ Create string value resource پنجرۀ زیر باز می‌شود:

در قسمتِ Resource value می‌توانید مقدارِ مورد نظر را وارد کرده و OK بزنید. کار تمام است. اندروید استودیو به صورت خودکار یک ریسورسِ متنی در فایلِ strings.xml اضافه می‌کند. البته اسمِ این فایلِ هر چیزِ دیگری هم می‌تواند باشد.

اکنون هر جایی به string/false_button@ ارجاع دهید مقدار False نمایش داده می‌شود. شاید روزی بخواهید برنامه را به زبانِ فارسی بسازید. کافی است مقدار False به به «نادرست» تغییر دهید. می‌توانید برای هر زبان یک فایلِ strings.xml تعریف کنید که بعداً در مورد آن حرف می‌زنیم.

با اضافه کردن هر سه ریسورس دیگر خطایی در Layout وجود ندارد. اکنون Layout آماده است. به تبِ Design بروید تا ببینید چه ساخته‌اید. بد نیست با قسمت‌های مختلفِ حالتِ Design نیز آشنا شوید.

آشنایی با قسمت‌های مختلف Layout Editor

به ترتیبِ شماره:

  1. این پلت حاویِ ویوها و ویجت‌هاست. هر یک از آن‌ها را می‌توانید با درگ کردن روی صفحه بکشید. البته خیلی دلچسب نیست. بیشتر به دردِ این می‌خورد که بفهمید چه المان‌هایی در اختیار دارید. در قسمتِ بالای پلت با کلیک روی ذره‌بین می‌توانید ویجتِ مورد نظر را جستجو کنید؛
  2. ساختارِ سلسله‌مراتبیِ ویوها را نشان می‌دهد. روی هر یک کلیک کنید در پیش‌نمایش انتخاب می‌شود و بالعکس روی هر یک از عناصرِ صفحه کلیک کنید در این پنجره به حالتِ انتخاب در می‌آید. این پنجره کاربرد زیادی برای درکِ ساختار Layout دارد؛ خصوصاً برای Layout های پیچیده؛
  3. در پنجرۀ Design به دو صورت می‌توانید نمایِ بصری برنامه را ببینید. اولی حالتِ Design است که آنچه را در گوشی می‌بینید به شما نمایش می‌دهد و دومی Blueprint است که نقشه رابطِ کاربری را نشان می‌دهد. البته فرقی زیادی ندارد و به ندرت استفاده می‌شود. از نوار ابزارِ بالا می‌توانید نوعِ نمایشِ را عوض کنید؛
  4. در این قسمت می‌توانید نمای برنامه را در حالت افقی (Landscape) و عمودی (Portrait) مشاهده کنید. حالتِ شب را فعال کنید. UI Mode های مختلفی مثلِ Car Dock, Desk Dock, Watch, Television و … را ببینید.

    گزینۀ Create Landscape Variation به صورت خودکار یک Layout برای حالتِ Landscape درست می‌کند. یکی از ویژگی‌های جالبِ اندروید این است که با توجه به پیکربندی‌های مختلف می‌توانید واسطِ کاربری برنامه را تغییر دهید. مثلاً با قرار گرفتنِ گوشی در حالت Landscape نمای برنامه (layout) را به کلی تغییر دهید.

    این پیکربندی‌ها را می‌توانید با هم ترکیب و Layoutهای هوشمندی بر اساسِ شرایط مختلف نمایش دهید. مثلاً اگر زبانِ گوشی فارسی باشد و گوشی در حالت Landscape قرار بگیرد و حالتِ شب هم فعال باشد یک Layout مشخص نمایش داده شود. به هر یک از این حالت‌ها یک qualifier گفته می‌شود. با کلیک روی گزینۀ Create other می‌توانید به همۀ انواع qualifier ها دسترسی داشته باشید و با ترکیبِ آن‌ها هر نوع Layoutای را بسازید. البته هرچقدر تعداد qualifier ها زیاد باشد زحمتِ شما هم زیاد می‌شود؛ چون برای هر یک از حالت‌ها باید واسطِ کاربری جدایی طراحی کنید؛
  5. در این قسمت می‌توانید واسطِ کاربری را در گوشی، تبلت‌، ساعت و تلویزیون اندرویدی با اندازه‌ها، رزولوشن‌‌ها و تراکم پیکسلی مختلف ببینید. معمولاً همین تعداد کافی است ولی در صورتِ لزوم با کلیک رویِ گزینۀ Add Device Definition می‌توانید دیوایسِ جدیدی با مشخصاتِ دلخواه تعریف کنید؛
  6. پیش‌نمایش را در یک API Level دلخواه نشان می‌دهد. فقط API هایی را در این قسمت می‌بینید که نصب کرده باشید؛ یعنی در فولدرِ Android Sdk در زیرفولدرِ Platforms وجود داشته باشند؛
  7. از این قسمت می‌توانید تم‌های مختلف را روی پیش‌نمایشِ برنامه اعمال کنید. AppTheme به صورتِ پیش‌فرض در حالتِ انتخاب قرار گرفته که تمِ فعلی برنامه را نشان می‌دهد. این تم در فایلِ res/values/styles.xml قرار دارد؛
  8. اگر برنامۀ شما چندزبانه باشد و برای هر زبان یک ریسورسِ متنی تعریف کرده باشید، از اینجا می‌توانید پیش‌نمایشِ برنامه را در زبانِ مورد نظر ببینید. حالتِ پیش‌فرض انگلیسی است. یک گزینۀ Edit Translation نیز وجود دارد که به راحتی می‌توانید رشته‌ها را در هر زبانی ترجمه و ویرایش کنید. از همینجا می‌توانید زبانِ جدیدی به برنامه اضافه کنید. اندروید استودیو در مدیریتِ ریسورس‌ها بسیار قوی عمل کرده و ابزارهای مفیدی در اختیارتان قرار داده است؛
  9. پیش‌نمایشِ برنامه را بزرگ و کوچک می‌کند؛
  10. وقتی پیش‌نمایشِ برنامه بزرگ شد با کلیک روی این دکمه می‌توانید مجدداً نمایِ کاملش را ببینید؛
  11. گاهی یک مثلث نارنجی یا یک دایرۀ قرمز در این قسمت نمایش داده می‌شود. دایرۀ قرمز که داخلش یک علامتِ تعجب خورده معمولاً زمانی نشان داده می‌شود که در فایلِ XML خطا وجود داشته باشد؛ مثلاً استفاده از ریسورسی که هنوز تعریف نکرده‌اید.

    مثلثِ نارنجی خطا نیست ولی ممکن است در شرایطی مشکل‌ساز شود. توجه به این اخطارها مهم است. با کلیک روی آن می‌توانید جزئیاتش را در قسمتِ پایین ببینید. مثلاً برای ما این اخطار را داده: Button should be borderless که با کلیک روی آن جزئیاتِ بیشتری نشان داده می‌شود. اخطارِ مهمی نیست ولی اگر مایل به اصلاحش هستید می‌توانید در گوگل جستجو کنید. مثلاً برای این خطا تغییر استایلِ دکمه پیشنهاد شده که می‌توانید در این لینک ببینید؛
  12. در این قسمت خواصِ ویوی انتخاب شده را می‌توانید به صورت بصری تغییر دهید. مثلاً می‌توانید wrap_content و match_parent یا متنِ ویجت‌ها را تغییر دهید؛ در واقع همان کاری که در فایلِ XML انجام می‌دادیم را می‌توانید به صورت بصری انجام دهید. با کلیک روی ذره‌بینِ بالای این پنل می‌توانید خصیصۀ مورد نظرتان را یافته و تغییر دهید. بازهم پیشنهادِ می‌کنم خودتان را به XML عادت دهید؛ سرعتتان بالاتر می‌رود.
بخوانید  آموزش توسعۀ آزمون محور (TDD) در اندروید – قسمت سوم

در Layout Editor یک نوار ابزارِ دیگر نیز وجود دارد:

بر اساسِ ویوی انتخاب شده ابزارهای این بخش ممکن است کمی متفاوت باشند. با کلیک روی آیکونِ چشم و انتخابِ گزینۀ Show Layout Decoration می‌توانید Status bar و Navigation bar را به این شکل ببینید (به نوار سبز بالا و مشکیِ پایین دقت کنید):

آشنایی با فایل‌هایِ مهمِ پروژه

حالا این فایلِ XML چطور به کدهای واقعی تبدیل می‌شود؟ یعنی مثلاً تگِ TextView چطور به شی TextView تبدیل می‌شود. اجازه دهید قبل از پرداختن به این موضوع نگاهی به ساختارِ فایل‌ها و فولدرهایِ پیش‌فرض در یک پروژۀ اندروید بیندازیم.

در ویرایشگر آیکونی وجود دارد که با کلیک روی آن فایلِ Layout باز می‌شود:

همین قابلیت در فایلِ Layout نیز وجود دارد. با کلیک روی دکمۀ آبیِ C فایل MainActivity.kt باز می‌شود:

در سمتِ چپ، یعنی در پنلِ Project دو دکمه به شماره‌های ۱ و ۲ می‌بینید که بسیار کاربردی هستند.

با کلیک روی دکمۀ شمارۀ ۱ جایگاهِ فایلِ کنونی در سلسله مراتبِ فایل‌ها نشان داده می‌شود؛ بنابراین خیلی سریع می‌توانید بفهمید که مثلاً فایلِ MainActivity.kt یا activity_main.xml کجا قرار گرفته است. این ویژگی به‌خصوص زمانی که تعداد فایل‌های پروژه زیاد باشد کاربرد دارد.

دکمۀ شمارۀ ۲ با عنوانِ Collapse All تمامی گره‌ها را تا بالاترین سطح می‌بندد. یک ویژگیِ مشترک در تمامِ IDEهای مبتنی بر Intellij – که اندروید استودیو نیز یکی از آن‌هاست – این است که برای تمامِ دکمه‌ها و زیرمنوها اگر شورتکاتی وجود داشته باشد درون tooltip یا مقابلِ منو نمایش داده می‌شود.

در پنلِ چپ یک قابلیتِ مهمِ دیگر نیز وجود دارد که چند گزینۀ مهمش را بررسی می‌کنیم:

هر یک از گزینه‌های این منو نمایی از ساختارِ سلسله مراتبی فایل‌ها است. مثلاً افرادی که سروکارشان با تست و تست‌نویسی است نمایِ Tests را انتخاب می‌کنند. در این حالت اندروید استودیو فقط فایل‌هایِ مربوط به تست را به کاربر نشان می‌دهد؛ پس دیگر اثری از فایلِ MainActivity.kt و activity_main.xml و ریسورس‌ها نخواهد بود. شاید فقط با سورس یعنی فایل‌های جاوا و کاتلین کار دارید پس نمایِ Project Source Files را برمی‌گزینید و شاید همه چیز را می‌خواهید الا سورس‌ها؛ این بار Project Non-Source File را انتخاب می‌کنید.

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

در نمایِ Project Files فایل‌های پروژه به همان صورتی که در File Explorer می‌بینید نمایش داده می‌شود. اندروید استودیو در این مورد هیچ دخالتی نمی‌کند و حتی فایل‌های نامرتبط با پروژه و فولدرهای خالی را هم نمایش می‌دهد. بنابراین اگر فایلی در فولدرِ پروژه دارید که در نماهای دیگر قابل رویت نیست بهتر است نمایِ Project Files را انتخاب کنید تا بی‌کم‌وکاست همه‌چیز را ببینید. در نمایِ Android که حالتِ پیش‌فرضِ اندروید استودیو است فقط فایل‌های مهم و اساسی که در فرایندِ ساخت و توسعۀ برنامه به آن نیاز دارید نمایش داده می‌شود. دسته‌بندی فایل‌ها صرفاً برایِ سهولتِ دسترسی است و با چیزی که در File Explorer می‌بینید متفاوت است.

خب به نمایِ Android برمی‌گردیم و فایل‌ها را بررسی می‌کنیم.

ابتدا فولدرِ app:

AndroidManifest.xml
هر برنامه‌ای در اندروید باید فایلی با نامِ AndroidManifest.xml داشته باشد. این فایل حاویِ اطلاعاتی است که برنامۀ شما را به Built tools، اندروید و گوگل پلی (و سایرِ مارکت‌های اندرویدی) معرفی می‌کند. این فایل شاملِ اطلاعاتِ فراوانی از نامِ پکیج، پرمیژن‌ها، کامپوننت‌های برنامه و … است که در آینده به صورتِ مفصل توضیح می‌دهم.

فایل‌های بعدی که بیشترِ وقتمان را در آن می‌گذرانیم اکتیویتی‌ها هستند. در اینجا فقط یک فایلِ MainActivity.kt داریم که در زیرشاخۀ java/com.bignerdranch.android.geoquiz قرار گرفته است. هرچند که می‌توانید این فایل را در فولدرِ دیگری مثلاً kotlin قرار دهید ولی از آنجایی که بین کاتلین و جاوا رابطۀ نزدیکی وجود دارد انجامِ این کار ضروری نیست. در واقع تفکیک سورس فایل‌ها بر اساسِ زبان مزیتِ چندانی برای شما ایجاد نمی‌کند. پس اجازه دهید به همین صورت باقی بماند.

ExampleInstrumentTest و ExampleUnitTest همانطور که از نامشان پیداست دو نمونه تست هستند که می‌توانید برای برنامۀ خود بنویسید. اندروید استودیو به صورتِ خودکار این دو فایل را برای هر پروژۀ جدید می‌سازد. قبلا در بحثِ تستِ کدها و آموزشِ توسعهِ آزمون محور به صورتِ عملی به این موضوع پرداخته‌ایم.

BuildConfig.java در فولدر Build قرار دارد و طبقِ قاعده‌ای کلی هر فایلی که در این فولدر قرار گرفته تحتِ کنترلِ Build Tools است؛ بنابراین محتوایِ آن را نمی‌توانید ویرایش کنید. یا بهتر بگویم اگر ویرایش کنید، بعد از کامپایل مجدداً به حالتِ قبل بازمی‌گردد.

فولدرِ دیگری به نامِ res وجود دارد که حاویِ تمامِ ریسورس‌های برنامه است؛ اعم از: تصاویر، صداها، آیکون‌ها، رشته‌ها، استایل‌ها، تم‌ها و … .

layoutها در فولدر Layout قرار می‌گیرند. تصاویر و آیکون‌ها در فولدرِ drawable و آیکونِ برنامه در فولدرِ mipmap قرار می‌گیرد و نهایتاً مقادیری مثلِ رنگ‌ها، رشته‌ها و استایل‌ها در فولدرِ values قرار می‌گیرند. در آینده با هر یک از این فایل‌ها کار می‌کنیم و خواهید دید که هدف از آن‌ها چیست.

بخوانید  آموزش زبان کاتلین – درس 15 (توابع infix)

بخشِ مهمِ دیگر Gradle Scripts است که مختصِ پیکربندی و تنظیماتِ کامپایلر است:

دو فایلِ build.gradle وجود دارد که یکی متعلق به پروژه (Project) و دیگری متعلق به ماژول (Module) است. (build.gradle(Project بالاترین سطحِ پیکربندی پروژه است که تنظیماتِ آن روی تمامِ زیرپروژه‌ها و ماژول‌ها اعمال می‌شود. (یک پروژه می‌تواند بیش از یک ماژول داشته باشد). فایلِ (build.gradle(Module فقط تنظیماتِ مربوط به یک ماژول را نگه‌داری می‌کند و کاری به ماژول‌های دیگر ندارد.

هر ماژول مسئولِ بخشی از پروژه است و وظیفه‌ای بر عهده دارد. با ترکیبِ ماژول‌ها، پروژۀ نهایی ساخته می‌شود. البته در اکثرِ برنامه‌های اندرویدی فقط یک ماژول (app) وجود دارد. هر ماژول دارای یک فایلِ build.gradle مختص به خود است. مثلاً در یک پروژه با سه ماژول با چنین تصویری روبرو هستیم:

با تغییرِ نمایِ پروژه به Project می‌توانید جایگاه هر یک از این فایل‌ها را در ساختارِ پروژه ببینید:

فایلِ gradle-wrapper-properties نسخه‌ای از گریدل که پروژۀ شما بر مبنای آن کامپایل شده را مشخص می‌کند. هر زمان بخواهید از نسخۀ جدیدی از گریدل استفاده کنید این فایل را باید آپدیت کنید. gradle.properties حاوی تعدادی پراپرتیِ جاوا است که صرفاً مقادیری از نوعِ string می‌پذیرد. بنابراین مقادیری مثلِ آرایه و لیست را نمی‌توانید در این فایل ذخیره کنید. به ندرت به این فایل نیاز پیدا می‌کنید چون حاویِ مقادیری است که مربوط به خودِ گریدل است.

فایلِ بعدی settings.gradle حاویِ اسکریپت‌هایی به زبانِ Groovy است. این اسکریپت پیش از اسکریپت‌های build.gradle و حتی پیش از اینکه instance ای از پروژه ساخته شود اجرا می‌شود. این فایل در سطحِ پروژه تعریف می‌شود؛ بنابراین صرفنظر از اینکه چند ماژول در پروژۀ شما وجود داشته باشد تنها یک فایل settings.gradle وجود دارد. معمولاً هدفِ اصلی از این فایل تعریفِ تمامِ ماژول‌های یک پروژه است.

در نمایِ Project فایل‌های دیگری نیز وجود دارد که فعلاً قصد بررسی‌شان را نداریم. بعداً با کاربردِ هر یک از این فایل‌ها و تنظیماتشان آشنا می‌شوید. فعلاً در همین حد بدانید که این فایل‌ها برای پیکربندی پروژه، ماژول‌ها و گریدل هستند.

نوشتنِ کدهای MainActivity.kt

package com.bignerdranch.android.geoquiz

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

AppCompatActivity زیرکلاسی از کلاسِ Activity است که برای سازگاریِ برنامه با نسخه‌های قدیمیِ اندروید استفاده می‌شود. در موردِ این کلاس بعداً توضیحاتِ بیشتری می‌دهم. برایِ دیدن همۀ importها روی علامتِ بعلاوه کلیک کنید:

اکتیویتیِ ما دارای یک فانکشنِ (?onCreate(Bundle است. این فانکشن زمانی که یک شی از اکتیویتی ساخته می‌شود فراخوانی می‌شود. یک اکتیویتی همانطور که گفتیم نیازمند UI یا واسطِ کاربری است تا با آن ارتباط برقرار کند. این کار را توسطِ تابعِ setContentView انجام می‌دهیم. این تابع layout دریافتی را اصطلاحاً inflate می‌کند؛ یعنی اندروید layout شما را به ویو آبجکت‌ها تبدیل کرده و در صفحه نشان می‌دهد. بعداً خواهید دانست که با کلاسِ LayoutInflater می‌توانید مستقیماً layout را به شی View تبدیل کنید.

R.layout.activity_main چیست؟

هر layout یک ریسورس است. ریسورس بخشی از برنامه است که کد نیست. قبلاً گفتم تصاویر، فایل‌های صوتی، آیکون و البته فایل‌های XML که layout یکی از آن‌هاست همگی ریسورس هستند. محلِ ریسورس‌ها را هم می‌دانید: app/res. در این فولدر با توجه به نوعِ ریسورس، فولدرهای دیگری وجود دارد. layoutها در فولدرِ layout قرار دارند. برای دسترسی به هر ریسورس به ID اش نیاز داریم. اما این آیدی چیست؟ چطور ساخته می‌شود؟

تمامِ IDها را خودِ Build Tools می‌سازد. کافی است یکبار پروژه را بیلد کنید. (آیکونِ چکش یا کلیدِ Ctrl+F9).

نمایِ پروژه را به Project تغییر دهید و مطابقِ تصویر فایلِ R.java را پیدا کنید:

این فایل قلبِ ریسورس‌هاست. Build Tools به صورتِ خودکار بعد از کامپایلِ پروژه تمامِ آیدی‌ها را در این فایل تعریف می‌کند. همانطور که می‌بینید آیدیِ activity_main درونِ کلاسِ layout تعریف شده (قسمتِ هایلایت شده)؛ یعنی اگر بخواهیم آدرس بدهیم باید اینطور بنویسیم: R.layout.activity_main. فایل R.java بسیار شلوغ و طولانی است؛ ولی خوشبختانه کاری با آن ندارید و فقط آیدی‌ها را فراخوانی می‌کنید. قبلاً هم گفتم فایل‌هایی را که توسطِ کامپایلر تولید می‌شوند تغیر ندهید. حتی اگر اجازۀ تغییر داشته باشید بعد از کامپایلِ بعدی همۀ تغییراتتان از بین می‌رود.

اندروید برای تمامِ رشته‌ها و layout آیدی می‌سازد ولی اینکه کدام ویجت‌ یا ویو در layout دارای آیدی باشد به عهدۀ توسعه‌دهنده است. مثلاً در پروژۀ ما کاربر فقط با دو دکمۀ True و False ارتباط برقرار می‌کند. بنابراین فقط این دو دکمه نیازمندِ ID هستند. برای تعریفِ آیدی از خصیصۀ android:id استفاده کنید؛ به این صورت:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout

        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical">

    <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
              android:padding="24dp"
              android:text="@string/question_text" android:baselineAligned="false"/>

    <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content"
                  android:orientation="horizontal">

        <Button android:id="@+id/true_button" android:layout_width="wrap_content" android:layout_height="wrap_content"
                android:text="@string/true_button"/>

        <Button android:id="@+id/false_button" android:layout_width="wrap_content" android:layout_height="wrap_content"
                android:text="@string/false_button"/>
    </LinearLayout>


</LinearLayout>

شاید بپرسید چرا این خاصیت مثل android:text بعلاوه (+) ندارد و به جایِ آن از id+@ استفاده کردیم. دلیلش این است که برای رشته فقط به فایلِ string ارجاع می‌دهیم ولی اینجا آیدیِ جدیدی می‌سازیم. در واقع به اندروید اعلام می‌کنیم که برای این دکمه آیدیِ false_button تعریف کن.

نمایِ پروژه را به Android تغییر دهید. دو ریسورسِ جدید به نام‌های correct_toast و incorrect_toast به فایلِ Strings.xml اضافه کنید.

<resources>
    <string name="app_name">GeoQuiz</string>
    
    <string name="true_button">True</string>
    <string name="false_button">False</string>
    <string name="question_text">Canberra is the capital of Australia.</string>
    <string name="correct_toast">Correct!</string>
    <string name="incorrect_toast">Incorrect!</string>
</resources>

می‌خواهیم با کلیک روی دکمۀ True پیغامِ درونِ correct_toast نشاد داده شود (یعنی !Correct) و اگر False را زد پیغامِ incorrect_toast را نمایش دهد. حالا کدهای زیر را در فایلِ MainActivity.kt بنویسید. پیشنهاد می‌کنم کدها را ابتدا با چشم بررسی کنید و سپس خودتان در اندروید استودیو بنویسید. هیچ‌وقت با چشم تمرین نکنید.

package com.bignerdranch.android.geoquiz

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.Toast

class MainActivity : AppCompatActivity() {

    private lateinit var trueButton: Button;
    private lateinit var falseButton: Button;

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        trueButton = findViewById(R.id.true_button);
        falseButton = findViewById(R.id.false_button);

        trueButton.setOnClickListener { view: View ->
            Toast.makeText(this,
                R.string.correct_toast,
                Toast.LENGTH_SHORT)
                .show();
        }
        falseButton.setOnClickListener { view: View ->
            Toast.makeText(this,
                R.string.incorrect_toast,
                Toast.LENGTH_SHORT)
                .show();
        }

    }
}

ابتدا دو متغیر برای نگهداریِ trueButton و falseButton تعریف می‌کنیم. کاتلین برخلافِ جاوا اجازه نمی‌دهد مقدارِ هیچ متغیری را null قرار دهید مگر اینکه خودتان صراحتاً اعلام کنید. مثلاً var str=null. از طرفی تا زمانی که متدِ onCreate و متعاقباً findViewById فراخوانی نشود امکان مقداردهی دو متغیرِ یادشده وجود ندارد. اینجا به متغیری نیاز داریم که بتوانیم مقداردهیِ آن را در آینده تضمین کنیم. برای چنین هدفی از کلمۀ کلیدیِ lateinit (یعنی مقداردهی دیرهنگام) استفاده می‌کنیم. پس به جای اینکه بنویسیم private var trueButton: Button می‌نویسیم private lateinit var trueButton :Button. با این کار به کامپایلر اعلام می‌کنیم که مقدارِ این متغیر را بعداً خودم مشخص می‌کنم.

در داخلِ متدِ ()onCreate ابتدا آیدی R.layout.activity_main را به متدِ ()setContentView ارسال کرده‌ایم تا xml layout ای که نوشتیم به اکتیویتی اختصاص یابد و به کاربر نمایش داده شود. بعد از نمایشِ layout در دو خط بعدی با کمکِ متد ()findViewById دنبالِ آیدیِ دو دکمۀ true و false گشته‌ایم. اینجا متغیرها مقداردهی می‌شوند. اکنون درونِ هر یک از متغیرهای trueButton و falseButton یک شی ویو (از نوعِ Button) قرار گرفته است.

در ادامه با متدِ ()setOnClickListener برای هر یک از دکمه‌ها یک Event Listener تعریف کرده‌ایم. Listener منتظر می‌ماند تا کاربر روی یکی از دکمه‌ها کلیک کند تا کاری که درونِ آن تعریف شده را اجرا کند؛ که اینجا نمایشِ یک پیام است.

یکی از ساده‌ترین روش‌ها برای نمایشِ پیام در اندروید استفاده از Toast است. کلاسِ Toast متدی دارد به اسمِ makeText که متنِ موردِ نظرِ شما را نمایش می‌دهد. پارامترِ اولِ این متد context است که اینجا ما this قرار دادیم تا به اکتیویتیِ جاری (یعنی MainActivity) اشاره کند. در واقع Toast از ما می‌پرسد که پیغام را در چه contextای نمایش دهم و ما با ارسالِ this به اکتیویتیِ کنونی اشاره می‌کنیم. پارامترِ بعدی آیدیِ رشته‌ای است که می‌خواهیم نمایش دهد و پارامترِ آخر مدتِ زمانِ نمایشِ پیام را می‌پرسد. در آخر با متدِ ()show دستورِ نمایشِ Toast را صادر کرده‌ایم.

نکته: در صورت نیاز می‌توانید معادلِ جاوای کدهای کاتلین را ببینید. برای این کار از منویِ Tools گزینۀ Kotlin و سپس Show Kotlin Bytecode را انتخاب کنید. پنجره‌ای باز میشود که با کلیک روی دکمۀ Decompile نسخۀ جاوا نمایش داده می‌شود. دقت کنید این فایل، نمایشی است و امکانِ تغییرِ محتوای آن وجود ندارد. محتوایِ فایلِ اصلی که با زبان کاتلین نوشته‌اید نیز تغییری نمی‌کند. البته چون کدهای جاوا از دیکامپایلِ بایت‌کدهای جاوا به دست آمده، چندان با خروجیِ تمیزی مواجه نخواهید شد؛ ولی به هر حال گاهی به درد می‌خورد.

اجرایِ برنامه

حالت دیباگینگ را بر رویِ گوشی فعال کنید و سپس با کابلِ USB به سیستم متصل شوید. حالا با دکمۀ Shift+F10 برنامه را اجرا کنید. ممکن است پنجرۀ زیر باز شود:

در این پنجرۀ تمامِ دستگاه‌هایی که در حالتِ Debugging به سیستم متصل باشند نمایش داده می‌شود. یکی از دستگاه‌ها را انتخاب و OK کنید تا برنامه روی آن نصب و اجرا شود. با تیک زدن گزینۀ پایین دستگاهِ انتخاب شده پیش‌فرض در نظر گرفته می‌شود و در دفعات بعد بدونِ نمایشِ این پنجره، برنامه مستقیماً اجرا می‌شود.

در قسمتِ بعد سوالاتِ بیشتری به GeoQuiz اضافه می‌کنیم و الگویِ MVC را توضیح می‌دهم. اگر سوال، پیشنهاد یا انتقادی داشتید مطرح کنید.

, , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,

سید ایوب کوکبی

نویسنده و مترجم...

0 دیدگاه

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *