Android创建前台运行的Service

Service如果要防止尽可能不被系统杀掉,需要设置为在前台运行。

由于设置前台运行service的方法在2.0之前和2.0之后有所变化。

所以需要根据不同的版本进行区分;或者完全使用反射机制来处理,这样只要有相应的方法就可以使用,否则使用其他版本的方法。

下面是一个设置servcie前台运行的例子,参考了API中对Service的说明。

http://developer.android.com/reference/android/app/Service.html#

import java.lang.reflect.InvocationTargetException;  
import java.lang.reflect.Method;  
  
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.IBinder;  
import android.os.Build.VERSION;  
import android.util.Log;  
  
public class ForegroundService extends Service {  
    private static final String TAG = "ForegroundService";  
      
    private boolean mReflectFlg = false;  
      
    private static final int NOTIFICATION_ID = 1; // 如果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];    
      
    @Override    
    public void onCreate() {    
        super.onCreate();  
        Log.d(TAG, "onCreate");  
          
        mNM = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);    
        try {    
            mStartForeground = ForegroundService.class.getMethod("startForeground", mStartForegroundSignature);    
            mStopForeground = ForegroundService.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!");  
        }  
  
        Notification.Builder builder = new Notification.Builder(this);  
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,    
                new Intent(this, MainActivity.class), 0);    
        builder.setContentIntent(contentIntent);  
        builder.setSmallIcon(R.drawable.icon);  
        builder.setTicker("Foreground Service Start");  
        builder.setContentTitle("Foreground Service");  
        builder.setContentText("Make this service run in the foreground.");  
        Notification notification = builder.build();  
          
        startForegroundCompat(NOTIFICATION_ID, notification);    
    }    
      
    @Override  
    public int onStartCommand(Intent intent, int flags, int startId) {  
        super.onStartCommand(intent, flags, startId);  
        Log.d(TAG, "onStartCommand");  
          
        return START_STICKY;  
    }   
      
    @Override    
    public IBinder onBind(Intent intent) {    
        return null;    
    }    
  
    @Override    
    public void onDestroy() {    
        super.onDestroy();  
        Log.d(TAG, "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运行后的效果如图:

(1).通知栏显示内容:

 

(2).下拉后通知栏显示内容:

posted @ 2018-06-20 15:40  门罗的魔术师  阅读(488)  评论(0编辑  收藏  举报