shmakova
shmakova

Reputation: 6426

BroadcastReceiver receives events with delay after reboot

I try to receive PHONE_STATE intents with next BroadcastReceiver

<receiver android:name=".CallReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.PHONE_STATE" />
        <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

But after rebooting my Nexus 5X and making the call to this device, ringing events can be received after the call has been already finished a minute ago. How can I fix it? Any ideas?

Upvotes: 8

Views: 3920

Answers (6)

karanatwal.github.io
karanatwal.github.io

Reputation: 3673

According to CommonsWare in this answer-

There are many, many apps that want to get control at boot time. How quickly yours will get its turn will depend on many variables, such as the number of installed apps, the CPU speed of the device, the amount of system RAM on the device, etc.

Also, starting an activity from a BroadcastReceiver at boot time is fairly evil. If you want to be the first thing the user sees after a reboot, write a home screen implementation.

All you can do is give priority like this -

 <action android:name="android.intent.action.BOOT_COMPLETED" android:priority="999"/>

Upvotes: 2

Amani
Amani

Reputation: 3979

You can use foreground service and register your receiver in your foreground service instead of manifest. Using a foreground service may reduce delay as foreground service is more important than background service and registered receiver in a foreground service may be more important to OS than registered receiver in manifest as always your program is running and in foreground before phone state is changed.

Also i do not think ACTION_PHONE_STATE_CHANGED is an Ordered Broadcast as it could not be aborted by receiver thus using Priority which other answers suggest has no effect on it (priority is only for ordered broadcasts).

remove phone state receiver from manifest but keep your BOOT_COMPLETED receiver in manifest and start following service at boot complete

register receiver in onCreate of a Service:

   @Override
    public void onCreate() {
        super.onCreate();
        phoneStateReceiver = new PhoneStateReceiver();
        registerReceiver(phoneStateReceiver, new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED));
    }

unregister in onDestroy:

   @Override
    public void onDestroy() {
        unregisterReceiver(phoneStateReceiver);
        super.onDestroy();
    }

add a static method to your service to start service:

// start service even if your app is in stopped condition in android 8+
static void requestStart(@NonNull final Context context, @NonNull final String action){
        final Context appContext = context.getApplicationContext();
        Intent intent = new Intent(appContext, AppService.class);
        intent.setAction(action);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // this is required to start the service if there is 
            // no foreground process in your app and your app is
            // stopped in android 8 or above
            appContext.startForegroundService(intent);
        } else {
            appContext.startService(intent);
        }
    }

start foreground in your onStartCommand

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
         if(ACTION_START.equals(intent.getAction()))
           startForeground(ID, notification);
         else if(ACTION_STOP.equals(intent.getAction()))
           stopForeground(true);

         return START_STICKY;
}

Upvotes: 1

chaunv
chaunv

Reputation: 843

I'm thinking when you create Intent for send Broadcast, you miss set flag for intent. You need set tag FLAG_RECEIVER_FOREGROUND for your intent.

I don't see source code create Intent to sent Broadcast in this topic so I suggest a sample:

Intent intent = new Intent();
intent.setAction(...);
intent.setFlags(FLAG_RECEIVER_FOREGROUND);
...

You can see more at: https://developer.android.com/reference/android/content/Intent.html#FLAG_RECEIVER_FOREGROUND

EDIT:

I has just changed file AndroidManifest, you can try it:

<receiver android:name=".CallReceiver"
            android:enabled="true"
            android:exported="true"
            android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
            <intent-filter>
                <action android:name="android.intent.action.PHONE_STATE" />
                <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

Upvotes: 1

rds
rds

Reputation: 26994

ACTION_PHONE_STATE_CHANGED doesn't have the FLAG_RECEIVER_FOREGROUND flag, hence it runs in the background queue.

Hypothesis: On startup, there are often many applications which are listening to BOOT_COMPLETED (yes, that's a bad practice, but some people still do it, you should blame them) and as a result the background queue is quite busy. I'm not surprise that another background broadcast added in a busy queue takes a minute to be handled

You can confirm my hypothesis by looking in logcat for

ActivityManager: processNextBroadcast

As an alternative, you could register a listener on the phone log content provider.

Upvotes: 0

ROBOT
ROBOT

Reputation: 1

The value must be greater than -1000 and less than 1000. please,go through below link

http://developer.android.com/guide/topics/manifest/intent-filter-element.html

Upvotes: 0

HelloCsl
HelloCsl

Reputation: 221

this because there any other Receiver listen to this broadcast, you can try to improve you Recevier' priority just like that

<intent-filter android:priority="2147483647">  
<action android:name="android.intent.action.BOOT_COMPLETED" />  
</intent-filter>

Upvotes: 2

Related Questions