My Android advanced tutorial ------) the intent in the onStartCommand () method of service in android is null
Today, when I was maintaining a company APP, a null pointer suddenly went wrong,
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Intent.getBooleanExtra(java.lang.String, boolean)' on a null object reference
The following is the error log.
D/AndroidRuntime( 4721): Shutting down VME/AndroidRuntime( 4721): FATAL EXCEPTION: mainE/AndroidRuntime( 4721): Process: com.tintele.sos, PID: 4721E/AndroidRuntime( 4721): java.lang.RuntimeException: Unable to start service com.tintele.sos.SosService@36087165 with null: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Intent.getBooleanExtra(java.lang.String, boolean)' on a null object referenceE/AndroidRuntime( 4721): at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3152)E/AndroidRuntime( 4721): at android.app.ActivityThread.access$2100(ActivityThread.java:178)E/AndroidRuntime( 4721): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1568)E/AndroidRuntime( 4721): at android.os.Handler.dispatchMessage(Handler.java:111)E/AndroidRuntime( 4721): at android.os.Looper.loop(Looper.java:194)E/AndroidRuntime( 4721): at android.app.ActivityThread.main(ActivityThread.java:5637)E/AndroidRuntime( 4721): at java.lang.reflect.Method.invoke(Native Method)E/AndroidRuntime( 4721): at java.lang.reflect.Method.invoke(Method.java:372)E/AndroidRuntime( 4721): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:959)E/AndroidRuntime( 4721): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:754)E/AndroidRuntime( 4721): Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Intent.getBooleanExtra(java.lang.String, boolean)' on a null object referenceE/AndroidRuntime( 4721): at com.tintele.sos.SosService.onStartCommand(SosService.java:309)E/AndroidRuntime( 4721): at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3135)E/AndroidRuntime( 4721): ... 9 more
Print the log and find that the Intent is null in the onStartCommand (intent, int flags, int startId) method. This error is caused by a lack of in-depth understanding of the flags parameter of the onStartCommand () method. The error code is as follows:
boolean groundAlarmFlag=intent.getBooleanExtra(flag, false);
The flag parameter is passed elsewhere. The Code is as follows:
Intent intent = new Intent(getBaseContext(), SosService.class);intent.putExtra(flag, true);startService(intent);
[Error cause]
Therefore, the intent parameter is null because the intent parameter is passed through the startService (Intent) method. However, if the Service exits, it may be automatically restarted by the system, in this case, intent will be null.
[Solution]
[Method 1] determine whether intent is null before using intent. That is:
boolean groundAlarmFlag = false; if (intent!=null) { groundAlarmFlag=intent.getBooleanExtra(flag, false);}
Method 2]
Returns the value of the onStartCommand () method from
return super.onStartCommand(intent, flags, startId);
Change
return super.onStartCommand(intent, Service.START_REDELIVER_INTENT, startId);
The default value of the onStartCommand method is START_STICKY_COMPATIBILITY or START_STICKY. intent cannot be null.
/** * Called by the system every time a client explicitly starts the service by calling * {@link android.content.Context#startService}, providing the arguments it supplied and a * unique integer token representing the start request. Do not call this method directly. * *
For backwards compatibility, the default implementation CILS * {@ link # onStart} and returns either {@ link # START_STICKY} * or {@ link # START_STICKY_COMPATIBILITY }.**
If you need your application to run on platform versions prior to API * level 5, you can use the following model to handle the older {@ link # onStart} * callback in that case.handleCommand
Method is implemented by * you as appropriate: ** {@ sample development/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService. java * start_compatibility }**
Note that the system callthis on your * service's main thread. A service's main thread is the same * thread where UI operations take place for Activities running in the * same process. you shoshould always avoid stalling the main * thread's event loop. when doing long-running operations, * network cals, or heavy disk I/O, you shoshould kick off a new * thread, or use {@ link android. OS. asyncTask }.
** @ Param intent The Intent supplied to {@ link android. content. context # startService}, * as given. this may be null if the service is being restarted after * its process has gone away, and it had previusly returned anything * handle t {@ link # START_STICKY_COMPATIBILITY }. * @ param flags Additional data about this start request. currently either * 0, {@ link # START_FLAG_REDELIVERY}, or {@ link # START_FL AG_RETRY }. * @ param startId A unique integer representing this specific request to * start. use with {@ link # stopSelfResult (int )}. ** @ return The return value indicates what semantics the system shoshould * use for the service's current started state. it may be one of the * constants associated with the {@ link # START_CONTINUATION_MASK} bits. ** @ see # stopSelfResult (int) */public int onStartCommand (Intent intent, int flags, int startId) {onStart (intent, startId); return mStartCompatibility? START_STICKY_COMPATIBILITY: START_STICKY ;}
========================================================== ======================================
The following are some examples.FlagsParameters: START_STICKY_COMPATIBILITY,
START_STICKY, START_NOT_STICKY, and START_REDELIVER_INTENT. The following table describes how to create an ECS instance:
START_STICKY |
If the service process is killed, the service State is retained to the starting state, but the intent object to be delivered is not retained. Then the system will try to re-create the service. Because the service status is starting, the onStartCommand (Intent, int, int) method will be called after the service is created. If no startup command is passed to service during this period, the Intent parameter is null. |
START_NOT_STICKY |
Non-viscous ". When this return value is used, if the service is kill abnormally after onStartCommand is executed, the system will not automatically restart the service. |
START_REDELIVER_INTENT |
Intent. When this return value is used, if the service is kill abnormally after onStartCommand is executed, the system automatically restarts the service and passes in the Intent value. |
START_STICKY_COMPATIBILITY |
START_STICKY compatible version, but it is not guaranteed that the service will be restarted after it is killed. |
The source code is as follows:
/** * Constant to return from {@link #onStartCommand}: compatibility * version of {@link #START_STICKY} that does not guarantee that * {@link #onStartCommand} will be called again after being killed. */ public static final int START_STICKY_COMPATIBILITY = 0; /** * Constant to return from {@link #onStartCommand}: if this service's * process is killed while it is started (after returning from * {@link #onStartCommand}), then leave it in the started state but * don't retain this delivered intent. Later the system will try to * re-create the service. Because it is in the started state, it will * guarantee to call {@link #onStartCommand} after creating the new * service instance; if there are not any pending start commands to be * delivered to the service, it will be called with a null intent * object, so you must take care to check for this. * *
This mode makes sense for things that will be explicitly started * and stopped to run for arbitrary periods of time, such as a service * specify Ming background music playback. */public static final int START_STICKY = 1;/*** Constant to return from {@ link # onStartCommand }: if this service's * process is killed while it is started (after returning from * {@ link # onStartCommand}), and there are no new start intents to * deliver to it, then take the service out of the started state and * don't recreate until a future explicit call to * {@ link Context # startService Context. startService (Intent )}. the * service will not receive a {@ link # onStartCommand (Intent, int, int )} * call with a null Intent because it will not be re-started if there * are no pending Intents to deliver. **
This mode makes sense for things that want to do some work as a * result of being started, but can be stopped when under memory pressure * and will explain it start themselves again later to do more work. an * example of such a service wocould be one that polls for data from * a server: it cocould schedule an alarm to poll every N minutes by having * the alarm start its service. when its {@ link # onStartCommand} is * called from the alarm, it schedules a new alarm for N minutes later, * and spawns a thread to do networkits ing. if its process is killed * while doing that check, the service will not be restarted until the * alarm goes off. */public static final int START_NOT_STICKY = 2;/*** Constant to return from {@ link # onStartCommand }: if this service's * process is killed while it is started (after returning from * {@ link # onStartCommand }), then it will be scheduled for a restart * and the last delivered Intent re-delivered to it again via * {@ link # onStartCommand }. this Intent will remain scheduled for * redelivery until the service CILS {@ link # stopSelf (int)} with the * start ID provided to {@ link # onStartCommand }. the * service will not receive a {@ link # onStartCommand (Intent, int, int )} * call with a null Intent because it will only be re-started if * it is not finished processing all Intents sent to it (and any such * pending events will be delivered at the point of restart ). */public static final int START_REDELIVER_INTENT = 3;
The official documents are described as follows:
Public static final int START_STICKY_COMPATIBILITY
Added in API level 5
Constant to return fromonStartCommand(Intent, int, int)
: Compatibility versionSTART_STICKY
That does not guarantee thatonStartCommand(Intent, int, int)
Will be called again after being killed.
Constant Value: 0 (0x00000000)
Public static final int START_STICKY
Added in API level 5
Constant to return fromonStartCommand(Intent, int, int)
: If this service's process is killed while it is started (after returning fromonStartCommand(Intent, int, int)
), Then leave it in the started state but don't retain this delivered intent. later the system will try to re-create the service. because it is in the started state, it will guarantee to callonStartCommand(Intent, int, int)
After creating the new service instance; if there are not any pending start commands to be delivered to the service, it will be called with a null intent object, so you must take care to check for this.
This mode makes sense for things that will be explicitly started and stopped to run for arbitrary periods of time, such as a service discovery Ming background music playback.
Constant Value: 1 (0x00000001) public static final int START_NOT_STICKYAdded in API level 5
Constant to return fromonStartCommand(Intent, int, int)
: If this service's process is killed while it is started (after returning fromonStartCommand(Intent, int, int)
), And there are no new start intents to deliver to it, then take the service out of the started state and don't recreate until a future explicit callContext.startService(Intent)
. The service will not receiveonStartCommand(Intent, int, int)
Call with a null Intent because it will not be re-started if there are no pending Intents to deliver.
This mode makes sense for things that want to do some work as a result of being started, but can be stopped when under memory pressure and will explain it start themselves again later to do more work. an example of such a service wocould be one that polls for data from a server: it cocould schedule an alarm to poll every N minutes by having the alarm start its service. when itsonStartCommand(Intent, int, int)
Is called from the alarm, it schedules a new alarm for N minutes later, and spawns a thread to do its networking. if its process is killed while doing that check, the service will not be restarted until the alarm goes off.
Constant Value: 2 (0x00000002) public static final int START_REDELIVER_INTENT
Added in API level 5
Constant to return fromonStartCommand(Intent, int, int)
: If this service's process is killed while it is started (after returning fromonStartCommand(Intent, int, int)
), Then it will be scheduled for a restart and the last delivered Intent re-delivered to it againonStartCommand(Intent, int, int)
. This Intent will remain scheduled for redelivery until the service CILSstopSelf(int)
With the start ID providedonStartCommand(Intent, int, int)
. The service will not receiveonStartCommand(Intent, int, int)
Call with a null Intent because it will only be re-started if it is not finished processing all Intents sent to it (and any such pending events will be delivered at the point of restart).
Constant Value: 3 (0x00000003)
Public int onStartCommand (Intent intent, int flags, int startId)
Added in API level 5
Called by the system every time a client explicitly starts the service by callingstartService(Intent)
, Providing the arguments it supplied and a unique integer token representing the start request. Do not call this method directly.
For backwards compatibility, the default implementation CILSonStart(Intent, int)
And returns eitherSTART_STICKY
OrSTART_STICKY_COMPATIBILITY
.
If you need your application to run on platform versions prior to API level 5, you can use the following model to handle the olderonStart(Intent, int)
Callback in that case.handleCommand
Method is implemented by you as appropriate:
// This is the old onStart method that will be called on the pre-2.0// platform. On 2.0 or later we override onStartCommand() so this// method will not be called.@Overridepublic void onStart(Intent intent, int startId) { handleCommand(intent);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) { handleCommand(intent); // We want this service to continue running until it is explicitly // stopped, so return sticky. return START_STICKY;}
Note that the system callthis on your service's main thread. A service's main thread is the same thread where UI operations take place for Activities running in the same process. you shoshould always avoid stalling the main thread's event loop. when doing long-running operations, network CILS, or heavy disk I/O, you shoshould kick off a new thread, or useAsyncTask
.
Parameters
Intent |
The Intent suppliedstartService(Intent) , As given. This may be null if the service is being restarted after its process has gone away, and it had previusly returned anything else tSTART_STICKY_COMPATIBILITY . |
Flags |
Additional data about this start request. Currently either 0,START_FLAG_REDELIVERY , OrSTART_FLAG_RETRY . |
StartId |
A unique integer representing this specific request to start. UsestopSelfResult(int) . |
Returns
- The return value indicates what semantics the system shocould use for the service's current started state. It may be one of the constants associated with
START_CONTINUATION_MASK
Bits. See Also