Android

액티비티 (8) : 최근 사용한 앱 화면

까망사과 2022. 5. 13. 22:00

최근 사용한 앱 화면(이하 최근 앱 화면)은 가장 최근에 액세스한 액티비티와 태스크가 나열된 시스템 수준 UI이다.

이 목록을 탐색해서 태스크를 재개하거나 스와이프로 제거할 수 있다.

 

최근 앱 화면은 문서 중심 모델(안드로이드 5.0에 추가됨)을 사용한다. 이 모델은 같은 액티비티의 여러 개의 인스턴스(서로 다른 내용을 포함)가 최근 앱 화면에 태스크로 표시되도록 한다. 예를 들어 구글 드라이브는 여러 문서에 대해 각각 태스크를 가질 수 있다. 각 문서가 최근 앱 화면에 태스크로 표시된다.

 

다른 일반적인 예로 브라우저를 사용할 때 공유 > Gmail을 탭하면 Gmail 앱의 메일 작성 화면이 표시된다. 이때 최근 앱 버튼을 탭하면 브라우저와 Gmail 앱의 태스크가 분리되어 있다는 것을 알 수 있다.

 

일반적으로 태스크와 액티비티가 최근 앱 화면에 표시되는 방식을 시스템이 정의하도록 해야 하며 이 동작을 수정할 필요는 없다. 하지만 액티비티가 최근 앱 화면에 표시되는 방식과 시기를 앱이 결정할 수 있다. ActivityManager.AppTask 클래스를 사용하면 태스크를 관리할 수 있으며, Intent 클래스의 액티비티 플래그를 사용하면 액티비티가 최근 앱 화면에 추가되거나 제거되는 시기를 지정할 수 있다. 또한 <activity> 요소의 속성을 사용하면 매니페스트의 동작을 설정할 수 있다.

 

최근 사용한 앱 화면에 태스크 추가

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

 

인텐트 플래그를 사용하여 태스크 추가

액티비티의 새 문서를 생성할 때 startActivity()를 호출하고 거기에 액티비티를 실행하는 인텐트를 전달한다.

시스템이 최근 앱 화면에서 액티비티를 새 태스크로 취급하도록 논리적 중단을 추가하려면 액티비티를 실행하는 인텐트의 addFlags()FLAG_ACTIVITY_NEW_DOCUMENT 플래그를 전달하면 된다.

 

FLAG_ACTIVITY_NEW_DOCUMENT는 안드로이드 5.0에서 deprecated된 FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET을 대체하는 플래그이다.

 

새 문서를 생성할 때 FLAG_ACTIVITY_MULTIPLE_TASK 플래그를 설정하면 타겟 액티비티는 항상 새 태스크의 루트로 생성된다. 이렇게 설정하면 같은 문서가 여러 태스크에서 열릴 수 있다. 예시는 다음과 같다.

fun createNewDocument(view: View) {
    val newDocumentIntent = newDocumentIntent()
    if (useMultipleTasks) {
        newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
    }
    startActivity(newDocumentIntent)
}

private fun newDocumentIntent(): Intent =
        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, documentCounter++)
        }

 

FLAG_ACTIVITY_NEW_DOCUMENT 플래그로 실행되는 액티비티는 launchMode 속성 값이 "standard"이어야 한다.

 

메인 액티비티가 새 액티비티를 시작하면 시스템은 인텐트와 컴포넌트 이름 및 데이터가 일치하는 기존 태스크를 찾는다. 찾지 못하거나 인텐트가 FLAG_ACTIVITY_MULTIPLE_TASK 플래그를 포함하면 새 액티비티가 새 태스크의 루트로 생성된다. 찾는다면 그 태스크를 앞으로 가져오고 onNewIntent()에 새 인텐트를 전달한다. 다음 예시에서 새 액티비티는 인텐트를 수신하고 최근 앱 화면에 새 문서를 생성한다.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_new_document)
    documentCount = intent
            .getIntExtra(DocumentCentricActivity.KEY_EXTRA_NEW_DOCUMENT_COUNTER, 0)
    documentCounterTextView = findViewById(R.id.hello_new_document_text_view)
    setDocumentCounterText(R.string.hello_new_document_counter)
}

override fun onNewIntent(newIntent: Intent) {
    super.onNewIntent(newIntent)
    /* FLAG_ACTIVITY_MULTIPLE_TASK 플래그가 사용되지 않았다면 이 액티비티는 재사용될 것이다. */
    setDocumentCounterText(R.string.reusing_document_counter)
}

 

액티비티 속성을 사용하여 태스크 추가

액티비티가 항상 새 태스크에서 실행되도록 하려면 매니페스트 파일에서 <activity>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_DOCUMENTFLAG_ACTIVITY_MULTIPLE_TASK 플래그 중 하나가 인텐트에 설정되어 있으면 그 동작을 재정의한다. 최근 앱 화면이 앱의 단일 태스크를 표시하며 이는 사용자가 마지막에 호출한 액티비티가 무엇이든 간에 그 액티비티부터 재개된다.

"none""never" 이외의 값을 사용하려면 액티비티의 launchMode 속성값이 "standard"이어야 한다.

그렇지 않으면 documentLaunchMode 속성값으로 "none"이 사용된다.

 


태스크 제거

기본적으로 문서 태스크는 액티비티가 종료될 때 최근 앱 화면에서 제거된다.

이 동작은 ActivityManager.AppTask, 인텐트 플래그, <activity> 속성을 사용하여 재정의할 수 있다.

 

<activity>excludeFromRecents 속성값을 true로 설정하면 최근 앱 화면에서 태스크를 항상 완전히 제거할 수 있다.

또한 maxRecents 속성에 정수값을 할당하면 최근 앱 화면에서 앱이 포함할 수 있는 태스크의 최대 개수(기본값은 16)를 설정할 수 있다. 최대 태스크 개수에 도달하면 사용한 지 가장 오래된 태스크가 최근 앱 화면에서 제거된다. maxRecents의 최댓값은 50이며(메모리가 적은 디바이스는 25) 1 미만의 값은 유효하지 않다.

 

AppTask를 사용하여 태스크 제거

최근 앱 화면에서 새 태스크를 생성하는 액티비티에서 finishAndRemoveTask()를 호출하면 태스크를 제거하고 관련된 모든 액티비티를 종료하는 시기를 지정할 수 있다.

fun onRemoveFromOverview(view: View) {
    // 더 이상 필요 없는 문서를 오버뷰 스택에서 제거하는 것이 좋다.
    finishAndRemoveTask()
}

 

종료된 태스크 유지

액티비티가 종료되었더라도 최근 앱 화면에서 태스크를 유지하려면 액티비티를 실행하는 인텐트의 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>autoRemoveFromRecents 속성값을 false로 설정해야 한다.

문서 액티비티에 대한 기본값은 true이며 일반 액티비티에 대한 기본값은 false이다.

이 속성을 사용하면 FLAG_ACTIVITY_RETAIN_IN_RECENTS 플래그가 재정의된다.