알림

알림은 애플리케이션의 정상 UI 외부에서 사용자에게 표시할 수 있는 메시지입니다. 시스템에 알림을 실행하라고 명령하면 처음에 알림 영역에서 아이콘으로 나타납니다. 알림 세부 정보를 보려면 사용자는 알림 창을 열어야 합니다. 알림 영역과 알림 창은 사용자가 언제든 볼 수 있는, 시스템이 제어하는 영역입니다.

그림 1. 알림 영역에 있는 알림입니다.

그림 2. 알림 창에 있는 알림입니다.

참고: 따로 언급된 부분을 제외하고 이 가이드는 버전 4 지원 라이브러리NotificationCompat.Builder 클래스를 참조합니다. 클래스 Notification.Builder는 Android 3.0(API 레벨 11)에 추가되었습니다.

디자인 고려 사항

Android 사용자 인터페이스의 중요한 부분인 알림에는 자체적인 디자인 지침이 있습니다. Android 5.0(API 레벨 21)부터 도입된 머티어리얼 디자인 변경 사항은 특히 중요하며, 자세한 정보를 보려면 재료 디자인 교육을 검토해야 합니다. 알림과 그 상호작용을 디자인하는 방법을 알아보려면 알림 디자인 가이드를 읽어보십시오.

알림 생성

NotificationCompat.Builder 개체에서 알림에 대한 UI 정보와 작업을 지정합니다. 알림 자체를 생성하려면 NotificationCompat.Builder.build()를 호출합니다. 이는 사양이 포함된 Notification 객체를 반환합니다. 알림을 발행하려면 NotificationManager.notify()를 호출해서 시스템에 Notification 객체를 전달합니다.

필수 알림 콘텐츠

Notification 객체는 다음을 반드시 포함해야 합니다.

선택적 알림 콘텐츠 및 설정

다른 모든 알림 설정 및 콘텐츠는 선택 사항입니다. 이들에 관해 자세히 알아보려면 NotificationCompat.Builder의 참조 문서를 참조하십시오.

알림 작업

선택 항목이기는 하지만 알림에 작업을 하나 이상 추가해야 합니다. 작업은 사용자가 알림에서 애플리케이션의 Activity로 바로 갈 수 있게 하고, 여기에서 사용자는 하나 이상의 이벤트를 보거나 더 많은 작업을 할 수 있습니다.

하나의 알림은 여러 개의 작업을 제공할 수 있습니다. 사용자가 알림을 클릭했을 때 트리거되는 작업을 항상 정의해야 합니다. 일반적으로 작업은 애플리케이션의 Activity를 엽니다. 또한, 알람 다시 알림이나 텍스트 메시지에 즉시 답장 등과 같은 추가 작업을 수행하는 알림 버튼을 추가할 수 있습니다. 이 기능은 Android 4.1부터 사용할 수 있습니다. 추가 작업 버튼을 사용할 경우, 앱의 Activity에서 해당 기능을 사용할 수 있게 해야 합니다. 자세한 정보는 처리 호환성 섹션을 참조하십시오.

Notification에서 작업 자체는 애플리케이션에서 Activity를 시작하는 Intent가 포함된 PendingIntent가 정의합니다. PendingIntent를 동작과 연관시키려면 NotificationCompat.Builder의 적절한 메서드를 호출합니다. 예를 들어, 사용자가 알림 창의 알림 텍스트를 클릭했을 때 Activity를 시작하려면, setContentIntent()를 호출하여 PendingIntent를 추가합니다.

사용자가 알림을 클릭했을 때 Activity를 시작하는 동작이 가장 보편적인 작업 시나리오입니다. 또한, 사용자가 알림을 무시했을 때 Activity를 시작할 수도 있습니다. Android 4.1 이후부터는 Activity를 작업 버튼에서 시작할 수 있습니다. 자세한 내용을 알아보려면 NotificationCompat.Builder 참조 가이드를 읽어보십시오.

알림 우선 순위

원한다면, 알림에 우선 순위를 설정할 수 있습니다. 우선 순위는 기기 UI에 알림 표시 방식을 암시하는 역할을 합니다. 알림 우선 순위를 설정하려면, NotificationCompat.Builder.setPriority()를 호출하고 NotificationCompat 우선 순위 상수 중 하나에 전달합니다. 우선 순위 수준은 PRIORITY_MIN(-2)에서 PRIORITY_MAX(2)까지 다섯 개가 있습니다. 별도의 설정이 없을 경우, 우선 순위 기본값은 PRIORITY_DEFAULT(0)으로 설정됩니다.

적절한 우선 순위 수준 설정에 관한 정보는 알림 디자인 가이드에서 "알림 우선 순위 올바르게 설정하고 관리하기"를 참조하십시오.

단순 알림 만들기

다음 조각은 사용자가 알림을 클릭하면 알리는 액티비티를 지정하는 단순한 알림을 나타냅니다. 이 코드는 TaskStackBuilder 객체를 생성하고 이를 사용하여 해당 작업의 PendingIntent를 생성합니다. 이 패턴은 액티비티를 시작할 때 탐색 보존 섹션에서 자세히 설명합니다.

NotificationCompat.Builder mBuilder =
        new NotificationCompat.Builder(this)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!");
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(this, ResultActivity.class);

// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(ResultActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
        stackBuilder.getPendingIntent(
            0,
            PendingIntent.FLAG_UPDATE_CURRENT
        );
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(mId, mBuilder.build());

완료되었습니다. 이제 사용자에게 알림이 전달되었습니다.

알림에 확장 레이아웃 적용

확장된 보기에 알림을 나타나게 하려면, 먼저 원하는 일반 보기 옵션으로 NotificationCompat.Builder 객체를 생성합니다. 다음에는 확장된 레이아웃 객체의 인수로 Builder.setStyle()을 호출합니다.

확장 알림은 Android 4.1 이전 플랫폼에서 사용할 수 없다는 것을 명심하십시오. Android 4.1 이하 플랫폼에서 알림을 처리하는 방법은 처리 호환성 섹션을 참조하십시오.

예를 들어, 다음 코드 조각은 이전 조각에서 생성된 알림을 변경하여 확장 레이아웃을 사용하는 방법을 나타냅니다.

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
    .setSmallIcon(R.drawable.notification_icon)
    .setContentTitle("Event tracker")
    .setContentText("Events received")
NotificationCompat.InboxStyle inboxStyle =
        new NotificationCompat.InboxStyle();
String[] events = new String[6];
// Sets a title for the Inbox in expanded layout
inboxStyle.setBigContentTitle("Event tracker details:");
...
// Moves events into the expanded layout
for (int i=0; i < events.length; i++) {

    inboxStyle.addLine(events[i]);
}
// Moves the expanded layout object into the notification object.
mBuilder.setStyle(inBoxStyle);
...
// Issue the notification here.

처리 호환성

알림 기능을 설정하는 메서드가 지원 라이브러리 클래스 NotificationCompat.Builder에 있더라도 모든 알림 기능을 특정 버전에서 사용할 수 있는 것은 아닙니다. 예를 들어, 확장 알림에 따라 달라지는 작업 버튼은 Android 4.1 이상에만 나타납니다. 확장 알림 자체를 Android 4.1 이상에서만 이용할 수 있기 때문입니다.

최상의 호환성을 보장하기 위해 알림은 NotificationCompat와 하위 클래스, 특히 NotificationCompat.Builder를 이용해서 알림을 생성합니다. 또한, 알림을 구현할 때 이 절차를 따릅니다.

  1. 사용하는 버전에 관계없이 모든 사용자에게 모든 알림 기능을 제공합니다. 이를 위해서 앱의 Activity에서 모든 기능을 이용할 수 있는지 검증합니다. 그러려면 새로운 Activity를 추가해야 할 수도 있습니다.

    예를 들어, 여러분이addAction()을 사용하여 미디어 재생을 중지하고 시작하는 제어를 제공하고 싶다면 먼저 앱의 Activity에 이 제어를 구현합니다.

  2. 사용자가 알림을 클릭하면 알림을 시작시키는 방식으로 모든 사용자에게 Activity에서 알림 기능을 사용할 수 있게 합니다. 이를 위해, Activity를 위한 PendingIntent를 생성합니다. setContentIntent()를 호출하여 알림에 PendingIntent를 추가합니다.
  3. 이제 알림에서 사용하고자 하는 확장 알림 기능을 추가합니다. 또한, 사용자가 알림을 클릭하면 시작되는 Activity에서 개발자가 추가한 모든 기능을 사용할 수 있어야 합니다.

알림 관리

같은 유형의 이벤트에서 알림을 여러 번 발행해야 할 경우, 완전히 새로운 알림을 만드는 것은 삼가야 합니다. 대신, 일부 값을 변경하거나 추가하거나, 두 가지 조치를 모두 취하여 이전 알림을 업데이트하는 것이 좋습니다.

예를 들어, Gmail은 읽지 않은 메시지 개수를 올리고 각 이메일의 요약을 알림에 추가하여 새 이메일 도착을 알립니다. 이것을 일명 알림을 "쌓는다"고 하며, 이는 알림 디자인 가이드에 자세히 설명되어 있습니다.

참고: 이 Gmail 기능에는 "받은편지함" 확장 레이아웃이 필요한데, 이것은 Android 4.1부터 이용할 수 있는 확장 알림 기능의 일부입니다.

다음 섹션은 알림 업데이트 방법과 삭제 방법을 설명합니다.

알림 업데이트

알림이 업데이트되도록 설정하려면, NotificationManager.notify()를 호출하여 알림 ID와 함께 발행합니다. 알림을 발행한 후에 업데이트하려면, NotificationCompat.Builder 객체를 업데이트하거나 생성하고, Notification 객체를 구축하고, 이전에 사용한 것과 같은 ID로 Notification을 발행합니다. 이전 알림이 여전히 표시되는 경우, 시스템은 Notification 객체의 콘텐츠에서 알림을 업데이트합니다. 이전 알림을 무시할 경우, 대신 새로운 알림이 생성됩니다.

다음 코드 조각은 발생한 이벤트 개수를 반영하여 업데이트된 알림을 나타낸 것입니다. 이것은 알림을 쌓아 요약을 표시합니다.

mNotificationManager =
        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Sets an ID for the notification, so it can be updated
int notifyID = 1;
mNotifyBuilder = new NotificationCompat.Builder(this)
    .setContentTitle("New Message")
    .setContentText("You've received new messages.")
    .setSmallIcon(R.drawable.ic_notify_status)
numMessages = 0;
// Start of a loop that processes data and then notifies the user
...
    mNotifyBuilder.setContentText(currentText)
        .setNumber(++numMessages);
    // Because the ID remains unchanged, the existing notification is
    // updated.
    mNotificationManager.notify(
            notifyID,
            mNotifyBuilder.build());
...

알림 제거

알림은 다음 중 하나가 발생할 때까지 계속 표시된 상태로 유지됩니다.

  • 사용자가 개별적으로 삭제하거나 "모두 삭제"를 사용하여 알림을 무시합니다( 알림을 지울 수 있는 경우).
  • 사용자가 알림을 클릭하고, 알림을 생성했을 때 setAutoCancel() 을 호출했을 경우입니다.
  • 특정 알림 ID에 대해 cancel()을 호출합니다. 이 메서드도 현재 진행 중인 알림을 삭제합니다.
  • cancelAll()을 호출합니다. 이것은 이전에 발행한 알림을 모두 제거합니다.

액티비티를 시작할 때 탐색 보존

알림에서 Activity를 시작할 때는 사용자의 예상 탐색 경험을 보존해야 합니다. '뒤로'를 클릭하면 사용자를 애플리케이션의 정상 작업 흐름을 거쳐 메인 스크린으로 보내고, '최근'을 클릭하면 Activity를 별개의 작업으로 표시합니다. 탐색 경험을 보존하려면 새 작업에서 Activity를 시작해야 합니다. 새로운 작업을 부여하기 위한 PendingIntent 설정 방법은 시작하는 Activity의 성격에 따라 달라집니다. 여기에는 두 가지 일반적인 상황이 있습니다.

정규 액티비티
애플리케이션의 정상적 작업 흐름의 일부인 Activity를 시작합니다. 이 상황에서 PendingIntent를 설정하여 새 작업을 시작하고 애플리케이션의 정상적인 '뒤로' 동작을 재현하는 백 스택으로 PendingIntent를 제공합니다.

Gmail 앱에서 보낸 알림이 이것을 잘 보여줍니다. 하나의 이메일 메시지에 대한 알림을 클릭하면 메시지 자체를 보게 됩니다. 뒤로를 터치하면 알림에서 들어간 것이 아니라 메인 스크린에서 Gmail에 들어간 것처럼 Gmail을 통해 메인 스크린으로 돌아갑니다.

이것은 알림을 터치하기만 하면 어느 애플리케이션에 있든 관계 없이 발생하는 일입니다. 예를 들어, Gmail에서 메시지를 작성하다가 한 이메일에 대한 알림을 클릭하면 해당 이메일로 바로 이동합니다. 뒤로 를 터치하면 작성 중인 메시지가 아니라 받은편지함과 메인 스크린으로 돌아갑니다.

특수 액티비티
Activity가 알림에서 시작될 경우 사용자에게는 이것만 보입니다. Activity는 알림 자체에서 표시하기 어려운 정보를 제공하므로 어떤 면에서는 알림을 확장하는 셈입니다. 이 상황에서는, PendingIntent를 설정하고 새로운 작업에서 시작합니다. 시작된 Activity는 애플리케이션 액티비티 흐름의 일부가 아니므로 백 스택을 생성하지 않아도 됩니다. 뒤로를 클릭하면 사용자는 여전히 메인 스크린으로 돌아갑니다.

정규 액티비티 PendingIntent 설정

직접 진입 Activity를 시작하는 PendingIntent를 설정하려면 다음과 같은 단계를 따르십시오.

  1. 매니페스트에서 애플리케이션의 Activity 계층을 정의합니다.
    1. Android 4.0.3 이전에 대한 지원을 추가합니다. 이렇게 하려면 <meta-data> 요소를 <activity>의 하위 요소로 추가하여 개발자가 시작하는 Activity의 상위 요소를 지정합니다.

      이 요소의 경우, android:name="android.support.PARENT_ACTIVITY"를 설정합니다. <parent_activity_name>가 상위 요소 <activity> 에 대한 android:name의 값인 android:value="<parent_activity_name>" 를 시작합니다. 다음 XML을 예시로 참조하십시오.

    2. Android 4.1 이후에 대한 지원도 추가합니다. 이렇게 하려면 개발자가 시작하는 Activity<activity> 요소에 android:parentActivityName 속성을 추가합니다.

    최종 XML은 이런 모습을 띠는 것이 정상입니다.

    <activity
        android:name=".MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity
        android:name=".ResultActivity"
        android:parentActivityName=".MainActivity">
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value=".MainActivity"/>
    </activity>
    
  2. Activity를 시작하는 Intent에 기초하여 백 스택을 생성합니다.
    1. Intent를 생성하여 Activity를 생성합니다.
    2. TaskStackBuilder.create()를 호출하여 스택 빌더를 생성합니다.
    3. addParentStack()을 호출하여 스택 빌더를 백 스택에 추가합니다. 매니페스트에서 정의한 계층의 각 Activity의 경우, 백 스택에 Activity를 시작하는 Intent 객체가 포함됩니다. 이 메서드는 새로운 작업에서 스택을 시작하는 플래그도 추가합니다.

      참고: addParentStack()에 대한 인수가 시작된 Activity의 참조이기는 하지만, 이 메서드 호출은 Activity를 시작하는 Intent를 추가하지 않습니다. 대신, 그 부분은 다음 단계에서 해결합니다.

    4. addNextIntent()를 호출하여 Activity를 시작하는 Intent를 추가합니다. 첫 번째 단계에서 생성한 IntentaddNextIntent()에 대한 인수로 전달합니다.
    5. 필요할 경우 TaskStackBuilder.editIntentAt()을 호출하여 스택에서Intent 객체에 대한 인수를 추가합니다. 이것은 사용자가 '뒤로'를 사용하여 탐색할 때 대상Activity가 의미 있는 데이터를 표시하도록 보장하기 위해 때때로 필요한 절차입니다.
    6. 이 백 스택에 대한 PendingIntent를 가져옵니다. 이때 getPendingIntent()를 호출하는 방법을 씁니다. 그러면 이 PendingIntentsetContentIntent()에 대한 인수로 사용할 수 있습니다.

다음 코드 조각은 이 과정을 나타낸 것입니다.

...
Intent resultIntent = new Intent(this, ResultActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack
stackBuilder.addParentStack(ResultActivity.class);
// Adds the Intent to the top of the stack
stackBuilder.addNextIntent(resultIntent);
// Gets a PendingIntent containing the entire back stack
PendingIntent resultPendingIntent =
        stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
...
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(id, builder.build());

특수 액티비티 PendingIntent 설정

다음 섹션에서는 특수 액티비티 PendingIntent를 설정하는 법을 설명합니다.

특수 Activity에는 백 스택이 필요하지 않습니다. 따라서 매니페스트에서 이것의 Activity 계층을 정의하지 않아도 되고, 백 스택을 구축하기 위해 addParentStack()을 호출하지 않아도 됩니다. 대신 매니페스트를 사용하여 Activity 작업 옵션을 설정하고, PendingIntent를 생성하십시오. 이때 getActivity()를 호출하는 방법을 씁니다.

  1. 매니페스트에서 다음 속성을 Activity에 대한 <activity> 요소에 추가합니다.
    android:name="activityclass"
    액티비티의 완전히 정규화된 클래스 이름입니다.
    android:taskAffinity=""
    이것은 개발자가 코드에서 설정하는 FLAG_ACTIVITY_NEW_TASK 플래그와 더불어 이 Activity가 애플리케이션의 기본 작업으로 들어가지 않게 보장합니다. 애플리케이션의 기본 유사성을 가지고 있는 기존 작업은 모두 영향을 받지 않습니다.
    android:excludeFromRecents="true"
    새 작업을 최근에서 배제하여 사용자가 우연히 이곳으로 다시 이동하지 못하게 합니다.

    이 조각은 해당 요소를 나타낸 것입니다.

    <activity
        android:name=".ResultActivity"
    ...
        android:launchMode="singleTask"
        android:taskAffinity=""
        android:excludeFromRecents="true">
    </activity>
    ...
    
  2. 알림을 구축 및 발행합니다.
    1. Activity를 시작하는 Intent를 생성합니다.
    2. Activity가 새로운, 빈 작업에서 시작되도록 설정합니다. 이때 setFlags()FLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_CLEAR_TASK 플래그와 함께 호출하면 됩니다.
    3. Intent에 필요한 다른 모든 옵션을 설정합니다.
    4. PendingIntentIntent로부터 생성합니다. 이때 getActivity()를 호출하면 됩니다. 그러면 이 PendingIntentsetContentIntent()에 대한 인수로 사용할 수 있습니다.

    다음 코드 조각은 이 과정을 나타낸 것입니다.

    // Instantiate a Builder object.
    NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
    // Creates an Intent for the Activity
    Intent notifyIntent =
            new Intent(this, ResultActivity.class);
    // Sets the Activity to start in a new, empty task
    notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                            | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    // Creates the PendingIntent
    PendingIntent notifyPendingIntent =
            PendingIntent.getActivity(
            this,
            0,
            notifyIntent,
            PendingIntent.FLAG_UPDATE_CURRENT
    );
    
    // Puts the PendingIntent into the notification builder
    builder.setContentIntent(notifyPendingIntent);
    // Notifications are issued by sending them to the
    // NotificationManager system service.
    NotificationManager mNotificationManager =
        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    // Builds an anonymous Notification object from the builder, and
    // passes it to the NotificationManager
    mNotificationManager.notify(id, builder.build());
    

알림에서 진행 상태 표시

알림에는 사용자에게 진행 중인 작업의 상태를 보여주는 애니메이션 진행 표시기를 포함할 수 있습니다. 작업이 얼마나 걸릴지, 주어진 시점에 어느 정도 완료되었는지를 추정할 수 있는 경우 표시기의 "확정적" 형태(진행률 표시줄)를 사용하십시오. 작업의 길이를 추정할 수 없으면, 표시기의 "비확정적" 형태(액티비티 표시기)를 사용하십시오.

진행 상태 표시기는 ProgressBar 클래스의 플랫폼 구현으로 표시됩니다.

Android 4.0부터 시작되는 플랫폼에서 진행 상태 표시기를 사용하려면, setProgress()를 호출하십시오. 이전 버전의 경우, 개발자 나름의 사용자 지정 알림 레이아웃을 생성해야 하며 여기에 ProgressBar 보기가 포함되어 있어야 합니다.

다음 섹션은 setProgress()를 사용하여 알림의 진행 상태를 표시하는 법을 설명합니다.

고정 기간 진행 상태 표시기 표시

확정적인 진행률 표시줄을 표시하려면 setProgress(max, progress, false)를 호출하여 표시줄을 알림에 추가하고, 그 다음에 알림을 발행합니다. 작업이 진행되는 동안 progress를 증가시키고 알림을 업데이트합니다. 작업이 끝날 무렵 progressmax와 같아야 합니다. setProgress()를 호출하는 보편적인 방법은 max를 100에 설정하고 작업에 대한 "완료 비율" 값에 따라 progress를 증가시키는 것입니다.

작업이 완료되면 진행률 표시줄이 표시되는 상태로 둘 수도 있고, 제거할 수도 있습니다. 어느 경우를 택하더라도 알림 텍스트를 업데이트하여 작업이 완료되었다고 표시하는 것을 잊지 마십시오. 진행률 표시줄을 제거하려면, setProgress(0, 0, false)를 호출합니다. 예:

...
mNotifyManager =
        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this);
mBuilder.setContentTitle("Picture Download")
    .setContentText("Download in progress")
    .setSmallIcon(R.drawable.ic_notification);
// Start a lengthy operation in a background thread
new Thread(
    new Runnable() {
        @Override
        public void run() {
            int incr;
            // Do the "lengthy" operation 20 times
            for (incr = 0; incr <= 100; incr+=5) {
                    // Sets the progress indicator to a max value, the
                    // current completion percentage, and "determinate"
                    // state
                    mBuilder.setProgress(100, incr, false);
                    // Displays the progress bar for the first time.
                    mNotifyManager.notify(0, mBuilder.build());
                        // Sleeps the thread, simulating an operation
                        // that takes time
                        try {
                            // Sleep for 5 seconds
                            Thread.sleep(5*1000);
                        } catch (InterruptedException e) {
                            Log.d(TAG, "sleep failure");
                        }
            }
            // When the loop is finished, updates the notification
            mBuilder.setContentText("Download complete")
            // Removes the progress bar
                    .setProgress(0,0,false);
            mNotifyManager.notify(ID, mBuilder.build());
        }
    }
// Starts the thread by calling the run() method in its Runnable
).start();

지속적 액티비티 표시기 표시

비확정적 액티비티 표시기를 표시하려면, setProgress(0, 0, true)으로 알림에 표시기를 추가하고(처음의 인수 두 개는 무시합니다) , 알림을 발행합니다. 그 결과로 진행률 표시줄과 같은 스타일의 표시기가 나타납니다. 다만 이것은 애니메이션이 계속 진행 중입니다.

작업을 시작할 때 알림을 발행합니다. 애니메이션은 알림을 수정할 때까지 실행됩니다. 작업이 완료되면, setProgress(0, 0, false)를 호출하고 알림을 업데이트하여 액티비티 표시기를 제거합니다. 이 작업은 항상 해야 합니다. 하지 않으면, 작업이 완료되더라도 애니메이션이 계속 실행됩니다. 또한, 알림 텍스트를 변경하여 작업이 완료되었음을 나타내는 것을 잊지 마십시오.

액티비티 표시기의 작동 원리를 알아보려면 이어지는 코드 조각을 참조하십시오. 다음 줄을 찾을 수 있습니다.

// Sets the progress indicator to a max value, the current completion
// percentage, and "determinate" state
mBuilder.setProgress(100, incr, false);
// Issues the notification
mNotifyManager.notify(0, mBuilder.build());

찾은 줄을 다음 줄로 교체하십시오.

 // Sets an activity indicator for an operation of indeterminate length
mBuilder.setProgress(0, 0, true);
// Issues the notification
mNotifyManager.notify(0, mBuilder.build());

알림 메타데이터

알림은 다음 NotificationCompat.Builder 메서드로 할당된 메타데이터에 따라 정렬할 수 있습니다.

  • setCategory()는 기기가 우선 순위 모드일 때 앱 알림을 처리하는 방법을 시스템에 전달합니다 (예를 들어, 알림이 수신 전화나 채팅 메시지, 알람 등을 나타낼 경우).
  • setPriority()는 우선 순위 필드가 포함된 알림을 PRIORITY_MAX 또는 PRIORITY_HIGH로 설정하고, 알림에 소리나 진동이 포함되어 있을 경우 작은 부동 창에 나타나게 합니다.
  • addPerson()을 사용하면 알림에 사람 목록을 추가할 수 있게 해줍니다. 개발자의 앱은 이 신호를 사용하여 시스템에 지정된 사람들로부터 받은 알림을 함께 그룹화해야 한다고 알리거나, 이런 사람들로부터 받은 알림을 더욱 중요한 것으로 순위를 높일 수 있습니다.

그림 3. 헤드업 알림을 표시하고 있는 전체 화면 액티비티

헤드업 알림

Android 5.0(API 레벨 21)에서는 알림을 작은 부동 창에 나타낼 수 있습니다 (다른 말로 헤드업 알림이라고 부릅니다). 이것은 기기가 활성 상태일 때(즉, 기기가 잠금 해제 상태이며 화면에 켜져 있는 경우) 해당됩니다. 이와 같은 알림은 외견상 일반적인 알림의 소형 형태와 비슷해 보이지만, 해드업 알림에서는 작업 버튼도 표시한다는 점이 다릅니다. 사용자는 현재 앱을 떠나지 않고도 헤드업 알림에 조치를 취하거나 이를 무시할 수 있습니다.

헤드업 알림을 트리거할 수 있는 조건의 예시를 몇 가지 소개하면 다음과 같습니다.

  • 사용자 액티비티가 전체 화면 모드이거나(앱이 fullScreenIntent를 사용할 경우)
  • 알림의 우선 순위가 높고 벨소리나 진동을 사용할 경우

잠금 화면 알림

Android 5.0 (API 레벨 21) 릴리스부터 알림이 잠금 화면에도 나타날 수 있게 되었습니다. 앱은 이 기능을 사용하면 미디어 재생 제어와 다른 보편적인 작업을 제공할 수 있습니다. 사용자는 설정을 통해 잠금 화면에 알림 표시 여부를 선택할 수 있고, 개발자는 앱의 알림이 잠금 화면에 표시될지 여부를 지정할 수 있습니다.

가시성 설정

보안 잠금 화면에 알림이 얼마나 상세하게 표시될 것인지 그 수준을 앱이 제어할 수 있습니다. setVisibility()를 호출하고 다음 값 중 하나를 지정합니다.

  • VISIBILITY_PUBLIC은 알림의 전체 콘텐츠를 표시합니다.
  • VISIBILITY_SECRET은 이 알림의 어떤 부분도 화면에 표시하지 않습니다.
  • VISIBILITY_PRIVATE은 알림 아이콘과 콘텐츠 제목 등의 기본 정보는 표시하지만 알림의 전체 콘텐츠는 숨깁니다.

VISIBILITY_PRIVATE으로 설정하면 , 알림 콘텐츠의 대체 버전을 제공할 수도 있습니다. 이렇게 하면 특정 세부 사항만 숨깁니다. 예를 들어, SMS 앱에서 3개의 새 문자 메시지가 있습니다.라고 표시하면서도 문자 메시지의 내용과 발신자는 숨길 수 있습니다. 이 대체 알림을 제공하려면, 우선 대체 알림을 생성합니다. 이때 NotificationCompat.Builder를 사용합니다. 비공개 알림 객체를 생성하는 경우, 대체 알림을 이에 첨부할 때 setPublicVersion() 메서드를 통합니다.

잠금 화면에서 미디어 재생 제어

Android 5.0(API 레벨 21)의 잠금 화면에서는 더 이상 RemoteControlClient를 기반으로 한 미디어 제어를 표시하지 않습니다. 이는 사용되지 않고 있기 때문입니다. 대신, Notification.MediaStyle 템플릿을 addAction() 메서드와 함께 사용하십시오. 이 메서드는 작업을 클릭할 수 있는 아이콘으로 변환해줍니다.

참고: 이 템플릿과 addAction() 메서드는 지원 라이브러리에 포함되어 있지 않으므로 이 기능은 Android 5.0 이상에서만 실행됩니다.

Android 5.0의 잠금 화면에서 미디어 재생 제어를 표시하려면, 위에 설명한 바와 같이 가시성을 VISIBILITY_PUBLIC으로 설정합니다. 그런 다음 다음 샘플 코드에서 설명한 바와 같이 작업을 추가하고 Notification.MediaStyle 템플릿을 설정합니다.

Notification notification = new Notification.Builder(context)
    // Show controls on lock screen even when user hides sensitive content.
    .setVisibility(Notification.VISIBILITY_PUBLIC)
    .setSmallIcon(R.drawable.ic_stat_player)
    // Add media control buttons that invoke intents in your media service
    .addAction(R.drawable.ic_prev, "Previous", prevPendingIntent) // #0
    .addAction(R.drawable.ic_pause, "Pause", pausePendingIntent)  // #1
    .addAction(R.drawable.ic_next, "Next", nextPendingIntent)     // #2
    // Apply the media style template
    .setStyle(new Notification.MediaStyle()
    .setShowActionsInCompactView(1 /* #1: pause button */)
    .setMediaSession(mMediaSession.getSessionToken())
    .setContentTitle("Wonderful music")
    .setContentText("My Awesome Band")
    .setLargeIcon(albumArtBitmap)
    .build();

참고: RemoteControlClient를 사용하지 않게 된 것은 미디어 제어에 이외에도 더 많은 영향을 미칩니다. 미디어 세션을 관리하고 재생을 제어하기 위한 새 API에 관한 자세한 정보는 미디어 재생 제어를 참조하십시오.

사용자 지정 알림 레이아웃

알림 프레임워크를 사용하면 사용자 지정 레이아웃을 정의할 수 있습니다. 사용자 지정 레이아웃은 RemoteViews 객체에서 알림의 외관을 정의합니다. 사용자 지정 레이아웃 알림은 일반적인 알림과 비슷하지만, 이들은 XML 레이아웃 파일에서 정의한 RemoteViews에 기초합니다.

사용자 지정 알림 레이아웃에 사용할 수 있는 높이는 알림 보기에 따라 다릅니다. 일반 보기 레이아웃은 64dp로 제한되어 있으며 확장 보기 레이아웃은 256dp로 제한되어 있습니다.

사용자 지정 레이아웃을 정의하려면 XML 레이아웃 파일을 팽창하는 RemoteViews 객체를 인스턴트화하는 것부터 시작합니다. 그런 다음, setContentTitle()과 같은 메서드를 호출하는 대신 setContent()를 호출합니다. 사용자 지정 알림에서 콘텐츠 세부 정보를 설정하려면 RemoteViews의 메서드를 사용하여 보기의 하위 요소에 대한 값을 설정합니다.

  1. 알림에 대한 XML 레이아웃은 별도의 파일에 생성하십시오. 파일 이름은 원하는 대로 아무 것이나 사용해도 좋지만, 확장자는 .xml을 사용해야 합니다.
  2. 앱에서 RemoteViews 메서드를 사용하여 알림의 아이콘과 텍스트를 정의합니다. 이 RemoteViews 객체를 NotificationCompat.Builder 안에 넣으십시오. setContent()를 호출하면 됩니다. 배경 DrawableRemoteViews 객체에서 설정하는 것은 삼가하십시오. 텍스트 색상을 읽을 수 없게 될 수도 있습니다.

RemoteViews 클래스에도 개발자가 손쉽게 사용할 수 있는 여러 가지 메서드가 포함되어 있습니다. 이를 이용해 Chronometer 또는 ProgressBar를 알림의 레이아웃에 추가하면 됩니다. 알림의 사용자 지정 레이아웃 생성에 관한 자세한 정보는 RemoteViews 참조 문서를 참조하십시오.

주의: 사용자 지정 레이아웃을 사용하는 경우, 사용자 지정 레이아웃이 다양한 기기 방향과 해상도에서 작동하는지 각별히 주의를 기울여 확인하십시오. 이 조언은 모든 보기 레이아웃에 공통적으로 적용되지만, 특히 알림에 중요한 의미를 지닙니다. 알림 창에서는 공간이 굉장히 제한되어 있기 때문입니다. 사용자 지정 레이아웃을 너무 복잡하게 만들지 마시고, 여러 가지 구성에서 테스트하는 것을 잊지 마십시오.

사용자 지정 알림 텍스트에 스타일 리소스 사용

사용자 지정 알림의 텍스트에는 항상 스타일 리소스를 사용하십시오. 알림의 배경 색상은 기기와 버전별로 다를 수 있습니다. 스타일 리소스를 사용하면 이러한 차이를 감안하는 데 도움이 됩니다. Android 2.3부터 시스템은 표준 알림 레이아웃 텍스트의 스타일을 정의했습니다. Android 2.3 이상을 대상으로 하는 애플리케이션에서와 같은 스타일을 사용하면 텍스트가 디스플레이 배경에서도 잘 보이도록 할 수 있습니다.