최근 화면(개요 화면, 최근 작업 목록 또는 최근 앱 화면이라고도 함)은 최근에 액세스한 활동 및 작업을 나열하는 시스템 수준 UI입니다. 사용자는 목록을 탐색하고, 다시 시작할 작업을 선택하거나, 스와이프하여 목록에서 작업을 삭제할 수 있습니다.
최근 화면은 Android 5.0 (API 수준 21)에서 도입된 문서 중심 모델을 사용합니다. 이 모델에서는 다양한 문서가 포함된 동일한 Activity의 여러 인스턴스를 최근 화면에 태스크로 표시할 수 있습니다. 예를 들어 Google 드라이브에는 여러 Google 문서 각각에 관한 작업이 있을 수 있습니다. 각 문서는 최근 화면에 작업으로 표시됩니다.
또 다른 일반적인 예는 사용자가 브라우저를 사용하고 공유 > Gmail 을 탭하는 경우입니다. Gmail 앱의 편지쓰기 화면이 나타납니다. 이때 최근 버튼을 탭하면 별도의 작업으로 실행되는 Chrome 및 Gmail이 표시됩니다.
일반적으로 시스템에서 작업 및 활동이 최근 화면에 표시되는 방식을 정의하도록 허용합니다. 이 동작을 직접 수정할 필요가 없습니다. 그러나 앱은 활동이 최근 화면에 표시되는 방식 및 시기를 결정할 수 있습니다.
ActivityManager.AppTask 클래스를 사용하면 작업을 관리할 수 있으며 Intent 클래스의 활동 플래그를 사용하면 활동이 최근 화면에서 추가 또는 삭제되는 시기를 지정할 수 있습니다. 또한
<activity> 속성을 통해
manifest의 동작도 설정할 수 있습니다.
최근 화면에 작업 추가
Intent 클래스의 플래그를 사용하여
태스크를 추가하면 최근 화면에서 문서를 열거나
다시 여는 시기 및 방식을 더 세부적으로 제어할 수 있습니다.
<activity> 속성을 사용하면
항상 새 작업에서 문서를 열지 아니면 문서에 기존
작업을 다시 사용할지 선택할 수 있습니다.
인텐트 플래그를 사용하여 작업 추가
활동의 새 문서를 만들 때
startActivity()
메서드를 호출하여 활동을 실행하는 인텐트를 이 메서드에 전달합니다. 시스템이 최근 화면에서 활동을 새 태스크로 처리하도록 논리적 중단을 삽입하려면 활동을 실행하는 Intent의 addFlags() 메서드에 있는 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 수준 라우팅 (onCreate 및 onNewIntent)을 처리하는 반면 @Composable 함수는 제공된 상태를 기반으로 UI를 렌더링하는 역할만 합니다.
활동 속성을 사용하여 작업 추가
또한 활동은 manifest에서 항상 새
작업으로 실행되도록 <activity>
속성 android:documentLaunchMode를 사용하여 지정할 수 있습니다.
이 속성에는 4개의 값이 있으며, 사용자가 애플리케이션으로 문서를 열 때 다음과 같은 효과를 냅니다.
intoExisting- 활동이 문서에 기존 작업을 다시 사용합니다. 이는
FLAG_ACTIVITY_NEW_DOCUMENT플래그를 설정하지 않고FLAG_ACTIVITY_MULTIPLE_TASK플래그를 설정하는 것과 동일합니다. 이는 인텐트 플래그를 사용하여 작업 추가 섹션에 설명되어 있습니다. always- 문서가 이미 열려 있더라도 활동이 문서의 새 작업을 생성합니다. 이 값을 사용하는 것은
FLAG_ACTIVITY_NEW_DOCUMENT및FLAG_ACTIVITY_MULTIPLE_TASK플래그를 모두 설정하는 것과 동일합니다. none- 활동이 문서의 새 작업을 생성하지 않습니다. 최근 화면은 활동을 기본적인 방식으로 처리합니다. 앱의 단일 작업을 표시하며 이때 사용자가 마지막으로 호출한 활동이 무엇이든 관계없이 그 활동부터 다시 시작합니다.
never- 활동이 문서의 새 작업을 생성하지 않습니다. 이 값을 설정하면
FLAG_ACTIVITY_NEW_DOCUMENT및FLAG_ACTIVITY_MULTIPLE_TASK플래그의 동작을 재정의합니다. 이들 중 하나가 인텐트에 설정되어 있고 최근 화면이 앱의 단일 작업을 표시하는 경우 사용자가 마지막으로 호출한 Activity부터 다시 시작합니다.
작업 삭제
기본적으로 문서 작업은 활동이 완료될 때 최근 화면에서 자동으로 종료됩니다.
ActivityManager.AppTask
클래스, Intent 플래그 또는
<activity> 속성을 사용하여 이 동작을 재정의할 수 있습니다.
속성
android:excludeFromRecents
을 true로 설정하여 언제든지 최근 화면에서 작업을 완전히 제외할 수 있습니다.<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:autoRemoveFromRecents
을 false로 설정합니다. 기본값은 문서 활동에서는 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) } }