第一话地址:http://blog.csdn.net/programmersun/article/details/9849835
//本文会持续更新,希望大家能提出项目中遇到的问题和自己的观点与大家分享,让大家少走弯路。
//注意:提出的内容需要以 观点/问题--->原因--->解决方案--->扩展的方式编写
观点:service可能会被系统杀掉,如何使他长时间活着呢?
原因:一个service默认是background的,这意味着当系统资源紧缺的时候,系统可能会杀掉service以此获取更多的资源空间。
解决方案:
1)在api level 5 之后可以使用startForeground去将service设置成foreground
在api level 5之前可以使用以下代码去达到同样效果
private static final Class<?>[] mSetForegroundSignature = new Class[] {
boolean.class};
private static final Class<?>[] mStartForegroundSignature = new Class[] {
int.class, Notification.class};
private static final Class<?>[] mStopForegroundSignature = new Class[] {
boolean.class};
private NotificationManager mNM;
private Method mSetForeground;
private Method mStartForeground;
private Method mStopForeground;
private Object[] mSetForegroundArgs = new Object[1];
private Object[] mStartForegroundArgs = new Object[2];
private Object[] mStopForegroundArgs = new Object[1];
void invokeMethod(Method method, Object[] args) {
try {
method.invoke(this, args);
} catch (InvocationTargetException e) {
// Should not happen.
Log.w("ApiDemos", "Unable to invoke method", e);
} catch (IllegalAccessException e) {
// Should not happen.
Log.w("ApiDemos", "Unable to invoke method", e);
}
}
/**
* This is a wrapper around the new startForeground method, using the older
* APIs if it is not available.
*/
void startForegroundCompat(int id, Notification notification) {
// If we have the new startForeground API, then use it.
if (mStartForeground != null) {
mStartForegroundArgs[0] = Integer.valueOf(id);
mStartForegroundArgs[1] = notification;
invokeMethod(mStartForeground, mStartForegroundArgs);
return;
}
// Fall back on the old API.
mSetForegroundArgs[0] = Boolean.TRUE;
invokeMethod(mSetForeground, mSetForegroundArgs);
mNM.notify(id, notification);
}
/**
* This is a wrapper around the new stopForeground method, using the older
* APIs if it is not available.
*/
void stopForegroundCompat(int id) {
// If we have the new stopForeground API, then use it.
if (mStopForeground != null) {
mStopForegroundArgs[0] = Boolean.TRUE;
invokeMethod(mStopForeground, mStopForegroundArgs);
return;
}
// Fall back on the old API. Note to cancel BEFORE changing the
// foreground state, since we could be killed at that point.
mNM.cancel(id);
mSetForegroundArgs[0] = Boolean.FALSE;
invokeMethod(mSetForeground, mSetForegroundArgs);
}
@Override
public void onCreate() {
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
try {
mStartForeground = getClass().getMethod("startForeground",
mStartForegroundSignature);
mStopForeground = getClass().getMethod("stopForeground",
mStopForegroundSignature);
return;
} catch (NoSuchMethodException e) {
// Running on an older platform.
mStartForeground = mStopForeground = null;
}
try {
mSetForeground = getClass().getMethod("setForeground",
mSetForegroundSignature);
} catch (NoSuchMethodException e) {
throw new IllegalStateException(
"OS doesn't have Service.startForeground OR Service.setForeground!");
}
}
@Override
public void onDestroy() {
// Make sure our notification is gone.
stopForegroundCompat(R.string.foreground_service_started);
}
2)相信大家看了上面两种方法的差异,都体会了andorid碎片化带来的麻烦。好在还有一种比较简单的方法,但是该方法只能在某些特定场合使用,如后台断点下载,推送服务之类的,如果用在音乐播放,就可能出现突然一卡的现象,这样很大的影响用户体验。该方法主要是在service的oncreate方法中新建一个计时器(使用alarmManager)这样每过一段时间就可以去启动一次service,当然如果service本身在running,那么就从onstartCommand开始,这样就可以达到和上面两种方法相同的效果。
扩展:service默认运行在主线程,所以不要在主线程中作耗时操作。
好啦,说到这里我提出一个疑问,举个例子,如一个service在播放音乐,为什么这个service没有影响我们的操作呢,或者说,为何我们感觉不到他的存在?