Search code examples
androidservicebroadcastreceiver

How Manage Broadcast Receivers in Services


I'm writting an app that its main goal is starts TuneIn player when my device is conected to AC. The first version used only broadcast receivers and it works well, except for the normal behavior of android OS discarding receivers once fired, because, i'm looking for something more permanent I'm trying to use a service to maintain the broadcast receiver active, but I'm getting some errors that I can't understand.

So in what way it's possible use broadcast receivers inside a service?

I'm putting one error Log, and part of my code.

Errors:

07-19 08:03:27.019: ERROR/AndroidRuntime(15785): FATAL EXCEPTION: main
        java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.BATTERY_CHANGED flg=0x60000000 (has extras) } in com.upm.radioC.Servicio$1@407a0420
        at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:722)
        at android.os.Handler.handleCallback(Handler.java:587)
        at android.os.Handler.dispatchMessage(Handler.java:92)
        at android.os.Looper.loop(Looper.java:130)
        at android.app.ActivityThread.main(ActivityThread.java:3683)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:507)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:895)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:653)
        at dalvik.system.NativeStart.main(Native Method)
        Caused by: java.lang.IllegalStateException: System services not available to Activities before onCreate()
        at android.app.Activity.getSystemService(Activity.java:3536)
        at com.upm.radioC.Tools.checkData(Tools.java:26)
        at com.upm.radioC.Servicio$1.onReceive(Servicio.java:60)
        at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:709)

Main Class

public class Inicio extends Activity {
  @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);}

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflador = getMenuInflater();
        inflador.inflate(R.menu.menu, menu);
        return true;
    }

    @Override
    public boolean onMenuItemSelected(int featureId, MenuItem opcion) {
        TextView btn = (TextView) findViewById(R.id.txtEtiqueta);
        Intent svc = new Intent(this, Servicio.class);
        switch (opcion.getItemId()) {
            case R.id.mnuRegistra:
                startService(svc);
                btn.setText("Monitoreo Iniciado");
                break;
            case R.id.mnuLibera:
                stopService(svc);
                btn.setText("Monitoreo Detenido");
                break;
        }
        return super.onMenuItemSelected(featureId, opcion);
    }
}

Service Class

public class Servicio extends Service {

    private BroadcastReceiver receiver;
    private IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
    private Tools NetWork = new Tools(); //Custom Class for activate/deactivate GSM data

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

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

    @Override
    public int onStartCommand(Intent i, int flags, int startID) {
        _startService();
        return START_STICKY; }

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

    private void _startService() {
        receiver = new BroadcastReceiver() {
            public void onReceive(Context context, Intent intent) {
                int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
                if (plugged == BatteryManager.BATTERY_PLUGGED_USB) {
                    Toast.makeText(getApplicationContext(), "Conectado a USB", Toast.LENGTH_LONG).show();                    
                }else if (plugged == BatteryManager.BATTERY_PLUGGED_AC) {
                    if (!NetWork.checkData()) try {
                        NetWork.turnData(true);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    Intent LaunchIntent = getPackageManager().getLaunchIntentForPackage("tunein.player");
                    startActivity(LaunchIntent);
                    Toast.makeText(getApplicationContext(), "Conectado a AC", Toast.LENGTH_LONG).show();
                } else {
                    if (NetWork.checkData()) try {
                        NetWork.turnData(false);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    Toast.makeText(getApplicationContext(), "Desconectado de las fuentes de poder", Toast.LENGTH_LONG).show();
                }
            }
        };
        registerReceiver(receiver, filter);
    }

    private void _shutdownService() {
        unregisterReceiver(receiver);}

}

Thanks in advance!


Solution

  • Looks like it has got something to do with the context in which you are calling getSystemService. Try passing the service context to the Tools class, and then use that context for calling getSystemService.

    Create Tools instance in onCreate of Servicio

    private Tools NetWork = null;
    
    @Override
    public void onCreate() {
        super.onCreate();
        Network = new Tools(this);
    }
    

    And then in your Tools class store this incoming Context in a private variable (say mContext) and use that in the methods of that class.

    boolean checkData() { 
        ConnectivityManager connManager = (ConnectivityManager) mContext.getSystemService(CONNECTIVITY_SERVICE); 
        NetworkInfo mMobile = connManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
        return mMobile.isConnected();
    }
    

    EDIT:

    For understanding Context, you can refer to below references

    1. demystifyind context

    2. Context, What Context