我的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。
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
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.
public static final int START_STICKY
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.
public static final int START_NOT_STICKY
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.
public static final int START_REDELIVER_INTENT
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).
public int onStartCommand (Intent intent, int flags, int startId)
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 the
START_CONTINUATION_MASKbits.
See Also
====================================================================================
作者:欧阳鹏 欢迎转载,与人分享是进步的源泉!
转载请保留原文地址:http://blog.csdn.net/ouyang_peng
====================================================================================
我的Android进阶之旅------>android中service的onStartCommand()方法中intent为null的问题的更多相关文章
- 我的Android进阶之旅------>Android中查看应用签名信息
一.查看自己的证书签名信息 如上一篇文章<我的Android进阶之旅------>Android中制作和查看自定义的Debug版本Android签名证书>地址:http://blog ...
- 我的Android进阶之旅------> Android为TextView组件中显示的文本添加背景色
通过上一篇文章 我的Android进阶之旅------> Android在TextView中显示图片方法 (地址:http://blog.csdn.net/ouyang_peng/article ...
- 我的Android进阶之旅------> Android在TextView中显示图片方法
面试题:请说出Android SDK支持哪些方式显示富文本信息(不同颜色.大小.并包含图像的文本信息),并简要说明实现方法. 答案:Android SDK支持如下显示富文本信息的方式. 1.使用Tex ...
- 我的Android进阶之旅------>Android中AsyncTask源码分析
在我的<我的Android进阶之旅------>android异步加载图片显示,并且对图片进行缓存实例>文章中,先后使用了Handler和AsyncTask两种方式实现异步任务机制. ...
- 我的Android进阶之旅------> Android为TextView组件中显示的文本加入背景色
通过上一篇文章 我的Android进阶之旅------> Android在TextView中显示图片方法 (地址:http://blog.csdn.net/ouyang_peng/article ...
- 我的Android进阶之旅------>Android利用温度传感器实现带动画效果的电子温度计
要想实现带动画效果的电子温度计,需要以下几个知识点: 1.温度传感器相关知识. 2.ScaleAnimation动画相关知识,来进行水印刻度的缩放效果. 3.android:layout_weight ...
- 我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(三)Android客户端功能实现
我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(一)PC服务器端(地址:http://blog.csdn.net/ouyang_pen ...
- 我的Android进阶之旅------>Android疯狂连连看游戏的实现之实现游戏逻辑(五)
在上一篇<我的Android进阶之旅------>Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)>中提到的两个类: GameConf:负责管理游戏的 ...
- 我的Android进阶之旅------>Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)
正如在<我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型(三)>一文中看到的,在AbstractBoard的代码中,当程序需要创建N个Piec ...
随机推荐
- AspectJ 是什么
http://www.blogjava.net/hwpok/archive/2008/06/28/211312.html 1. 序 Aspect Oriented Programming (AOP)是 ...
- Spring核心项目及微服务架构方向
spring 顶级项目:Spring IO platform:用于系统部署,是可集成的,构建现代化应用的版本平台,具体来说当你使用maven dependency引入spring jar包时它就在工作 ...
- 在CMD中查看端口被什么程序占用
我们要查看端口被什么程序占用,可以使用下面方法.比如端口28848 1. 打开cmd,输入命令netstat -ano | findstr ":28848",显示结果如下,最后一个 ...
- pandas 绘图与滑窗
#import nessary library before start import pandas as pd import numpy as np import matplotlib.pyplot ...
- win10 在当前目录下 打开cmd
windows7 : 按住 shift 键 , 右键 就有该选项. windows10 : 运行下面的 注册表文件: 该注册表文件内容如下: Windows Registry Editor Versi ...
- go项目布局(摘录)
go的项目结构布局 或 包结构布局 这一块大家似乎还在摸索吧, 常用的应该还是类似于java的mvc布局, 但网上也有不同的布局方式,查阅github上的一些源码,也有大量的采用. 我把自己碰到的资料 ...
- iOS_绘制带删除线的Label
效果图例如以下: 一个带删除线的文本标签,继承自UILabel 自绘代码过程例如以下: 1,重写控件的drawRect方法 2,首先得到上下文对象 3,设置颜色,并指定是填充(Fill)模式还是笔刷( ...
- JavaScript之变量、作用域和内存问题
js中的变量可能包含2种数据类型,基础数据类型和引用数据类型. 一般而言,基本数据类型是数据段,引用数据类型是对象. 保存方式的不同: 基本类型可以直接操作保存在变量中的值:而引用类型真实的值是保存在 ...
- Unity3D - LINEAR INTERPOLATION
原文地址:http://unity3d.com/learn/tutorials/modules/beginner/scripting/linear-interpolation 水平有限,翻译粗略,欢迎 ...
- LeetCode459. Repeated Substring Pattern
Description Given a non-empty string check if it can be constructed by taking a substring of it and ...