최근 화면

최근 화면(개요 화면, 최근 작업 목록 또는 최근 앱 화면이라고도 함)은 최근에 액세스한 활동작업을 나열하는 시스템 수준 UI입니다. 사용자는 목록을 탐색하고, 다시 시작할 작업을 선택하거나, 스와이프하여 목록에서 작업을 삭제할 수 있습니다.

최근 화면은 Android 5.0 (API 수준 21)에서 도입된 문서 중심 모델을 사용합니다. 이 모델에서는 다양한 문서가 포함된 동일한 Activity의 여러 인스턴스를 최근 화면에 태스크로 표시할 수 있습니다. 예를 들어 Google 드라이브에는 여러 Google 문서 각각에 관한 작업이 있을 수 있습니다. 각 문서는 최근 화면에 작업으로 표시됩니다.

2개의 Google Drive 문서를 보여주는 최근 화면 - 각기 별도의 작업으로 표시됩니다.

또 다른 일반적인 예는 사용자가 브라우저를 사용하고 공유 > Gmail 을 탭하는 경우입니다. Gmail 앱의 편지쓰기 화면이 나타납니다. 이때 최근 버튼을 탭하면 별도의 작업으로 실행되는 Chrome 및 Gmail이 표시됩니다.

별도의 작업으로 실행되는 Chrome 및 Gmail을 보여주는 최근 화면.

일반적으로 시스템에서 작업 및 활동이 최근 화면에 표시되는 방식을 정의하도록 허용합니다. 이 동작을 직접 수정할 필요가 없습니다. 그러나 앱은 활동이 최근 화면에 표시되는 방식 및 시기를 결정할 수 있습니다.

ActivityManager.AppTask 클래스를 사용하면 작업을 관리할 수 있으며 Intent 클래스의 활동 플래그를 사용하면 활동이 최근 화면에서 추가 또는 삭제되는 시기를 지정할 수 있습니다. 또한 <activity> 속성을 통해 manifest의 동작도 설정할 수 있습니다.

최근 화면에 작업 추가

Intent 클래스의 플래그를 사용하여 태스크를 추가하면 최근 화면에서 문서를 열거나 다시 여는 시기 및 방식을 더 세부적으로 제어할 수 있습니다. <activity> 속성을 사용하면 항상 새 작업에서 문서를 열지 아니면 문서에 기존 작업을 다시 사용할지 선택할 수 있습니다.

인텐트 플래그를 사용하여 작업 추가

활동의 새 문서를 만들 때 startActivity() 메서드를 호출하여 활동을 실행하는 인텐트를 이 메서드에 전달합니다. 시스템이 최근 화면에서 활동을 새 태스크로 처리하도록 논리적 중단을 삽입하려면 활동을 실행하는 IntentaddFlags() 메서드에 있는 FLAG_ACTIVITY_NEW_DOCUMENT 플래그를 전달해야 합니다.

새 문서를 만들 때 FLAG_ACTIVITY_MULTIPLE_TASK 플래그를 설정하면 시스템은 항상 타겟 활동을 루트로 사용하여 새 작업을 생성합니다. 이 설정을 사용하면 동일한 문서를 둘 이상의 작업에서 열 수 있습니다. 다음 코드는 기본 활동이 이를 이행하고 컴포저블에서 새 활동을 시작하는 방법을 보여줍니다.

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")
    }
}

위 코드에서 활동은 OS 수준 라우팅 (onCreateonNewIntent)을 처리하는 반면 @Composable 함수는 제공된 상태를 기반으로 UI를 렌더링하는 역할만 합니다.

활동 속성을 사용하여 작업 추가

또한 활동은 manifest에서 항상 새 작업으로 실행되도록 <activity> 속성 android:documentLaunchMode를 사용하여 지정할 수 있습니다. 이 속성에는 4개의 값이 있으며, 사용자가 애플리케이션으로 문서를 열 때 다음과 같은 효과를 냅니다.

intoExisting
활동이 문서에 기존 작업을 다시 사용합니다. 이는 FLAG_ACTIVITY_NEW_DOCUMENT 플래그를 설정하지 않고 FLAG_ACTIVITY_MULTIPLE_TASK 플래그를 설정하는 것과 동일합니다. 이는 인텐트 플래그를 사용하여 작업 추가 섹션에 설명되어 있습니다.
always
문서가 이미 열려 있더라도 활동이 문서의 새 작업을 생성합니다. 이 값을 사용하는 것은 FLAG_ACTIVITY_NEW_DOCUMENTFLAG_ACTIVITY_MULTIPLE_TASK 플래그를 모두 설정하는 것과 동일합니다.
none
활동이 문서의 새 작업을 생성하지 않습니다. 최근 화면은 활동을 기본적인 방식으로 처리합니다. 앱의 단일 작업을 표시하며 이때 사용자가 마지막으로 호출한 활동이 무엇이든 관계없이 그 활동부터 다시 시작합니다.
never
활동이 문서의 새 작업을 생성하지 않습니다. 이 값을 설정하면 FLAG_ACTIVITY_NEW_DOCUMENTFLAG_ACTIVITY_MULTIPLE_TASK 플래그의 동작을 재정의합니다. 이들 중 하나가 인텐트에 설정되어 있고 최근 화면이 앱의 단일 작업을 표시하는 경우 사용자가 마지막으로 호출한 Activity부터 다시 시작합니다.

작업 삭제

기본적으로 문서 작업은 활동이 완료될 때 최근 화면에서 자동으로 종료됩니다. ActivityManager.AppTask 클래스, Intent 플래그 또는 <activity> 속성을 사용하여 이 동작을 재정의할 수 있습니다.

속성 android:excludeFromRecentstrue로 설정하여 언제든지 최근 화면에서 작업을 완전히 제외할 수 있습니다.<activity>

앱이 최근 화면에 포함할 수 있는 최대 태스크 수를 설정하려면 <activity> 속성을 android:maxRecents 정수 값으로 설정하면 됩니다. 최대 작업 수에 도달하면 가장 오래전에 사용된 작업이 최근 화면에서 사라집니다. 기본값은 16이며 최댓값은 50 (메모리가 적은 기기에서는 25)입니다. 1 미만의 값은 유효하지 않습니다.

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")
    }
}

완료된 작업 유지

최근 화면에서 태스크를 유지하려면 활동이 완료되었더라도 활동을 실행하는 인텐트의 addFlags() 메서드에 있는 FLAG_ACTIVITY_RETAIN_IN_RECENTS 플래그를 전달해야 합니다.

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:autoRemoveFromRecentsfalse로 설정합니다. 기본값은 문서 활동에서는 true이며 일반 활동에서는 false입니다. 이 속성을 사용하면 FLAG_ACTIVITY_RETAIN_IN_RECENTS 플래그가 재정의됩니다.

최근 URL 공유 사용 설정 (Pixel만 해당)

Android 12 이상을 실행하는 Pixel 기기에서 사용자는 최근 화면에서 바로 최근 본 웹 콘텐츠 링크를 공유할 수 있습니다. 앱의 콘텐츠를 방문한 후 사용자는 최근 화면으로 스와이프하여 콘텐츠를 본 앱을 찾은 후 링크 버튼을 탭하여 URL을 복사하거나 공유할 수 있습니다.

최근 본 웹 콘텐츠를 공유하는 링크가 있는 최근 화면.

모든 앱은 다음 예와 같이 웹 UI를 제공하고 재정의하여 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)
    }
}