需求:1、程序后台每隔10秒钟扫描一次WIFI,扫描到XXX的wifi就发送通知栏消息给用户
2、程序 后台监听声音输入,并解析声音,然后发送通知栏消息给用户
普通的Service(后台Service): 通过手机的最近运行程序,可以直接杀死,起不来。
尝试过的方法:1、
onStartCommand方法,返回START_STICKY
2、
提升service优先级
3、
onDestroy方法里重启service
4、
Application加上Persistent属性
5、
监听系统广播判断Service状态
未尝试过的方法:
1、像微信一样,开启两个进程和两个服务(守护进程和服务)
2
、
将APK安装到/system/app,变身系统级应用(并不是所有的用户的手机ROOT过)
以上尝试过的方法,都会被杀死(在小米平板2上进行测试的)。
于是,我在网上找到了前台Service的方法,于是乎,没有被杀死了。
弊端:会产生一个通知栏的消息,在通知栏(类似于360管家一样,在通知栏不可以被移除(部分机型可以移除))
由于开发的时间很短--就用的这个:首先看下面的Service类:
注意这个类的
onStartCommand()的方法,我在这里面启动了两个后台的Service,并且让它返回
START_STICKY。
然后,注意
onDestroy()方法,在这里面,我停止了前台的Service,如果不想停止,可以将这行代码注释掉
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build.VERSION;
import android.os.IBinder;
import android.util.Log;
import com.baimi.dujiangyan.R;
import com.baimi.dujiangyan.activity.MainActivity;
/**
* @ClassName: KeepService
* @Description: 前台service,可以保持service不被杀死!在前台service中启动后台service(启动VoiceService和WifiService)
* @author
* @date 2016 -3 -12 上午9:29:29
*
*/
public class KeepService extends Service {
private boolean mReflectFlg = false;
private static final int NOTIFICATION_ID = 101; // 如果id设置为0,会导致不能设置为前台service
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];
@SuppressLint("NewApi")
@Override
public void onCreate() {
super.onCreate();
mNM = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE );
try {
mStartForeground = KeepService.class.getMethod("startForeground" , mStartForegroundSignature);
mStopForeground = KeepService.class.getMethod("stopForeground" , mStopForegroundSignature);
} catch (NoSuchMethodException e) {
mStartForeground = mStopForeground = null;
}
try {
mSetForeground = getClass().getMethod( "setForeground", mSetForegroundSignature);
} catch (NoSuchMethodException e) {
throw new IllegalStateException( "OS doesn't have Service.startForeground OR Service.setForeground!");
}
Intent intent = new Intent( this, MainActivity. class);
intent.putExtra( "ficationId", NOTIFICATION_ID);
Notification.Builder builder = new Notification.Builder(this);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0);
builder.setContentIntent(contentIntent); //设置了此项内容之后,点击通知栏的这个消息,就跳转到MainActivity
builder.setSmallIcon(R.drawable. ic_launcher);
// builder.setTicker("Foreground Service Start");
builder.setContentTitle( "发现周边优惠、畅享免费Wi-Fi" );
builder.setContentText( "【智慧生活】发现城市的智慧" );
Notification notification = builder.build();
startForegroundCompat( NOTIFICATION_ID, notification);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
//在这里我又启动了其他的两个Service,注意,此处启动的是后台的Service
startService( new Intent( this, WifiService. class));
startService( new Intent( this, VoiceService. class));
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
stopForegroundCompat( NOTIFICATION_ID);
}
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 ( mReflectFlg) {
// 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);
} else {
/*
* 还可以使用以下方法,当 sdk大于等于5时,调用 sdk现有的方法startForeground设置前台运行,
* 否则调用反射取得的 sdk level 5(对应Android 2.0)以下才有的旧方法setForeground设置前台运行
*/
if (VERSION. SDK_INT >= 5) {
startForeground(id, notification);
} else {
// 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 ( mReflectFlg) {
// 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);
} else {
/*
* 还可以使用以下方法,当 sdk大于等于5时,调用 sdk现有的方法stopForeground停止前台运行, 否则调用反射取得的 sdk
* level 5(对应Android 2.0)以下才有的旧方法setForeground停止前台运行
*/
if (VERSION. SDK_INT >= 5) {
stopForeground( true);
} else {
// 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);
}
}
}
}
关于前台Service,不知道还有什么办法来将Notification隐藏-- 这是个很大的问题---