Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Android

एंड्रॉइड में एक्टिविटी क्रैश होने पर नोटिफिकेशन कैसे साफ़ करें?

यह गाइड बताता है कि **UncaughtExceptionHandler** का उपयोग करके ऐप क्रैश होने पर नोटिफिकेशन को प्रोग्रामेटिक रूप से कैसे साफ़ किया जाए। यह सुनिश्चित करता है कि "भूत" नोटिफिकेशन न रहें जो टैप करने पर क्रैश लूप का कारण बनते हैं।

समस्या

जब कोई एक्टिविटी क्रैश होती है (अनकॉट एक्सेप्शन), तो ऐप प्रक्रिया समाप्त हो जाती है। यदि कोई नोटिफिकेशन लंबित था जो उस क्रैश हुई एक्टिविटी को खोलता है, तो नोटिफिकेशन पर टैप करने से ऐप पुनः आरंभ होता है → क्रैश एक्टिविटी लॉन्च होती है → फिर से क्रैश होती है → अनंत लूप।

समाधान: कस्टम UncaughtExceptionHandler

एक ग्लोबल एक्सेप्शन हैंडलर सेट करें जो डिफ़ॉल्ट हैंडलर को सौंपने से पहले नोटिफिकेशन कैंसिल करता है।

चरण 1: CrashHandler.java

package com.example.crashclearnotification;

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

public class CrashHandler implements Thread.UncaughtExceptionHandler {

    private static final int NOTIFICATION_ID = 12345; // आपके नोटिफिकेशन आईडी से मेल खाना चाहिए
    private final Thread.UncaughtExceptionHandler defaultHandler;
    private final NotificationManager notificationManager;

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

    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        try {
            // क्रैश से पहले नोटिफिकेशन कैंसिल करें
            if (notificationManager != null) {
                notificationManager.cancel(NOTIFICATION_ID);
                // या सभी कैंसिल करें: notificationManager.cancelAll();
            }
        } catch (Exception e) {
            // कैंसिलेशन विफल होने पर भी क्रैश रिपोर्टिंग जारी रखें
            e.printStackTrace();
        } finally {
            // डिफ़ॉल्ट हैंडलर को सौंपें (सिस्टम क्रैश डायलॉग दिखाता है, प्ले कंसोल को रिपोर्ट करता है, आदि)
            if (defaultHandler != null) {
                defaultHandler.uncaughtException(thread, throwable);
            } else {
                // फॉलबैक: प्रक्रिया समाप्त करें
                android.os.Process.killProcess(android.os.Process.myPid());
                System.exit(10);
            }
        }
    }
}

चरण 2: Application उपवर्ग में आरंभीकरण

package com.example.crashclearnotification;

import android.app.Application;

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        // ग्लोबल अनकॉट एक्सेप्शन हैंडलर स्थापित करें
        Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(this));
    }
}

चरण 3: AndroidManifest.xml - Application वर्ग घोषित करें

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

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

    <application
        android:name=".MyApplication"  <!-- कस्टम 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/Theme.CrashClearNotification">

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

चरण 4: MainActivity.java - नोटिफिकेशन बनाएँ

package com.example.crashclearnotification;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationCompat;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    private static final String CHANNEL_ID = "crash_demo_channel";
    private static final String CHANNEL_NAME = "क्रैश डेमो नोटिफिकेशन";
    public static final int NOTIFICATION_ID = 12345; // CrashHandler के साथ साझा

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

        createNotificationChannel();

        Button btnNotify = findViewById(R.id.btnCreateNotification);
        Button btnCrash = findViewById(R.id.btnForceCrash);

        btnNotify.setOnClickListener(v -> createNotification());
        btnCrash.setOnClickListener(v -> forceCrash());
    }

    private void createNotification() {
        Intent intent = new Intent(this, MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        intent.putExtra("from_notification", true);

        PendingIntent pendingIntent = PendingIntent.getActivity(
            this, 0, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentTitle("क्रैश टेस्ट नोटिफिकेशन")
            .setContentText("ऐप को क्रैश करें फिर मुझे टैप करें - मैं गायब हो जाऊँगा")
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true);

        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        manager.notify(NOTIFICATION_ID, builder.build());
    }

    private void forceCrash() {
        // जानबूझकर NullPointerException फेंकें
        throw new NullPointerException("जानबूझकर क्रैश टेस्ट के लिए");
    }

    private void createNotificationChannel() {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
            channel.setDescription("क्रैश पर ऑटो-क्लियर डेमो");
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }
    }
}

चरण 5: लेआउट (activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    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="0dp"
        android:layout_height="wrap_content"
        android:text="नोटिफिकेशन बनाएँ (आईडी: 12345)"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <Button
        android:id="@+id/btnForceCrash"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="ऐप को क्रैश करें (NullPointerException)"
        android:layout_marginTop="16dp"
        android:backgroundTint="#FF0000"
        app:layout_constraintTop_toBottomOf="@id/btnCreateNotification"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text="निर्देश: 1) नोटिफिकेशन बनाएँ 2) होम दबाएँ 3) ऐप को क्रैश करें 4) नोटिफिकेशन शेड खोलें - नोटिफिकेशन गायब होना चाहिए"
        android:textSize="14sp"
        android:textColor="#666"
        app:layout_constraintTop_toBottomOf="@id/btnForceCrash"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

यह कैसे काम करता है

1. ऐप शुरू होता है → MyApplication.onCreate() → CrashHandler स्थापित
2. उपयोगकर्ता नोटिफिकेशन बनाता है (आईडी 12345)
3. उपयोगकर्ता ऐप को क्रैश करता है (उदाहरण के लिए, NullPointerException)
4. सिस्टम CrashHandler.uncaughtException() को कॉल करता है
5. CrashHandler:
   a) NotificationManager.cancel(12345) → नोटिफिकेशन हटाता है
   b) defaultHandler.uncaughtException() → सामान्य क्रैश संचालन जारी रखता है
6. ऐप प्रक्रिया मर जाती है
7. उपयोगकर्ता नोटिफिकेशन शेड खोलता है → नोटिफिकेशन गायब (साफ़ किया गया)
8. उपयोगकर्ता ऐप पुनः लॉन्च करता है → साफ़ शुरुआत, कोई भूत नोटिफिकेशन नहीं

उन्नत: सभी नोटिफिकेशन कैंसिल करें

// CrashHandler में, विशिष्ट आईडी के बजाय:
notificationManager.cancelAll(); // ऐप के सभी नोटिफिकेशन हटाता है

उन्नत: क्रैश रिपोर्टिंग एकीकरण

यदि Firebase Crashlytics या समान का उपयोग कर रहे हैं, तो डिफ़ॉल्ट हैंडलर को कॉल करने से पहले कस्टम लॉजिक जोड़ें:

@Override
public void uncaughtException(Thread thread, Throwable throwable) {
    // 1. नोटिफिकेशन साफ़ करें
    if (notificationManager != null) {
        notificationManager.cancelAll();
    }
    
    // 2. कस्टम क्रैश लॉगिंग (वैकल्पिक)
    // Crashlytics.logException(throwable); // यदि Crashlytics उपयोग कर रहे हैं
    
    // 3. डिफ़ॉल्ट हैंडलर को सौंपें (Crashlytics, प्ले कंसोल, सिस्टम डायलॉग)
    if (defaultHandler != null) {
        defaultHandler.uncaughtException(thread, throwable);
    }
}

सीमाएँ

परिदृश्यकाम करता है?टिप्पणी
Java अनकॉट एक्सेप्शन✅ हाँThread.setDefaultUncaughtExceptionHandler द्वारा पकड़ा गया
नेटिव क्रैश (SIGSEGV, आदि)❌ नहींJVM स्तर से नीचे; जावा हैंडलर नहीं चलता
ANR (एप्लिकेशन नॉट रिस्पॉन्डिंग)❌ नहींसिस्टम द्वारा संभाला जाता है, अनकॉट एक्सेप्शन नहीं
सिस्टम द्वारा प्रक्रिया मारी गई (OOM)❌ नहींकोड निष्पादन का कोई अवसर नहीं

वैकल्पिक दृष्टिकोण: स्टार्टअप पर साफ़ करें

सरल, अधिक मजबूत दृष्टिकोण: ऐप स्टार्टअप पर सभी नोटिफिकेशन साफ़ करें।

// MyApplication.onCreate() या MainActivity.onCreate() में:
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancelAll(); // ऐप के सभी नोटिफिकेशन साफ़ करता है

यह क्रैश, बल-स्टॉप, सिस्टम किल, या सामान्य पुनः आरंभ के बाद काम करता है। अधिकांश ऐप्स के लिए अनुशंसित।

सर्वोत्तम अभ्यास

  1. स्थिर notificationId उपयोग करें जिसे CrashHandler और नोटिफिकेशन निर्माता दोनों जानते हैं
  2. Application.onCreate() में हैंडलर स्थापित करें, एक्टिविटी में नहीं
  3. डिफ़ॉल्ट हैंडलर को हमेशा सौंपें - क्रैश रिपोर्टिंग न तोड़ें
  4. स्टार्टअप पर cancelAll() पर विचार करें सरलता और मजबूती के लिए
  5. Firebase Crashlytics जैसे क्रैश रिपोर्टिंग टूल के साथ परीक्षण करें
  1. Android में Notification.deleteIntent का उपयोग कैसे करें? Android में Notification.deleteIntent का उपयोग कैसे करें?

    Android में Notification.deleteIntent का उपयोग यह उदाहरण दर्शाता है कि Android में Notification.deleteIntent का उपयोग कैसे किया जाता है। चरण 1 - नया प्रोजेक्ट बनाएं Android Studio में File → New Project पर जाएं और नया प्रोजेक्ट बनाने के लिए सभी आवश्यक विवरण भरें। चरण 2 - res/layout/activity_main.x

  1. Android में रिमाइंडर नोटिफिकेशन कैसे बनाएं? Android में रिमाइंडर नोटिफिकेशन कैसे बनाएं?

    Android में रिमाइंडर नोटिफिकेशन बनाना यह उदाहरण दर्शाता है कि Android में रिमाइंडर नोटिफिकेशन कैसे बनाया जाता है। चरण 1 - नया प्रोजेक्ट बनाएं Android Studio में File → New Project पर जाएं और नया प्रोजेक्ट बनाने के लिए सभी आवश्यक विवरण भरें। चरण 2 - res/layout/activity_main.xml में कोड जोड़ें <?

  1. एंड्रॉइड में एक्टिविटी को कैसे रीस्टार्ट करें? एंड्रॉइड में एक्टिविटी को कैसे रीस्टार्ट करें?

    एंड्रॉइड एक्टिविटी को प्रोग्रामेटिकली रीस्टार्ट करना यह गाइड एक्टिविटी को रीस्टार्ट करने के विभिन्न तरीकों को दर्शाता है, जिसमें इंटेंट फ्लैग्स और रिक्रिएशन शामिल हैं। लेआउट (activity_main.xml) <RelativeLayout xmlns:android=https://schemas.android.com/apk/res/android android:layout_width=mat