fouadalnoor
fouadalnoor

Reputation: 217

Service does not run from BroadcastReceiver? - Android

I am trying to get my service to run when there is an outgoing call on my phone. But for some reason my service does not run when this happens. I know the code for the "CallReceiver" executes since I used a toast message to display if that runs. I am able to run the service through my main activity, but this means it will run regardless of whether an outgoing call is made....

Below is my code:

The Receiver:

package com.example.hiworld;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;

public class CallReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        context.startService(new Intent(context, CallService.class));

        Toast.makeText(context, "Call Receiver started",
                Toast.LENGTH_LONG).show();

        Log.d("Calling Someone", "onReceived");

    }


}

The Service:

package com.example.hiworld;


import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.widget.Toast;

public class CallService extends IntentService  {

    public long StartTime=0;
    public long EndTime =0; 
    public long TotalTime = 0; 
    public long NumFreeMins = 0;


    public CallService() {
          super("CallService");
      }

    @Override
    protected void onHandleIntent(Intent intent) {


        StartTime = (System.currentTimeMillis())/60;

        TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);




            if(tm.getCallState()==0) //getting the time whenever the phone is off 
            {

                EndTime = (System.currentTimeMillis())/60;
                TotalTime = EndTime-StartTime;
                 NumFreeMins = 300-TotalTime; 

                 //notify user
                 this.displaymsg();

            }   



    }

public void displaymsg()
{
    Toast toast = Toast.makeText(getApplicationContext(), ""+NumFreeMins, Toast.LENGTH_SHORT);
    toast.show();
}
}

I have seen some people use the line:

context.startService(new Intent(this, CallService.class));

instead of:

context.startService(new Intent(context, CallService.class));

but the latter does not work for me...

Upvotes: 1

Views: 1486

Answers (2)

Squonk
Squonk

Reputation: 48871

Try specifying an <intent-filter> for your IntentService in the manifest for a specific 'action'. Example...

<service
    android:name=".CallService" >
    <intent-filter>
        <action android:name="com.example.hiworld.intent.DO_SOMETHING" />
    </intent-filter>
</service>

Then in the onReceive(...) method of your BroadcastReceiver do something like the following...

Intent callReceiverIntent = new Intent("com.example.hiworld.intent.DO_SOMETHING");

// Put the Intent received by the BroadcastReceiver as extras so the
// IntentService can process it...
callReceiverIntent.putExtras(intent);

context.startService(callReceiverIntent);

EDIT:

I built a simple test app based on the code you posted to pasrebin. I kept the code identical for the manifest, receiver and service and simply had to add a default Activity in order to get it to run.

I can see from monitoring logcat in the DDMS perspective of eclipse that the CallReceiver successfully receives the NEW_OUTGOING_CALL Intent and does, in fact, start the CallService.

The problem is, however, with attempting to show a Toast from an IntentService which causes an exception due to a 'leaked handler' and silently crashes.

The reason behind this is that an IntentService uses a background thread to carry out its work and trying to show the Toast (i.e., a UI element) from a non-UI thread won't work as the app has no UI components running. So, regardless of whether you use the local context variable or getApplicationContext(), there simply is no UI context with which to associate the Toast.

The reason why it works when starting the CallService from an Activity is obviously because the Activity provides a UI context that can be used by the Toast. In short, it generally seems that attempting to use Toast from an IntentService isn't a good idea unless the IntentService is always started by a UI component and even then, having a background thread create UI elements (such as a Toast) may cause problems.

The only way that this can be made to work with the current model is to change the IntentService to a Service. By default, code execution of a Service is done on the main (UI) thread and it is quite legal for a Service to show a Toast regardless of whether there are any of the app's Activities showing or not. In fact, I modified the code to use a Service and placed the code from onHandleIntent in onStartCommand() and I can see the Toasts when making an outgoing call.

Upvotes: 1

Salil Pandit
Salil Pandit

Reputation: 1498

Try

context.startService(new Intent(context.getApplicationContext(), CallService.class));

Upvotes: 0

Related Questions