کلاس Activity مؤلفه مهمی از برنامه Android است و نحوه راهاندازی و کنار هم قرار گرفتن فعالیتها بخش اساسی مدل برنامه پلاتفرم است. برخلاف الگوهای برنامهنویسی که در آنها برنامهها با روش main راهاندازی میشوند، سیستم Android کد را در نمونه Activity با فراخوانی روشهای بازفراخوانی خاصی که با مراحل خاصی از چرخه حیات آن مطابقت دارند، آغاز میکند.
این سند مفهوم فعالیتها را معرفی میکند و سپس راهنماییهای سادهای درباره نحوه کار با آنها ارائه میدهد. برای اطلاعات بیشتر درباره روالهای مطلوب در معماری برنامهتان، راهنمای معماری برنامه را ببینید.
مفهوم فعالیتها
تجربه برنامه تلفن همراه با همتای رایانهای آن متفاوت است زیرا تعامل کاربر با برنامه همیشه از یک جا شروع نمیشود. درعوض، مسیر کاربر اغلب بهصورت غیرقطعی شروع میشود. برای مثال، اگر برنامه ایمیلی را از صفحه اصلی باز کنید، ممکن است فهرستی از ایمیلها را ببینید. برعکس، اگر از برنامه رسانههای اجتماعی استفاده میکنید که سپس برنامه ایمیل شما را راهاندازی میکند، ممکن است مستقیماً به صفحه برنامه ایمیل برای نوشتن ایمیل بروید.
کلاس Activity برای تسهیل این الگو طراحی شده است. وقتی برنامهای برنامه دیگری را فرامیخواند، برنامه فراخواننده فعالیتی را در برنامه دیگر فرامیخواند، نه اینکه برنامه را بهعنوان یک کل اتمی فراخواند. به این ترتیب، فعالیت بهعنوان نقطه ورود برای تعامل برنامه با کاربر عمل میکند. فعالیت را بهعنوان زیرکلاس کلاس Activity پیادهسازی میکنید.
فعالیت پنجرهای را ارائه میدهد که برنامه در آن واسط کاربر خود را ترسیم میکند. این پنجره معمولاً کل صفحه را پر میکند، اما ممکن است از صفحه کوچکتر باشد و روی پنجرههای دیگر شناور باشد.
معمولاً، یک فعالیت در برنامه بهعنوان فعالیت اصلی مشخص میشود که اولین صفحهای است که وقتی کاربر برنامه را راهاندازی میکند ظاهر میشود. در برنامههای Compose مدرن، این تنها فعالیت ضروری است، زیرا composable-ها را در یک معماری تکفعالیتی میزبانی میکند، نه اینکه مالک سلسلهمراتب نما باشد. بهجای اینکه برنامه چندین فعالیت برای صفحهها داشته باشد، composableها در فعالیت میزبان چندین مقصد پیمایش هستند.
برای استفاده از فعالیتها در برنامهتان، باید اطلاعات مربوط به آنها را در مانیفست برنامه ثبت کنید و بهتر است از چرخههای حیات فعالیت آگاه باشید. بقیه این سند این موضوعات را معرفی میکند.
درحال پیکربندی مانیفست
برای اینکه برنامهتان بتواند از فعالیتها استفاده کند، باید فعالیتها و برخیاز مشخصههای آنها را در مانیفست اعلام کنید.
اعلام فعالیتها
برای اعلام فعالیتتان، فایل مانیفست را باز کنید و عنصر <activity> را بهعنوان فرزند عنصر <application> اضافه کنید. برای مثال:
<manifest ... >
<application ... >
<activity android:name=".ExampleActivity" />
...
</application ... >
...
</manifest >
تنها مشخصه الزامی برای این عنصر android:name است که
نام کلاس فعالیت را مشخص میکند. همچنین میتوانید مشخصههایی اضافه کنید که
ویژگیهای فعالیت را تعریف میکنند، مثل برچسب، نماد، یا زمینه واسط کاربر. برای اطلاعات بیشتر درباره این مشخصهها و مشخصههای دیگر، به سند مرجع عنصر <activity> مراجعه کنید.
اعلام فیلترهای قصد
فیلترهای قصد ویژگی بسیار قدرتمندی در پلاتفرم Android هستند. آنها امکان راهاندازی فعالیت را نهتنها براساس درخواست صریح، بلکه براساس درخواست ضمنی نیز فراهم میکنند. برای مثال، یک درخواست صریح ممکن است به سیستم بگوید «فعالیت ارسال ایمیل را در برنامه Gmail شروع کن». درمقابل، درخواست ضمنی به سیستم میگوید «صفحه ارسال ایمیل را در هر فعالیتی که میتواند این کار را انجام دهد شروع کن». وقتی میانای کاربر سیستم از کاربر میپرسد که از کدام برنامه برای انجام یک تکلیف استفاده کند، این فیلتر قصد است که درحال کار است.
با اعلام مشخصه <intent-filter> در عنصر <activity> میتوانید از این ویژگی بهره ببرید. تعریف این عنصر شامل عنصر <action> و، بهصورت اختیاری، عنصر <category> و/یا عنصر <data> است. این عناصر باهم ترکیب میشوند تا نوع قصدی را که فعالیت شما میتواند به آن پاسخ دهد مشخص کنند. برای مثال، تکهکد زیر نشان میدهد که چگونه فعالیتی را پیکربندی کنید که دادههای نوشتاری و ایمیل ارسال میکند و درخواستهای مربوط به انجام این کار را از فعالیتهای دیگر دریافت میکند:
<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SENDTO" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="mailto" />
</intent-filter>
</activity>
در این مثال، عنصر <action> مشخص میکند که این فعالیت داده ارسال میکند. اعلام عنصر <category> بهعنوان DEFAULT به فعالیت امکان میدهد
درخواستهای راهاندازی را دریافت کند. عنصر <data> نوع دادهای را که این فعالیت میتواند ارسال کند مشخص میکند. تکهکد زیر نحوه فراخوانی
فعالیت شرحدادهشده در بالا را برای نوشتن ایمیل نشان میدهد:
fun composeEmail(addresses: Array<String>, subject: String) {
val intent = Intent(Intent.ACTION_SENDTO).apply {
data = Uri.parse("mailto:") // Only email apps handle this.
putExtra(Intent.EXTRA_EMAIL, addresses)
putExtra(Intent.EXTRA_SUBJECT, subject)
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
اگر قصد دارید برنامهتان مستقل باشد و به برنامههای دیگر اجازه ندهید فعالیتهای آن را فعال کنند، به فیلترهای قصد دیگری نیاز ندارید. فعالیتهایی که نمیخواهید برای برنامههای دیگر دردسترس باشد نباید فیلتر قصد داشته باشند، و میتوانید آنها را خودتان بااستفاده از قصد صریح شروع کنید. برای کسب اطلاعات بیشتر درباره نحوه پاسخ دادن فعالیتهایتان به قصدها، به قصدها و فیلترهای قصد مراجعه کنید.
مدیریت کردن هدفهای ورودی
مثال زیر الگویی را برای مدیریت چرخه حیات فعالیت هنگام
مدیریت انواع مختلف هدف نشان میدهد: همرسانیهای تکمتنی، تکتصویری، و آرایههای
چندتصویری. با هدایت این ورودیهای متنوع ازطریق یک تابع متمرکز
handleIntent، اطمینان حاصل میشود که هر دو کنش ACTION_SEND و
ACTION_SEND_MULTIPLE بهدرستی تجزیه شده و به
ViewModel واگذار میشوند تا بهروزرسانی واسط کاربر واکنشی انجام شود.
class ExampleActivity : ComponentActivity() {
private val viewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleIntent(intent)
setContent {
ComposeApp(viewModel)
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
handleIntent(intent)
}
private fun handleIntent(intent: Intent?) {
when (intent?.action) {
Intent.ACTION_SEND -> {
if ("text/plain" == intent.type) {
intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
viewModel.handleText(it) // Update UI to reflect text being shared
}
} else if (intent.type?.startsWith("image/") == true) {
(intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))?.let {
viewModel.handleImage(it) // Update UI to reflect image being shared
}
}
}
Intent.ACTION_SEND_MULTIPLE -> {
if (intent.type?.startsWith("image/") == true) {
intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri::class.java)?.let {
viewModel.handleMultipleImages(it) // Update UI to reflect multiple images being shared
}
} else {
// Handle other types
}
}
else -> {
// Handle other intents
}
}
}
}
اعلام اجازهها
میتوانید از برچسب <activity> مانیفست برای کنترل اینکه کدام برنامهها میتوانند فعالیت خاصی را شروع کنند استفاده کنید. فعالیت والد نمیتواند فعالیت فرزند را راهاندازی کند، مگراینکه
هر دو فعالیت اجازههای یکسانی در مانیفست خود داشته باشند. اگر عنصر <uses-permission> را برای فعالیت اصلی اعلام کنید، هر فعالیت فرعی باید عنصر <uses-permission> منطبقی داشته باشد.
برای مثال، اگر برنامهتان بخواهد از برنامه فرضیای بهنام SocialApp برای همرسانی پستی در رسانههای اجتماعی استفاده کند، SocialApp خودش باید اجازهای را که برنامه فراخواننده آن باید داشته باشد تعریف کند:
<manifest>
<activity android:name="...."
android:permission="com.google.socialapp.permission.SHARE_POST"
/>
سپس، برای اینکه برنامهتان اجازه داشته باشد SocialApp را فراخوانی کند، باید با اجازه تنظیمشده در مانیفست SocialApp مطابقت داشته باشد:
<manifest>
<uses-permission android:name="com.google.socialapp.permission.SHARE_POST" />
</manifest>
برای اطلاعات بیشتر درباره اجازهها و امنیت بهطور کلی، به بازبینه امنیت مراجعه کنید.
مدیریت چرخه حیات فعالیت
درطول چرخه عمر فعالیت، آن فعالیت از چند حالت عبور میکند. از مجموعهای از فراخوانیهای برگشتی برای مدیریت گذار بین وضعیتها استفاده میکنید. بخشهای زیر این فراخوانیهای برگشتی را معرفی میکنند. در برنامه Compose، اتصال مستقیم به این callbackها توصیه نمیشود. بهجای آن، از Lifecycle API برای مشاهده تغییرات وضعیت استفاده کنید. برای اطلاعات بیشتر، ادغام چرخه حیات با Compose را ببینید.
onCreate
باید این فراخوانی برگشتی را که هنگام ایجاد فعالیت شما توسط سیستم فعال میشود پیادهسازی کنید. پیادهسازی شما باید مؤلفههای ضروری فعالیتتان را مقداردهی اولیه کند: برای مثال، برنامهتان باید در اینجا نماها را ایجاد کند و دادهها را به فهرستها متصل کند.
در برنامه Compose، از این callback برای راهاندازی composable میزبان خود بااستفاده از
setContent استفاده کنید، همانطور که در زیر نشان داده شده است:
class MyActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Text(text = stringResource(id = R.string.greeting))
}
}
}
وقتی onCreate تمام میشود، تماس برگشتی بعدی همیشه onStart است.
onStart
وقتی onCreate خارج میشود، فعالیت وارد وضعیت «شروعشده» میشود و
فعالیت برای کاربر نمایان میشود. این فراخوانی برگشتی حاوی چیزی است که به منزله
آمادهسازی نهایی فعالیت برای آمدن به پیشزمینه و تبدیل شدن به
تعاملی است.
onResume
سیستم این فراخوانی برگشتی را درست قبلاز اینکه فعالیت شروع به تعامل با کاربر کند
فراخوانی میکند. در این مرحله، فعالیت در بالای پشته فعالیت قرار دارد
و همه ورودیهای کاربر را ضبط میکند. بیشتر عملکردهای اصلی برنامه در روش onResume پیادهسازی میشود.
فراخوانی برگشتی onPause همیشه از onResume پیروی میکند.
onPause
وقتی فعالیت تمرکز را ازدست میدهد و وارد حالت «مکثشده» میشود، سیستم onPause را فراخوانی میکند. این وضعیت زمانی رخ میدهد که، برای مثال، کاربر روی دکمه «برگشت» یا
«موارد اخیر» تکضرب میزند. وقتی سیستم onPause را برای فعالیت شما فراخوانی میکند،
ازنظر فنی به این معنی است که فعالیت شما هنوز تاحدی قابلمشاهده است، اما اغلب
نشاندهنده این است که کاربر درحال ترک فعالیت است و فعالیت بهزودی
وارد وضعیت «متوقفشده» یا «ازسرگرفتهشده» میشود.
فعالیتی در وضعیت «متوقفشده» ممکن است به بهروزرسانی میانای کاربری ادامه دهد اگر کاربر انتظار داشته باشد میانای کاربری بهروز شود. نمونههایی از این فعالیت شامل فعالیتی است که صفحه نقشه ناوبری یا پخشکننده رسانه درحال پخش را نشان میدهد. حتی اگر چنین فعالیتهایی فوکوس را ازدست بدهند، کاربر انتظار دارد میانای کاربر آنها همچنان بهروز شود.
نباید از onPause برای ذخیره دادههای کاربر یا برنامه، برقراری تماسهای شبکه، یا اجرای تراکنشهای پایگاه داده استفاده کنید. برای اطلاعات درباره ذخیره کردن
دادهها، به ذخیره و بازیابی کردن وضعیت میانای کاربری گذرا مراجعه کنید.
وقتی اجرای onPause تمام میشود، فراخوانی برگشتی بعدی یا
onStop است یا onResume، بسته به اینکه بعداز ورود فعالیت به حالت «متوقفشده» چه اتفاقی میافتد.
onStop
وقتی فعالیت دیگر برای کاربر قابلمشاهده نباشد، سیستم onStop را فراخوانی میکند. این ممکن است به این دلیل اتفاق بیفتد که فعالیت درحال ازبین رفتن است، فعالیت جدیدی درحال شروع شدن است، یا فعالیت موجودی درحال ورود به حالت «ازسرگرفتهشده» است و فعالیت متوقفشده را پوشش میدهد. در همه این موارد، فعالیت متوقفشده دیگر بههیچوجه قابلمشاهده نیست.
فراخوانی برگشتی بعدی که سیستم فراخوانی میکند یا onRestart است، اگر
فعالیت برای تعامل با کاربر برگردد، یا onDestroy است اگر این
فعالیت کاملاً خاتمه یابد.
onRestart
سیستم این فراخوانی را زمانی فراخوانی میکند که فعالیتی در وضعیت «متوقفشده» درحال
بازراهاندازی باشد. onRestart وضعیت فعالیت را از زمانی که متوقف شده بود بازیابی میکند.
این فراخوانی برگشتی همیشه با onStart دنبال میشود.
onDestroy
سیستم این فراخوانی را قبلاز نابود شدن فعالیت فراخوانی میکند.
این فراخوانی برگشتی آخرین فراخوانی برگشتی است که فعالیت دریافت میکند. onDestroy معمولاً برای اطمینان از اینکه همه منابع فعالیت هنگام ازبین رفتن فعالیت یا فرایند حاوی آن آزاد میشوند پیادهسازی میشود.
این بخش فقط مقدمهای بر این موضوع ارائه میدهد. برای اطلاعات دقیقتر درباره چرخه حیات فعالیت و فراخوانهای برگشتی آن، به چرخه حیات فعالیت مراجعه کنید.