Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
480 views
in Technique[技术] by (71.8m points)

android - Notification Listener Service does not work after app is crashed

I have a problem on my app and I want to report this bug.

I develope the app which can crawls notifications using NotificationListenerService.

It works well.

But NotificationListenerService class has the problem I think.

Because, If the app is crashed, app can't crawl the notification at all, UNTIL the phone reboots.

Is anyone who can solve this problem??

Please help me.

The bug is very clear!! But It is not easy to find the solution ....

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If do you have already permissions then:

In your service class or another service/activity you can switch the "component hability" to listen notifications:

    public void tryReconnectService() {
        toggleNotificationListenerService();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            ComponentName componentName =
                    new ComponentName(getApplicationContext(), NotificationReaderV2Service.class);

            //It say to Notification Manager RE-BIND your service to listen notifications again inmediatelly!
            requestRebind(componentName);
        }
    }

/**
* Try deactivate/activate your component service
*/
    private void toggleNotificationListenerService() {
        PackageManager pm = getPackageManager();
        pm.setComponentEnabledSetting(new ComponentName(this, NotificationReaderV2Service.class),
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
        pm.setComponentEnabledSetting(new ComponentName(this, NotificationReaderV2Service.class),
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
    }

Your notification listener, is a SERVICE, it can be killed by System, you can do your service as FOREGROUND to drastically decrease the probability that the system will kill your service.

@Override
    public void onListenerConnected() {
        super.onListenerConnected();
        Log.d(TAG, "Service Reader Connected");
    Notification not = createNotification();
    NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    if (mNotificationManager != null) {
        mNotificationManager.notify(NOTIFICATION_ID, not);
    }

    startForeground(NOTIFICATION_ID, not);

    //Alarm to auto - send Intents to Service to reconnect, you can ommit next line.
    alarmIt();
}

If do you like so more "safe", you can to programming not-friendly battery alarms, try to use inexact alarms please, the user's battery will be happy:

private void alarmIt() {
    Log.d(TAG, "ALARM PROGRAMMATED at"+HotUtils.formatDate(new Date()));
    Calendar now = Calendar.getInstance();
    now.setTimeInMillis(System.currentTimeMillis());
    now.set(Calendar.MINUTE, now.get(Calendar.MINUTE) + 1);

    Intent intent = new Intent(this, NotificationReaderV2Service.class);
    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
    intent.setAction(REBIND_ACTION);

    PendingIntent pendingIntent = PendingIntent.getService(this, 0,
            intent, 0);

    AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

    //The alarms that are repeated are inaccurate by default, use RTC_WAKE_UP at your convenience.
    //Alarm will fire every minute, CHANGE THIS iF DO YOU CAN, you can't use less than 1 minute to repeating alarms.
    manager.setRepeating(AlarmManager.RTC_WAKEUP, now.getTimeInMillis(), 1000 * 60 * 1, pendingIntent);
}

and next read the Intent to reconnect service binding:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d(TAG, "Notification service onStartCommandCalled");
    if (intent!=null && !HotUtils.isNullOrEmpty(intent.getAction()) && intent.getAction().equals(REBIND_ACTION)){
        Log.d(TAG, "TRYING REBIND SERVICE at "+HotUtils.formatDate(new Date()));
        tryReconnectService();//switch on/off component and rebind
    }
    //START_STICKY  to order the system to restart your service as soon as possible when it was killed.
    return START_STICKY;
}

Keep in mind that doing all these steps you can sure that your service will be killed anyway by the system but this code will restart the service and make it harder to kill it.

Maybe, you should consider using PARTIAL_WAKE_LOCK with your service and execute it in a process independently (:remote) if you want even more certainty (Maybe this is useless)

I would like to add a common error that is often followed, NEVER override the onBind and onUnbind method or overwrite the INTENT ACTION. This will cause your service to not be connected and never run onListenerConnected Keep the Intent as it is, in most cases you do not need to edit it.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...