Android 前台Service保证APP不被杀死

需求: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隐藏-- 这是个很大的问题---


你可能感兴趣的:(前台Service,Service不被杀死)