적절한 뒤로 탐색 기능 제공

뒤로 탐색 기능은 사용자가 이전에 방문한 화면 기록을 통해 뒤로 이동하는 기능입니다. 모든 Android 기기는 이러한 탐색 기능을 위해 뒤로 버튼을 제공하므로 앱 UI에는 뒤로 버튼을 추가하지 말아야 합니다.

사용자가 애플리케이션을 사용하는 동안 거의 모든 상황에서 시스템이 활동 내역을 스태킹합니다. 덕분에 사용자가 뒤로 버튼을 누르면 원하는 대로 뒤로 이동할 수 있는 것입니다. 하지만 최상의 사용자 환경을 제공하기 위해 앱에서 수동으로 뒤로 동작을 지정해야 하는 경우가 있습니다.

뒤로 및 위로 탐색 기능 디자인, 작업 및 백 스택, Android 디자인: 탐색도 참조하세요.

뒤로 동작을 수동으로 지정해야 하는 탐색 패턴의 예로는 다음이 있습니다.

이러한 상황에서 뒤로 탐색 기능을 제대로 구현하는 방법을 다음 섹션에서 설명합니다.

딥 링크를 위한 새로운 백 스택 합성

일반적으로 시스템은 사용자가 한 활동에서 다음 활동으로 이동할 때 백 스택을 점진적으로 구축합니다. 그러나 사용자가 자체 작업에서 활동을 시작하는 딥 링크로 앱을 여는 경우 이 활동은 백 스택이 없이 새로운 작업으로 실행되는 것이므로 새로운 백 스택을 합성해야 합니다.

예를 들어 알림을 통해 사용자가 앱 계층 구조의 깊은 곳에 있는 활동을 시작할 경우, 작업의 백 스택에 활동을 추가하여 뒤로 버튼을 누르면 앱을 나가지 않고 상위 계층으로 가도록 해야 합니다. 이 패턴은 탐색 디자인 가이드에서 더 자세히 설명합니다.

매니페스트에 상위 활동 지정

Android 4.1(API 레벨 16)부터 android:parentActivityName 속성을 <activity> 요소에 지정하여 각 활동의 논리적 상위 항목을 선언할 수 있습니다. 이를 통해 시스템은 논리적으로 적합한 뒤로 또는 위로 탐색 경로를 결정할 수 있기 때문에 탐색이 쉬워집니다.

앱이 Android 4.0 이하를 지원하는 경우 앱에 지원 라이브러리를 포함하고 <meta-data> 요소를 <activity> 안에 추가합니다. 그런 다음 상위 활동을 android.support.PARENT_ACTIVITY의 값으로 지정하여 android:parentActivityName 속성과 일치하게 합니다.

예:

<application ... >
    ...
    <!-- The main/home activity (it has no parent activity) -->
    <activity
        android:name="com.example.myfirstapp.MainActivity" ...>
        ...
    </activity>
    <!-- A child of the main activity -->
    <activity
        android:name="com.example.myfirstapp.DisplayMessageActivity"
        android:label="@string/title_activity_display_message"
        android:parentActivityName="com.example.myfirstapp.MainActivity" >
        <!-- The meta-data element is needed for versions lower than 4.1 -->
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.myfirstapp.MainActivity" />
    </activity>
</application>

상위 활동을 이렇게 선언하면 NavUtils API를 사용하여 각 활동에 적합한 상위 활동을 식별함으로써 새로운 백 스택을 합성할 수 있습니다.

활동을 시작할 때 백 스택 생성

사용자가 앱으로 들어가는 이벤트가 발생할 때 백 스택에 활동 추가가 시작됩니다. 즉, startActivity()를 호출하는 대신 TaskStackBuilder API를 사용하여 새로운 백 스택에 있어야 할 각 활동을 정의합니다. 그런 다음 startActivities()를 호출하여 타겟 활동을 시작하거나 getPendingIntent()를 호출하여 적절한 PendingIntent를 생성합니다.

예를 들어 알림을 통해 사용자가 앱 계층 구조의 깊은 곳에 있는 활동을 시작할 경우, 이 코드를 사용해 PendingIntent를 만들면 이 개체가 활동을 시작하고 새로운 백 스택을 타겟 작업에 삽입합니다.

Kotlin

val detailsIntent = Intent(this, DetailsActivity::class.java)

val pendingIntent: PendingIntent? = TaskStackBuilder.create(this)
        // add all of DetailsActivity's parents to the stack,
        // followed by DetailsActivity itself
        .addNextIntentWithParentStack(detailsIntent)
        .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)

val builder = NotificationCompat.Builder(this)
        .setContentIntent(pendingIntent)
...

자바

// Intent for the activity to open when user selects the notification
Intent detailsIntent = new Intent(this, DetailsActivity.class);

// Use TaskStackBuilder to build the back stack and get the PendingIntent
PendingIntent pendingIntent =
        TaskStackBuilder.create(this)
                        // add all of DetailsActivity's parents to the stack,
                        // followed by DetailsActivity itself
                        .addNextIntentWithParentStack(detailsIntent)
                        .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentIntent(pendingIntent);
...

이렇게 만들어진 PendingIntent는 (detailsIntent에서 정의한) 시작해야 할 활동뿐 아니라 작업에 삽입되어야 할 백 스택(detailsIntent에서 정의한 DetailsActivity의 모든 상위 항목)도 지정합니다. 따라서 DetailsActivity가 시작되었을 때 뒤로를 누르면 각 DetailsActivity 클래스의 상위 활동을 따라 뒤로 이동하게 됩니다.

참고: addNextIntentWithParentStack() 메서드가 작동하려면 매니페스트 파일에서 각 활동의 논리적 상위 항목을 선언해야 합니다. 위 설명과 같이 android:parentActivityName 속성과 관련 <meta-data> 요소를 사용하면 됩니다.

프래그먼트에서 뒤로 탐색 구현

앱에서 프래그먼트를 사용할 때 개별 FragmentTransaction 개체가 백 스택에 추가되어야 하는 컨텍스트 변경을 나타낼 수 있습니다. 예를 들어 프래그먼트를 교환함으로써 핸드셋에서 마스터/세부 흐름을 구현하는 경우, 세부 화면에서 뒤로 버튼을 누르면 사용자가 마스터 화면으로 돌아가도록 해야 합니다. 이렇게 하려면 트랜잭션을 커밋하기 전에 addToBackStack()을 호출합니다.

Kotlin

// Works with either the framework FragmentManager or the
// support package FragmentManager (supportFragmentManager).
supportFragmentManager.beginTransaction()
        .add(detailFragment, "detail")
        // Add this transaction to the back stack
        .addToBackStack(null)
        .commit()

자바

// Works with either the framework FragmentManager or the
// support package FragmentManager (getSupportFragmentManager).
getSupportFragmentManager().beginTransaction()
                           .add(detailFragment, "detail")
                           // Add this transaction to the back stack
                           .addToBackStack(null)
                           .commit();

백 스택에 FragmentTransaction 개체가 있고 사용자가 뒤로 버튼을 누를 경우 FragmentManager가 백 스택에서 가장 최근의 트랜잭션을 죽이고 반대 동작(트랜잭션이 프래그먼트를 추가한 경우 관련 프래그먼트 삭제 등)을 실행합니다.

참고: 트랜잭션이 수평 탐색일 때(탭 전환 등) 또는 콘텐츠 모양을 수정할 때(필터 변경 등)는 트랜잭션을 백 스택에 추가하지 말아야 합니다. 언제 뒤로 탐색 기능이 적절한지 자세히 알아보려면 탐색 디자인 가이드를 참조하세요.

애플리케이션이 프래그먼트의 최신 상태를 반영하기 위해 작업 표시줄과 같은 다른 사용자 인터페이스 요소를 업데이트하는 경우, 트랜잭션 커밋 시 UI를 잊지 말고 업데이트하세요. 트랜잭션을 커밋할 때뿐만 아니라 백 스택이 변경된 후에도 사용자 인터페이스를 업데이트해야 합니다. FragmentTransaction이 언제 되돌려지는 알려면 FragmentManager.OnBackStackChangedListener를 설정하면 됩니다.

Kotlin

supportFragmentManager.addOnBackStackChangedListener {
    // Update your UI here.
}

자바

getSupportFragmentManager().addOnBackStackChangedListener(
        new FragmentManager.OnBackStackChangedListener() {
            public void onBackStackChanged() {
                // Update your UI here.
            }
        });

WebView를 위한 뒤로 탐색 구현

애플리케이션 일부가 WebView에 포함된 경우 뒤로 탐색 기능에서 방문 기록을 따라가는 것이 좋을 수 있습니다.0 기록 상태가 있는 경우 onBackPressed()WebView에 관한 프록시를 재정의하여 뒤로 탐색 기능을 구현할 수 있습니다.

Kotlin

override fun onBackPressed() {
    if (mWebView.canGoBack()) {
        mWebView.goBack()
    } else {
        // Otherwise defer to system default behavior.
        super.onBackPressed()
    }
}

자바

@Override
public void onBackPressed() {
    if (mWebView.canGoBack()) {
        mWebView.goBack();
        return;
    }

    // Otherwise defer to system default behavior.
    super.onBackPressed();
}

기록의 용량이 커질 수 있는 매우 동적인 웹페이지의 경우 이 메커니즘을 사용할 때 주의해야 합니다. 문서 해시가 자주 변경되는 페이지처럼 대용량 기록이 생성되는 페이지는 사용자가 활동에서 벗어나기 어려울 수 있습니다.

WebView 사용에 관한 자세한 내용은 WebView에서 웹 앱 만들기를 참조하세요.