user8365522
user8365522

Reputation:

Android - why the app crash when the service receive a call and the app is closed?

I am making an app that make something happen when the phone gets a call, so after a lot of searching I discover that I can use a BroadcastReceiver and a Service so I created a Service called PhoneStateService:

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.telephony.TelephonyManager;
import android.widget.Toast;

public class PhoneStateService extends Service {

    private static BroadcastReceiver broadcastReceiver;

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

    @Override
    public void onCreate() {
        registerBroadcastReceiver();
    }

    @Override
    public void onDestroy() {
        unregisterReceiver(broadcastReceiver);
        broadcastReceiver = null;
    }

    private void registerBroadcastReceiver() {
        broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
                if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)){
                    new PhoneStateHandler().onIncomingCallStarted(context);
                }
            }
        };
        IntentFilter filter = new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        registerReceiver(broadcastReceiver, filter);
    }
}

This is the code for starting PhoneStateService(inside MainActivity):

if(PermissionChecker.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PermissionChecker.PERMISSION_GRANTED) {
        startService(new Intent(getApplicationContext(), PhoneStateService.class));
    }

part from the Manifest file:

<service android:name=".Service.PhoneStateService" />

When the phone gets a call and the app is running (it's still didn't Destroy) everything is working good but after I close the app and the phone gets a call the app crash and give me the message that the app has stop working.

please tell me what is the problem, I didn't find answer.

Edit:

The Exception:

09-11 10:26:30.598 29461-29461/? E/AndroidRuntime: FATAL EXCEPTION: main
                                               Process: com.multiplies.multiring, PID: 29461
                                               java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.SCREEN_OFF flg=0x50000010 } in com.multiplies.multiring.Service.PhoneStateService$1@1924f18
                                                   at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:891)
                                                   at android.os.Handler.handleCallback(Handler.java:739)
                                                   at android.os.Handler.dispatchMessage(Handler.java:95)
                                                   at android.os.Looper.loop(Looper.java:148)
                                                   at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                   at java.lang.reflect.Method.invoke(Native Method)
                                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
                                                Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.os.Bundle.getString(java.lang.String)' on a null object reference
                                                   at com.multiplies.multiring.Service.PhoneStateService$1.onReceive(PhoneStateService.java:36)
                                                   at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:881)
                                                   at android.os.Handler.handleCallback(Handler.java:739) 
                                                   at android.os.Handler.dispatchMessage(Handler.java:95) 
                                                   at android.os.Looper.loop(Looper.java:148) 
                                                   at android.app.ActivityThread.main(ActivityThread.java:5417) 
                                                   at java.lang.reflect.Method.invoke(Native Method) 
                                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
                                                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

Edit:

I did what some people said:

String stateStr = intent.getExtras() != null ? intent.getExtras().getString(TelephonyManager.EXTRA_STATE) : "";

put the this doesn't fix the problem. I thought it won't work because if the intent.getExtras() is returning null, then the if statement won't work because it's returning null and it's want TelephonyManager.EXTRA_STATE_RINGING:

if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)){
                new PhoneStateHandler().onIncomingCallStarted(context);
}

but thank you for your help.

HUGE EDIT:

part of the Manifest:

<service android:name=".PhoneState.PhoneStateService" />
    <receiver android:name=".PhoneState.PhoneStateBroadcast">
    <intent-filter>
        <action android:name="android.intent.action.PHONE_STATE" />
    </intent-filter>
    </receiver>

PhoneStateBroadcast:

    import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.util.Log;

public class PhoneStateBroadcast extends BroadcastReceiver {

    Context context;

    public void onReceive(Context context, Intent intent) {
        this.context = context;

        try {

            TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE);

            switch (telephonyManager.getCallState()) {

                case TelephonyManager.CALL_STATE_RINGING:
                    context.startService(new Intent(context, PhoneStateService.class));
                    break;
            }


        } catch (Exception e) {
            Log.e("Phone Receive Error", " " + e);
        }

    }
}

PhoneStateService:

    import android.app.IntentService;
import android.content.Intent;

public class PhoneStateService extends IntentService {

    public PhoneStateService(String name) {
        super(name);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        new PhoneStateHandler().onIncomingCallStarted(getApplicationContext());
    }
}

after this edit I am still getting crash.

Upvotes: 2

Views: 763

Answers (2)

abhi rathi
abhi rathi

Reputation: 59

instead of Running a service All the time, make it a BroadcastReciever which is fired whenever the call state is changed.(Running service for a long period of time is not a good practice) thus by using Broadcast receiver, your service would run exactly when you want.

public class PhoneStateService extends BroadcastReceiver{

       public void onReceive(Context context, Intent intent) {
            mContext = context;

                try {

                    TelephonyManager tm = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE);
                    String deviceId=tm.getDeviceId();

                    switch (tm.getCallState()) {

                        case TelephonyManager.CALL_STATE_RINGING:  // incoming call

                     //do something on Incoming call event

                            break;

                        case TelephonyManager.CALL_STATE_IDLE:  //call Ends

                             //do something on Idle phone state i.e set your logic if an incoming call is complete then this block would execute.


                    }


                } catch (Exception e) {
                    Log.e("Phone Receive Error", " " + e);
                }

        }


    }

Then add this broadcastReciever to your Manifest under application tag

  <receiver android:name="orbitsys.com.prospect_call.CallerState">
                <intent-filter>
                    <action android:name="android.intent.action.PHONE_STATE" />
                </intent-filter>

Upvotes: 2

Frank
Frank

Reputation: 12300

For some reason the extra's are empty. You are doing intent.getExtras().XXX but intent.getExtras() returns null, calling .XXX on it throws an error.

Changing

String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);

into

String stateStr = intent.getExtras() != null ? intent.getExtras().getString(TelephonyManager.EXTRA_STATE) : "";

will stop the crash from happening, but you might want to look into what the reason is why you expect extra's but there aren't any in the intent.

Upvotes: 3

Related Questions