Computer >> 컴퓨터 >  >> 프로그래밍 >> Android

Android 앱이 크래시될 때 알림을 자동으로 삭제하는 방법

Android 앱이 크래시될 때 알림을 자동으로 삭제하는 방법

앱에서 진행 중인 알림을 표시하는 도중 액티비티가 비정상 종료(크래시)되면, 해당 알림이 상태 표시줄에 그대로 남아 있어 사용자에게 혼란을 줄 수 있습니다. 이 예제에서는 UncaughtExceptionHandler를 활용하여 앱이 크래시되는 순간 표시 중인 알림을 자동으로 제거하는 방법을 단계별로 살펴봅니다.

핵심 아이디어는 간단합니다. 기본 예외 처리 핸들러를 감싸는 커스텀 CrashHandler 클래스를 만들고, 예외가 발생하면 NotificationManager를 통해 해당 알림을 취소한 뒤 원래의 기본 핸들러에 처리를 위임하는 것입니다.


1단계 − 새 프로젝트 생성

Android Studio에서 File ⇒ New Project를 선택하고, 새 프로젝트를 만드는 데 필요한 모든 세부 정보를 입력하여 프로젝트를 생성합니다.

2단계 − 레이아웃 파일 작성

다음 코드를 res/layout/activity_main.xml에 추가합니다. 화면 중앙에 'Create Notification' 버튼 하나를 배치하는 단순한 구성입니다.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">

<Button
android:id="@+id/btnCreateNotification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_centerInParent="true"
android:text="Create Notification" />

</RelativeLayout>

3단계 − MainActivity 구현

다음 코드를 src/MainActivity.java에 추가합니다. 이 코드는 버튼 클릭 시 알림 채널을 생성하고 알림을 발행하는 역할을 합니다.

package app.tutorialspoint.com.notifyme;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

public class MainActivity extends AppCompatActivity {

public static final String NOTIFICATION_CHANNEL_ID = "10001";
private final static String default_notification_channel_id = "default";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void createNotification(View view) {
Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
notificationIntent.putExtra("fromNotification", true);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(MainActivity.this, default_notification_channel_id);
mBuilder.setContentTitle("My Notification");
mBuilder.setContentIntent(pendingIntent);
mBuilder.setColor(getColor(R.color.colorPrimary));
mBuilder.setContentText("Notification Listener Service Example");
mBuilder.setSmallIcon(R.drawable.ic_launcher_foreground);
mBuilder.setAutoCancel(true);

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "NOTIFICATION_CHANNEL_NAME", importance);
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
assert mNotificationManager != null;
mNotificationManager.createNotificationChannel(notificationChannel);
}

assert mNotificationManager != null;
mNotificationManager.notify((int) System.currentTimeMillis(), mBuilder.build());
}
}

4단계 − CrashHandler 구현

이번 예제의 핵심 부분입니다. 다음 코드를 src/CrashHandler.java로 새 파일을 만들어 추가합니다. 이 클래스는 Thread.UncaughtExceptionHandler를 구현하여, 앱에서 처리되지 않은 예외가 발생했을 때 먼저 알림을 취소한 후 기존 기본 핸들러로 흐름을 넘깁니다.

package app.tutorialspoint.com.notifyme;

import android.app.NotificationManager;
import android.content.Context;

public class CrashHandler implements Thread.UncaughtExceptionHandler {

private static final int NOTIFICATION_ID = 12345;
private Thread.UncaughtExceptionHandler defaultUEH;
private NotificationManager notificationManager;

public CrashHandler(Context context) {
this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}

@Override
public void uncaughtException(Thread t, Throwable e) {
if (notificationManager != null) {
try {
notificationManager.cancel(NOTIFICATION_ID);
} catch (Throwable ex) {
ex.printStackTrace();
}
}
notificationManager = null;
defaultUEH.uncaughtException(t, e);
}
}

참고: 실제 적용 시에는 알림을 발행할 때 mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build())처럼 고정된 ID를 사용해야 CrashHandler에서 동일한 ID로 알림을 정확히 취소할 수 있습니다.

5단계 − AndroidManifest.xml 설정

다음 코드를 AndroidManifest.xml에 추가합니다. 여기서 Application 태그 안에 커스텀 CrashHandler를 등록하는 코드를 넣어야 전체 앱에서 예외를 가로챌 수 있다는 점에 유의하세요.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="app.tutorialspoint.com.notifyme">

<uses-permission android:name="android.permission.VIBRATE" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">

<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

</application>
</manifest>

정리

이렇게 하면 앱이 어떤 이유로든 크래시되더라도, CrashHandler가 예외를 가로채는 즉시 표시 중인 알림을 제거한 뒤 기본 크래시 처리 흐름(로그 기록 및 앱 종료)을 그대로 수행합니다. 이 패턴은 다운로드 진행률 알림, 미디어 재생 알림 등 앱 종료 시 함께 사라져야 하는 알림을 관리할 때 특히 유용합니다.