我的Android进阶之旅------>android中service的onStartCommand()方法中intent为null的问题

简介:        今天在维护公司的一个APP的时候,突然爆了空指针异常,Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Intent.getBooleanExtra(java.lang.String, boolean)' on a null object reference        下面是报错的log。

       今天在维护公司的一个APP的时候,突然爆了空指针异常,

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Intent.getBooleanExtra(java.lang.String, boolean)' on a null object reference

       下面是报错的log。

D/AndroidRuntime( 4721): Shutting down VM
E/AndroidRuntime( 4721): FATAL EXCEPTION: main
E/AndroidRuntime( 4721): Process: com.tintele.sos, PID: 4721
E/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 reference
E/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 reference
E/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


     打印log后发现原来是在onStartCommand(Intent intent, int flags, int startId)方法中intent为null。这个错误是对onStartCommand()方法的flags参数没有深入理解造成的,报错的代码:

boolean groundAlarmFlag=intent.getBooleanExtra("flag", false);


      而这个flag参数是通过别处传过来的,代码如下:

Intent intent = new Intent(getBaseContext(), SosService.class);
intent.putExtra("flag", true);
startService(intent);

 

【报错原因】

       因此报错 intent的参数是null的原因是这个intent参数是通过startService(Intent)方法所传递过来的,但是如果Service在你的进程退出后有可能被系统自动重启,这个时候intent就会是null.
【解决方法】
        【方法一】在使用intent前需要判断一下是否为空。即:

boolean groundAlarmFlag = false;  
if (intent!=null) {
    groundAlarmFlag=intent.getBooleanExtra("flag", false);
}

        【方法二】

      将onStartCommand()方法的返回值从

return super.onStartCommand(intent, flags, startId);

      改成

return super.onStartCommand(intent, Service.START_REDELIVER_INTENT, startId);

因为onStartCommand方法的默认值START_STICKY_COMPATIBILITY或者START_STICKY不能保证intent不为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.
     * 
     * <p>For backwards compatibility, the default implementation calls
     * {@link #onStart} and returns either {@link #START_STICKY}
     * or {@link #START_STICKY_COMPATIBILITY}.
     * 
     * <p>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.  The <code>handleCommand</code> method is implemented by
     * you as appropriate:
     * 
     * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java
     *   start_compatibility}
     *
     * <p class="caution">Note that the system calls this 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 should always avoid stalling the main
     * thread's event loop.  When doing long-running operations,
     * network calls, or heavy disk I/O, you should kick off a new
     * thread, or use {@link android.os.AsyncTask}.</p>
     *
     * @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 previously returned anything
     * except {@link #START_STICKY_COMPATIBILITY}.
     * @param flags Additional data about this start request.  Currently either
     * 0, {@link #START_FLAG_REDELIVERY}, or {@link #START_FLAG_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 should
     * 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;
    }



==================================================================

下面具体讲解一下这几个flags的参数,首先参数有START_STICKY_COMPATIBILITY、

START_STICKY、START_NOT_STICKY、START_REDELIVER_INTENT四个。下面分别介绍一下,如下面表格所示:

START_STICKY        如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
START_NOT_STICKY      “非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。

START_REDELIVER_INTENT
      重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
START_STICKY_COMPATIBILITY

      START_STICKY的兼容版本,但不保证服务被kill后一定能重启。  

                                                                                                             



   源代码如下:

/**
     * 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.
     * 
     * <p>This mode makes sense for things that will be explicitly started
     * and stopped to run for arbitrary periods of time, such as a service
     * performing 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.
     * 
     * <p>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 explicit start themselves again later to do more work.  An
     * example of such a service would be one that polls for data from
     * a server: it could 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 its networking.  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 calls {@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 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;


 

 官方文档上的解释如下:

 

public static final int START_STICKY_COMPATIBILITY

 

Added in   API level 5

Constant to return from onStartCommand(Intent, int, int): compatibility version of START_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 from onStartCommand(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 call onStartCommand(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 performing background music playback.

Constant Value:  1 (0x00000001)
 

public static final int START_NOT_STICKY

Added in   API level 5

Constant to return from onStartCommand(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 call to Context.startService(Intent). The service will not receive a 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 explicit start themselves again later to do more work. An example of such a service would be one that polls for data from a server: it could schedule an alarm to poll every N minutes by having the alarm start its service. When its onStartCommand(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 from onStartCommand(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 again viaonStartCommand(Intent, int, int). This Intent will remain scheduled for redelivery until the service calls stopSelf(int) with the start ID provided toonStartCommand(Intent, int, int). The service will not receive a onStartCommand(Intent, int, int) call with a null Intent because it will 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 calling startService(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 calls onStart(Intent, int) and returns either START_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 older onStart(Intent, int) callback in that case. The 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.
@Override
public void onStart(Intent intent, int startId) {
    handleCommand(intent);
}

@Override
public 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 calls this 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 should always avoid stalling the main thread's event loop. When doing long-running operations, network calls, or heavy disk I/O, you should kick off a new thread, or use AsyncTask.

Parameters
intent The Intent supplied to startService(Intent), as given. This may be null if the service is being restarted after its process has gone away, and it had previously returned anything except START_STICKY_COMPATIBILITY.
flags Additional data about this start request. Currently either 0, START_FLAG_REDELIVERY, or START_FLAG_RETRY.
startId A unique integer representing this specific request to start. Use with stopSelfResult(int).
Returns
  • The return value indicates what semantics the system should use for the service's current started state. It may be one of the constants associated with theSTART_CONTINUATION_MASK bits.

 

 

====================================================================================

  作者:欧阳鹏  欢迎转载,与人分享是进步的源泉!

  转载请保留原文地址http://blog.csdn.net/ouyang_peng

====================================================================================




相关文章
|
11月前
|
Android开发 开发者
Android自定义view之利用drawArc方法实现动态效果
本文介绍了如何通过Android自定义View实现动态效果,重点使用`drawArc`方法完成圆弧动画。首先通过`onSizeChanged`进行测量,初始化画笔属性,设置圆弧相关参数。核心思路是不断改变圆弧扫过角度`sweepAngle`,并调用`invalidate()`刷新View以实现动态旋转效果。最后附上完整代码与效果图,帮助开发者快速理解并实践这一动画实现方式。
252 0
|
9月前
|
SQL Java 数据库连接
updateByPrimaryKeySelective()方法因字段为null导致的更新不成功问题解决办法
为了让这个解决方案更容易融入到现有系统中,其实现应该尽量简单且无缝,避免重复代码,并提高代码复用性。结合上述方法中提供的策略,应可以解决在使用 `updateByPrimaryKeySelective()`方法时因字段为null导致的更新不成功问题。请根据实际业务需求和上下文选择最合适的方案。这样的解决方案能够达到更佳的代码质量和维护性。
646 14
|
9月前
|
安全 数据库 Android开发
在Android开发中实现两个Intent跳转及数据交换的方法
总结上述内容,在Android开发中,Intent不仅是活动跳转的桥梁,也是两个活动之间进行数据交换的媒介。运用Intent传递数据时需注意数据类型、传输大小限制以及安全性问题的处理,以确保应用的健壯性和安全性。
592 11
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
832 15
Android 系统缓存扫描与清理方法分析
|
ARouter 测试技术 API
Android经典面试题之组件化原理、优缺点、实现方法?
本文介绍了组件化在Android开发中的应用,详细阐述了其原理、优缺点及实现方式,包括模块化、接口编程、依赖注入、路由机制等内容,并提供了具体代码示例。
439 2
|
Android开发
Android在rootdir根目录创建自定义目录和挂载点的方法
本文介绍了在Android高通平台的根目录下创建自定义目录和挂载点的方法,通过修改Android.mk文件并使用`LOCAL_POST_INSTALL_CMD`变量在编译过程中添加目录,最终在ramdisk.img的系统根路径下成功创建了`/factory/bin`目录。
959 1
|
开发工具 uml git
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
本文分享了下载AOSP源码的方法,包括如何使用repo工具和处理常见的repo sync错误,以及配置Python环境以确保顺利同步特定版本的AOSP代码。
3068 0
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
|
存储 大数据 数据库
Android经典面试题之Intent传递数据大小为什么限制是1M?
在 Android 中,使用 Intent 传递数据时存在约 1MB 的大小限制,这是由于 Binder 机制的事务缓冲区限制、Intent 的设计初衷以及内存消耗和性能问题所致。推荐使用文件存储、SharedPreferences、数据库存储或 ContentProvider 等方式传递大数据。
828 0
|
SQL 关系型数据库 数据处理
|
Android开发
【Android 进程保活】应用进程拉活 ( 系统 Service 机制拉活 | Service 组件 onStartCommand 方法分析 | 源码资源 )(三)
【Android 进程保活】应用进程拉活 ( 系统 Service 机制拉活 | Service 组件 onStartCommand 方法分析 | 源码资源 )(三)
564 0
【Android 进程保活】应用进程拉活 ( 系统 Service 机制拉活 | Service 组件 onStartCommand 方法分析 | 源码资源 )(三)

热门文章

最新文章

下一篇
开通oss服务