androidandroid-broadcastreceiver

Send a broadcast to an Activity that is not in the foreground


I have a background service that has a CountdownTimer. As the CountdownTimer counts down i send a broadcast to an Activity. When the CountdownTimer has counted down then the Activity is alerted and i can stop the service and unregister the receiver.

I have moved the normal receiver unregistering method from onStop and onPause into my own method that i call once a broadcast is received with "timer_finished". This is so i can move away from the Activity without unregistering.

Everything works fine if the user is currently viewing the Activity. If the user moves away from the Activity, the CoundownTimer is still running but the Activity is not receiving the broadcasts.

How can I do this so that the Activity receives the final broadcast "timer_finished"?

public class CountDownBroadcastService extends Service {

    private static final String TAG = CountDownBroadcastService.class.getSimpleName();

    public static final String COUNTDOWN_BR = "com.carefreegroup.rr3.countdown_br";
    Intent bi = new Intent(COUNTDOWN_BR);

    CountDownTimer cdt = null;
    Context mContext;

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

            mContext = this;

            Log.i(TAG, "Starting timer...");


            cdt = new CountDownTimer(10000, 1000) {
                @Override
                public void onTick(long millisUntilFinished) {

                    Log.i(TAG, "Countdown seconds remaining: " + millisUntilFinished / 1000);
                    bi.putExtra("countdown", millisUntilFinished);
                    bi.putExtra("timer_status", "timer_not_finished");
                    sendBroadcast(bi);
                }

                @Override
                public void onFinish() {
                    Log.i(TAG, "Timer finished");

                    bi.putExtra("timer_status", "timer_finished");


                    sendBroadcast(bi);

                }
            };

            cdt.start();
        }

        @Override
        public void onDestroy() {

            cdt.cancel();
            Log.i(TAG, "Timer cancelled");
            super.onDestroy();
        }

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {       
            return super.onStartCommand(intent, flags, startId);
        }

        @Override
        public IBinder onBind(Intent arg0) {       
            return null;
        }
}

.

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e(TAG, "start of oncreate");

        setContentView(R.layout.loneworker);

        getSupportActionBar().setDisplayShowHomeEnabled(true);
        getSupportActionBar().setIcon(R.drawable.ic_launcher);
        setTitle("Lone Worker");
        nfcscannerapplication = (NfcScannerApplication) getApplication();
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        tvCountDown = (TextView)findViewById(R.id.tvloneworkercountdown);
        callFinished = (Button)findViewById(R.id.buttonlwcallfinished);


        callFinished.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {

                Log.e(TAG, "inside callFinished");
                //maybe alert carer is safe***************************************

                setCountDownFinished();

            }
        });




        startService(new Intent(this, CountDownBroadcastService.class));
        Log.i(TAG, "Started service");






    }//end of onCreate



    private BroadcastReceiver br = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {            
            updateGUI(intent); // or whatever method used to update your GUI fields
        }
    };


    public void onResume() {
        super.onResume();        
        registerReceiver(br, new IntentFilter(CountDownBroadcastService.COUNTDOWN_BR));
        Log.i(TAG, "Registered broacast receiver");
        }



    private void updateGUI(Intent intent) {
        if (intent.getExtras() != null) {
            long millisUntilFinished = intent.getLongExtra("countdown", 0);
            //Log.i(TAG, "Countdown seconds remaining: " +  millisUntilFinished / 1000);    

            String status = intent.getStringExtra("timer_status");

            if(status.equalsIgnoreCase("timer_not_finished")){

                    tvCountDown.setText("Countdown seconds remaining: " +  millisUntilFinished / 1000);

            }else if(status.equalsIgnoreCase("timer_finished")){

                setCountDownFinished();
            }
        }
    }//end of updateGUI


    public void setCountDownFinished(){

        tvCountDown.setText("0");
        unregisterReceiver(br);
        Log.i(TAG, "Unregistered broacast receiver");

        stopService(new Intent(this, CountDownBroadcastService.class));
        Log.e(TAG, "Stopped CountDownBroadcastService");

    }// end of setCountDownFinished()




}

Solution

  • When you register a broadcast receiver programmatically in an activity, it will not get broadcasts when the activity is paused. The BroadcastReceiver docs are not as clear as they could be on this point. They recommend unregistering on onPause solely to reduce system overhead. If you want to receive events even when your activity is not in the foreground, register the receiver in your manifest using the receiver element.