صفحه «موارد اخیر»

صفحه «موارد اخیر» که صفحه «نمای کلی»، فهرست تکالیف اخیر، یا صفحه برنامه‌های اخیر نیز نامیده می‌شود، یک واسط کاربر در سطح سیستم است که فعالیت‌ها و تکالیف اخیراً دردسترس قرارگرفته را فهرست می‌کند. کاربر می‌تواند در فهرست پیمایش کند، تکلیفی را برای ازسر گرفتن انتخاب کند، یا تکلیفی را با تند کشیدن از فهرست بردارد.

صفحه «برنامه‌های اخیر» از مدل سندمحور استفاده می‌کند که در Android 5.0 (سطح API‏ ۲۱) معرفی شده است. در این مدل، چند نمونه از یک فعالیت که حاوی اسناد مختلف است می‌تواند به‌عنوان تکلیف در صفحه «برنامه‌های اخیر» نشان داده شود. برای مثال، Google Drive ممکن است برای هریک از چند سند Google یک تکلیف داشته باشد. هر سند به‌عنوان تکلیفی در صفحه «موارد اخیر» نشان داده می‌شود:

صفحه «موارد اخیر» دو سند Google Drive را نشان می‌دهد که هرکدام به‌عنوان یک تکلیف جداگانه نمایش داده شده‌اند.

نمونه رایج دیگر زمانی است که کاربر از مرورگر خود استفاده می‌کند و روی هم‌رسانی > Gmail تک‌ضرب می‌زند. صفحه نوشتن برنامه Gmail ظاهر می‌شود. با تک‌ضرب زدن روی دکمه «موارد اخیر» در آن زمان، Chrome و Gmail به‌عنوان کارهای جداگانه درحال اجرا نشان داده می‌شوند:

صفحه «موارد اخیر» که Chrome و Gmail را درحال اجرا به‌عنوان تکالیف جداگانه نشان می‌دهد.

معمولاً به سیستم اجازه می‌دهید نحوه نمایش تکالیف و فعالیت‌هایتان را در صفحه «موارد اخیر» تعریف کند. نیازی نیست این رفتار را اصلاح کنید. بااین‌حال، برنامه‌تان می‌تواند تعیین کند که فعالیت‌ها چگونه و چه زمانی در صفحه «موارد اخیر» نشان داده شوند.

کلاس ActivityManager.AppTask به شما امکان می‌دهد تکالیف را مدیریت کنید، و پرچم‌های فعالیت کلاس Intent به شما امکان می‌دهد مشخص کنید چه زمانی فعالیتی به صفحه «موارد اخیر» اضافه یا از آن برداشته شود. همچنین، مشخصه‌های <activity> به شما امکان می‌دهد رفتار را در مانیفست تنظیم کنید.

افزودن تکالیف به صفحه «موارد اخیر»

استفاده از پرچم‌های کلاس Intent برای افزودن تکلیف، کنترل بیشتری بر زمان و نحوه باز شدن یا باز شدن مجدد سند در صفحه «موارد اخیر» به شما می‌دهد. وقتی‌که از مشخصه‌های <activity> استفاده می‌کنید، می‌توانید انتخاب کنید که سند همیشه در تکلیف جدیدی باز شود یا از تکلیف موجودی برای سند استفاده شود.

استفاده از پرچم «قصد» برای افزودن تکلیف

وقتی سند جدیدی برای فعالیتتان ایجاد می‌کنید، روش startActivity() را فراخوانی می‌کنید و قصدی را که فعالیت را راه‌اندازی می‌کند به آن منتقل می‌کنید. برای درج وقفه منطقی به‌گونه‌ای که سیستم با فعالیت شما به‌عنوان تکلیف جدیدی در صفحه «موارد اخیر» رفتار کند، پرچم FLAG_ACTIVITY_NEW_DOCUMENT را در روش addFlags() از Intent که فعالیت را راه‌اندازی می‌کند ارسال کنید.

اگر پرچم FLAG_ACTIVITY_MULTIPLE_TASK را هنگام ایجاد سند جدید تنظیم کنید، سیستم همیشه تکلیف جدیدی با فعالیت هدف به‌عنوان ریشه ایجاد می‌کند. این تنظیم اجازه می‌دهد یک سند در بیش‌از یک تکلیف باز شود. کد زیر نشان می‌دهد که چگونه فعالیت اصلی این کار را انجام می‌دهد و فعالیت جدید را از composable شما شروع می‌کند:

private fun newDocumentIntent(context: Context): Intent =
    Intent(context, NewDocumentActivity::class.java).apply {
        addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT or Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)
        putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, documentCounter++)
    }

@Composable
fun CreateDocumentButton() {
    val context = LocalContext.current
    Button(
        onClick = {
            val intent = newDocumentIntent(context)
            // Add FLAG_ACTIVITY_MULTIPLE_TASK if needed based on state
            context.startActivity(intent)
        }
    ) {
        Text("Create New Document")
    }
}

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

اگر سیستم تکلیفی را پیدا کند که قصد آن با نام مؤلفه قصد و داده‌های قصد مطابقت داشته باشد، آن تکلیف را به جلو می‌آورد و قصد جدید را به onNewIntent() منتقل می‌کند. فعالیت جدید قصد را دریافت می‌کند و سند جدیدی در صفحه «موارد اخیر» ایجاد می‌کند، همان‌طور که در مثال زیر نشان داده شده است:

class DocumentCentricActivity : ComponentActivity() {
    private var documentState by mutableStateOf(
        DocumentState(
            count = 0,
            textResId = R.string.hello_new_document_counter
        )
    )

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val initialCount = intent.getIntExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, 0)

        documentState = documentState.copy(count = initialCount)

        setContent {
            MaterialTheme {
                DocumentScreen(
                    count = documentState.count,
                    textResId = documentState.textResId
                )
            }
        }
    }

    override fun onNewIntent(newIntent: Intent) {
        super.onNewIntent(newIntent)
        // If FLAG_ACTIVITY_MULTIPLE_TASK has not been used, this Activity is reused.
        documentState = documentState.copy(
            textResId = R.string.reusing_document_counter
        )
    }

    data class DocumentState(val count: Int, @StringRes val textResId: Int)

    companion object {
        const val KEY_EXTRA_NEW_DOCUMENT_COUNTER = "KEY_EXTRA_NEW_DOCUMENT_COUNTER"
    }
}

@Composable
fun DocumentScreen(count: Int, @StringRes textResId: Int) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.Center
    ) {
        // UI reacts to whichever string resource ID was passed down
        Text(text = stringResource(id = textResId))
        Spacer(modifier = Modifier.height(8.dp))
        Text(text = "Counter: $count")
    }
}

In the preceding code, the Activity handles the OS-level routing (onCreate and onNewIntent), while the @Composable function is responsible only for rendering the UI based on the provided state.

استفاده از مشخصه فعالیت برای افزودن تکلیف

فعالیت همچنین می‌تواند در مانیفست خود مشخص کند که همیشه بااستفاده از مشخصه android:documentLaunchMode در تکلیف جدیدی راه‌اندازی می‌شود<activity>. این مشخصه چهار مقدار دارد که وقتی کاربر سندی را با برنامه باز می‌کند، تأثیرات زیر را ایجاد می‌کند:

intoExisting
این فعالیت از تکلیف موجود برای سند دوباره استفاده می‌کند. این کار مانند تنظیم پرچم FLAG_ACTIVITY_NEW_DOCUMENT بدون تنظیم پرچم FLAG_ACTIVITY_MULTIPLE_TASK است، همان‌طور که در بخش استفاده از پرچم Intent برای افزودن تکلیف شرح داده شده است.
always
این فعالیت تکلیف جدیدی برای سند ایجاد می‌کند، حتی اگر سند ازقبل باز شده باشد. استفاده از این مقدار مانند تنظیم هر دو پرچم FLAG_ACTIVITY_NEW_DOCUMENT و FLAG_ACTIVITY_MULTIPLE_TASK است.
none
این فعالیت تکلیف جدیدی برای سند ایجاد نمی‌کند. صفحه «موارد اخیر» با فعالیت به‌صورت پیش‌فرض رفتار می‌کند. این حالت یک تکلیف را برای برنامه نمایش می‌دهد که از هر فعالیتی که کاربر آخرین بار فراخوانده است ازسر گرفته می‌شود.
never
این فعالیت تکلیف جدیدی برای سند ایجاد نمی‌کند. تنظیم این مقدار رفتار پرچم‌های FLAG_ACTIVITY_NEW_DOCUMENT و FLAG_ACTIVITY_MULTIPLE_TASK را لغو می‌کند. اگر هرکدام از این‌ها در هدف تنظیم شده باشد و صفحه «موارد اخیر» یک تکلیف را برای برنامه نمایش دهد، از هر فعالیتی که کاربر آخرین‌بار فراخوانده است ازسر گرفته می‌شود.

برداشتن تکالیف

به‌طور پیش‌فرض، وقتی فعالیت تکلیف سند تمام می‌شود، تکلیف به‌طور خودکار از صفحه «موارد اخیر» خارج می‌شود. می‌توانید این رفتار را با کلاس ActivityManager.AppTask ، با پرچم Intent، یا با مشخصه <activity> لغو کنید.

همیشه می‌توانید با تنظیم کردن مشخصه <activity> android:excludeFromRecents روی true، تکلیفی را به‌طور کامل از صفحه «موارد اخیر» مستثنی کنید.

با تنظیم کردن مشخصه <activity> android:maxRecents روی مقدار عدد صحیح، می‌توانید حداکثر تعداد تکالیفی را که برنامه‌تان می‌تواند در صفحه «موارد اخیر» داشته باشد تنظیم کنید. وقتی به حداکثر تعداد تکلیف برسید، تکلیفی که از آخرین استفاده آن بیشتر از بقیه گذشته است از صفحه «موارد اخیر» ناپدید می‌شود. مقدار پیش‌فرض ۱۶ است، و حداکثر مقدار ۵۰ است (۲۵ در دستگاه‌های با حافظه کم). مقادیر کمتر از ۱ معتبر نیست.

استفاده از کلاس AppTask برای برداشتن تکالیف

در فعالیتی که تکلیف جدیدی در صفحه «موارد اخیر» ایجاد می‌کند، می‌توانید با فراخوانی روش finishAndRemoveTask() مشخص کنید که تکلیف چه زمانی برداشته شود و همه فعالیت‌های مرتبط با آن به پایان برسد:

@Composable
fun RemoveTaskButton() {
    val context = LocalContext.current
    Button(
        onClick = {
            // It is good practice to remove a document from the overview stack if not needed anymore.
            (context as? Activity)?.finishAndRemoveTask()
        }
    ) {
        Text("Remove from Recents")
    }
}

حفظ کردن تکالیف تمام‌شده

اگر می‌خواهید تکلیفی را در صفحه «موارد اخیر» نگه دارید، حتی اگر فعالیت آن به‌پایان رسیده باشد، پرچم FLAG_ACTIVITY_RETAIN_IN_RECENTS را در روش addFlags() قصدی که فعالیت را راه‌اندازی می‌کند ارسال کنید.

private fun newDocumentIntent() =
        Intent(this, NewDocumentActivity::class.java).apply {
            addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT or
                    android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)
            putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, getAndIncrement())
        }

برای دستیابی به همان اثر، مشخصه <activity> android:autoRemoveFromRecents را روی false تنظیم کنید. مقدار پیش‌فرض برای فعالیت‌های سند true و برای فعالیت‌های عادی false است. استفاده از این مشخصه پرچم FLAG_ACTIVITY_RETAIN_IN_RECENTS را لغو می‌کند.

فعال کردن هم‌رسانی نشانی وب موارد اخیر (فقط Pixel)

در دستگاه‌های Pixel دارای Android نسخه ۱۲ یا بالاتر، کاربران می‌توانند پیوندهای محتوای وب اخیراً مشاهده‌شده را مستقیماً از صفحه «موارد اخیر» هم‌رسانی کنند. پس‌از بازدید از محتوا در برنامه، کاربر می‌تواند تند به صفحه «موارد اخیر» بکشد و برنامه‌ای را که محتوا را در آن مشاهده کرده است پیدا کند، سپس روی دکمه پیوند تک‌ضرب بزنید تا نشانی وب را کپی یا هم‌رسانی کند.

صفحه «موارد اخیر» با پیوندی برای هم‌رسانی محتوای وب اخیراً مشاهده‌شده.

هر برنامه‌ای می‌تواند با ارائه یک میانای کاربری وب و لغو کردن onProvideAssistContent()، پیونددهی «موارد اخیر» را برای کاربران فعال کند، همان‌طور که در مثال زیر نشان داده شده است:

class MainActivity : ComponentActivity() {

    // Track the current URL as state so the UI can update it during navigation
    private var currentWebUri by mutableStateOf("https://example.com/home")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            AppTheme {
                // Pass a lambda to your Compose UI so it can update the URL state
                // as the user navigates through your app.
                MainScreen(
                    onPageChanged = { newUrl -> currentWebUri = newUrl }
                )
            }
        }
    }

    override fun onProvideAssistContent(outContent: AssistContent) {
        super.onProvideAssistContent(outContent)

        // The system calls this when the user enters the Recents screen.
        // Provide the active URI tracked by the Compose state.
        outContent.webUri = Uri.parse(currentWebUri)
    }
}