Home > Software design >  Android Broadcast not triggering Receiver
Android Broadcast not triggering Receiver

Time:05-25

I've been trying to figure out this bug for days...

Issue: sendBroadcast(intent) isn't triggering BroadcastReceiver.

My code successfully starts a foreground service... This is supposed to broadcast to a receiver in an activity, but the intent never makes it to the Receiver.

I've tried writing the code out exactly as the examples are given in the documentation, and even copied code from earlier posts here, but nothing has worked.


My manifest file:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.julescarboni.speedcamerawarning">

    <!-- Request permissions  -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.SpeedCameraWarning"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:theme="@style/Theme.SpeedCameraWarning.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <!-- Mention the Location Service here -->
        <service android:name=".LocationService"
            android:foregroundServiceType="location"
            android:enabled="true" />
        <receiver android:name=".ProcessActivity$LocationReceiver"
            android:exported="true">
            <intent-filter>
                <!-- Sample filter to listen when device boot is completed -->
                <!-- This type of receiver cant be declared in codes -->
                <action android:name="com.julescarboni.speedcamerawarning.LocationService" />
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </receiver>

    </application>

</manifest>

The service that's broadcasting:

public class LocationService extends Service {

    public static final String INTENT_ID = "com.julescarboni.speedcamerawarning.LocationService";
    private static final int ONGOING_NOTIFICATION_ID = 1;
    public static final String CHANNEL_ID = "ForegroundServiceChannel";
    //private final Context context = getApplicationContext();
    private Timer timer = new Timer(); // Timer for the service to use
    public static final int SERVICE_INTERVAL = 1000; // TODO: Set to 10 seconds

    /*@Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        startService();
    }*/

    @Override
    public void onCreate() {
        super.onCreate();
    }

    // Execution of service will start on calling this method
    public int onStartCommand(Intent intent, int flags, int startId) {

        // Create foreground service notification
        // TODO: Add icon to notification

        String input = intent.getStringExtra("inputExtra");
        createNotificationChannel();
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,
                0, notificationIntent, 0);
        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("Foreground Service")
                .setContentText(input)
                .setSmallIcon(R.drawable.ic_launcher_foreground)
                .setContentIntent(pendingIntent)
                .build();
        startForeground(1, notification);

        // Activate timer with location getting task
        timer.scheduleAtFixedRate(new ProcessTrigger(), 0, SERVICE_INTERVAL);

        // Return status of the service
        return START_NOT_STICKY;
    }

    @Override
    // Execution of the service will stop on calling this method
    public void onDestroy() {
        super.onDestroy();

        // Stop the timer and task
        timer.cancel();
        timer = null;

        // Stop the process
        stopForeground(true);
    }

    // This is what the service actually runs
    // It simply sends a signal that it is time to run the process code

    private class ProcessTrigger extends TimerTask {
        @Override
        public void run() {
            // This is the process we do every time the timer triggers
            Log.d("LocationService", "Timer triggered");
            Intent intent = new Intent();
            intent.setAction(INTENT_ID);
            //intent.putExtra("data", "null");
            sendBroadcast(intent);
        }
    }

    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void createNotificationChannel() {
        // Create notification channel for foreground service notifications
        // Create the NotificationChannel, but only on API 26  because
        // the NotificationChannel class is new and not in the support library

        // Build API level must be 26 or greater (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O).
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel serviceChannel = new NotificationChannel(
                    CHANNEL_ID,
                    "Foreground Service Channel",
                    NotificationManager.IMPORTANCE_DEFAULT
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(serviceChannel);
        }
    }
}

The activity with the receiver:

public class ProcessActivity extends AppCompatActivity {

    LocationReceiver locationReceiver = null;
    Boolean myReceiverIsRegistered = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        locationReceiver = new LocationReceiver();
        // Register receiver
        registerReceiver(locationReceiver, new IntentFilter(LocationService.INTENT_ID));
        myReceiverIsRegistered = true;
    }
    @Override
    protected void onResume() {
        super.onResume();
        /*if (!myReceiverIsRegistered) {
            registerReceiver(locationReceiver, new IntentFilter(LocationService.INTENT_ID));
            myReceiverIsRegistered = true;
        }*/
    }
    @Override
    protected void onPause() {
        super.onPause();
        /*if (myReceiverIsRegistered) {
            unregisterReceiver(locationReceiver);
            myReceiverIsRegistered = false;
        }*/
    }

    private void doProcess() {

        // THIS CODE HERE HAS BEEN REMOVED TO KEEP THIS SECTION CONCISE.
        // SEE BELOW FOR THIS doProcess() FUNCTION.
        // Its main purpose is to get the last known location from a fused location manager.

    }

    public static class LocationReceiver extends BroadcastReceiver {
        // RECEIVES TIMER TRIGGERS FROM LOCATION SERVICE

        // Create new instance of the process activity
        // This instance contains all the code that we need to run each time the timer is triggered
        // I.e. it is the foreground process code
        ProcessActivity processActivity = new ProcessActivity();

        @Override
        public void onReceive(Context context, Intent intent ) {
            Log.d("LocationReceiver", "Trigger received, calling process now");
            processActivity.doProcess();
        }
    }

}

The doProcess() function from the activity has so far never been called because the reciever has never been triggered, so I removed it to make the question more concise (if it's important, I'll add it into the question).

CodePudding user response:

First of all if you delcared receiver in manifest you don't need to create instance and register it programatically, because.

The system package manager registers the receiver when the app is installed. The receiver then becomes a separate entry point into your app which means that the system can start the app and deliver the broadcast if the app is not currently running.

The system creates a new BroadcastReceiver component object to handle each broadcast that it receives. This object is valid only for the duration of the call to onReceive(Context, Intent). Once your code returns from this method, the system considers the component no longer active. https://developer.android.com/guide/components/broadcasts#manifest-declared-receivers 2) For what purposes do you use this line inside of IntentFilter tag:

3)This line should not be existed:

ProcessActivity processActivity = new ProcessActivity();

You cant just create an object of activity, because it's a system component and it's creating instance of the activity.

try to check logs after fixes.

CodePudding user response:

I suggest you eat sausage and make this line not be exist :

ProcessActivity processActivity = new ProcessActivity();

  • Related