歡迎光臨
每天分享高質量文章

2018年Android保活方案效果統計

一、常見保活方案

  • 1、監聽廣播:監聽全域性的靜態廣播,比如時間更新的廣播、開機廣播、解鎖屏、網路狀態、解鎖加鎖亮屏暗屏(3.1版本),高版本需要應用開機後執行一次才能監聽這些系統廣播,目前此方案失效。可以更換思路,做APP啟動後的保活(監聽廣播啟動保活的前臺服務)

  • 2、定時器、JobScheduler:假如應用被系統殺死,那麼定時器則失效,此方案失效。JobService在5.0,5.1,6.0作用很大,7.0時候有一定影響(可以在電源管理中給APP授權)

  • 3、雙行程(NDK方式Fork子行程)、雙Service守護:高版本已失效,5.0起系統回收策略改成行程組。雙Service方案也改成了應用被殺,任何後臺Service無法正常狀態執行

  • 4、提高Service優先順序:只能一定程度上緩解Service被立馬回收

二、保活

  • 1、AIDL方式單行程、雙行程方式保活Service

  • 2、降低oom_adj的值:常駐通知欄(可透過啟動另外一個服務關閉Notification,不對oom_adj值有影響)、使用”1畫素“的Activity改寫在getWindow()的view上、迴圈播放無聲音訊(黑科技,7.0下殺不掉)

  • 3、監聽鎖屏廣播:使Activity始終保持前臺

  • 4、使用自定義鎖屏介面:改寫了系統鎖屏介面。

  • 5、透過android:process屬性來為Service建立一個行程

  • 6、跳轉到系統白名單介面讓使用者自己新增app進入白名單

三、複活

  • 1、JobScheduler:原理類似定時器,5.0,5.1,6.0作用很大,7.0時候有一定影響(可以在電源管理中給APP授權)

  • 2、推送互相喚醒複活:極光、友盟、以及各大廠商的推送

  • 3、同派系APP廣播互相喚醒:比如今日頭條系、阿裡系

方案實現效果統計

1、雙行程守護方案(基於onStartCommand() return START_STICKY)

  • 1、原生5.0、5.1:原生工作列滑動清理app,Service會被殺掉,然後被拉起,接著一直存活

  • 2、金立F100(5.1):一鍵清理直接殺掉整個app,包括雙守護行程。不手動清理情況下,經測試能鎖屏存活至少40分鐘

  • 3、華為暢享5x(6.0):一鍵清理直接殺掉整個app,包括雙守護行程。不手動清理下,鎖屏只存活10s。結論:雙行程守護方案失效。

  • 4、美圖m8s(7.1.1):一鍵清理直接殺掉整個app,包括雙守護行程。不清理情況下,鎖屏會有被殺過程(9分鐘左右被殺),之後重新複活,之後不斷被幹掉然後又重新複活。結論:雙守護行程可在後臺不斷拉起Service。

  • 5、原生7.0:工作列清除APP後,Service存活。使用此方案後Service照樣存活。

  • 6、LG V30+(7.1.2):不加雙行程守護的時候,一鍵清理無法殺掉服務。加了此方案之後也不能殺掉服務,鎖屏存活(測試觀察大於50分鐘)

  • 7、小米8(8.1):一鍵清理直接幹掉app並且包括雙守護行程。不清理情況下,不加守護行程方案與加守護行程方案Service會一直存活,12分鐘左右closed。結論:此方案沒有起作用

結論:除了華為此方案無效以及未更改底層的廠商不起作用外(START_STICKY欄位就可以保持Service不被殺)。此方案可以與其他方案混合使用

2、監聽鎖屏廣播開啟1畫素Activity(基於onStartCommand() return START_STICKY)
  • 1、原生5.0、5.1:鎖屏後3s服務被幹掉然後重啟(START_STICKY欄位起作用)

  • 2、華為暢享5x(6.0):鎖屏只存活4s。結論:方案失效。

  • 3、美圖m8s(7.1.1):同原生5.0

  • 4、原生7.0:同美圖m8s。

  • 5、LG V30+(7.1.2):鎖屏後情況跟不加情況一致,服務一致保持執行,結論:此方案不起作用

  • 6、小米8(8.1):關屏過2s之後app全部被幹掉。結論:此方案沒有起作用

結論:此方案無效果

3、故意在後臺播放無聲的音樂(基於onStartCommand() return START_STICKY)

  • 1、原生5.0、5.1:鎖屏後3s服務被幹掉然後重啟(START_STICKY欄位起作用)

  • 2、華為暢享5x(6.0):一鍵清理後服務依然存活,需要單獨清理才可殺掉服務,鎖屏8分鐘後依然存活。結論:此方案適用

  • 3、美圖m8s(7.1.1):同5.0

  • 4、原生7.0:任務管理器中關閉APP後服務被幹掉,大概過3s會重新複活(同僅START_STICKY欄位樣式)。結論:看不出此方案有沒有其作用

  • 5、LG V30+(7.1.2):使用此方案前後效果一致。結論:此方案不起作用

  • 6、小米8(8.1):一鍵清理可以殺掉服務。鎖屏後保活超過20分鐘

結論:成功對華為手機保活。小米8下也成功突破20分鐘

4、使用JobScheduler喚醒Service(基於onStartCommand() return START_STICKY)

  • 1、原生5.0、5.1:任務管理器中幹掉APP,服務會在週期時間後重新啟動。結論:此方案起作用

  • 2、華為暢享5x(6.0):一鍵清理直接殺掉APP,過12s左右會自動重啟服務,JobScheduler起作用

  • 3、美圖m8s(7.1.1):一鍵清理直接殺掉APP,無法自動重啟

  • 4、原生7.0:同美圖m8s(7.1.1)

  • 5、小米8(8.1):同美圖m8s(7.1.1)

結論:只對5.0,5.1、6.0起作用

5、混合使用的效果,並且在通知欄彈出通知

  • 1、原生5.0、5.1:任務管理器中幹掉APP,服務會在週期時間後重新啟動。鎖屏超過11分鐘存活

  • 2、華為暢享5x(6.0):一鍵清理後服務依然存活,需要單獨清理才可殺掉服務。結論:方案適用。

  • 3、美圖m8s(7.1.1):一鍵清理APP會被殺掉。正常情況下鎖屏後服務依然存活。

  • 4、原生7.0:任務管理器中關閉APP後服務被幹掉,過2s會重新複活

  • 5、小米8(8.1):一鍵清理可以殺掉服務,鎖屏下後臺保活時間超過38分鐘

  • 6、榮耀10(8.0):一鍵清理殺掉服務,鎖屏下後臺保活時間超過23分鐘

  • 結論:高版本情況下可以使用彈出通知欄、雙行程、無聲音樂提高後臺服務的保活機率

實現具體過程

一、雙行程實現方案

使用AIDL系結方式新建2個Service優先順序(防止服務同時被系統殺死)不一樣的守護行程互相拉起對方,併在每一個守護行程的ServiceConnection的系結回呼裡判斷保活Service是否需要重新拉起和對守護執行緒進行重新系結。

1、新建一個AIDL檔案

KeepAliveConnection
interface KeepAliveConnection  {
}

2、新建一個服務類StepService,onBind()方法傳回new KeepAliveConnection.Stub()物件,併在ServiceConnection的系結回呼中對守護行程服務類GuardService的啟動和系結。

/**
* 主行程 雙行程通訊
*
* @author LiGuangMin
* @time Created by 2018/8/17 11:26
*/
public class StepService extends Service {

   private final static String TAG = StepService.class.getSimpleName();
   private ServiceConnection mServiceConnection = new ServiceConnection() {
       @Override
       public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
           Logger.d(TAG, "StepService:建立連結");
           boolean isServiceRunning = ServiceAliveUtils.isServiceAlice();
           if (!isServiceRunning) {
               Intent i = new Intent(StepService.this, DownloadService.class);
               startService(i);
           }
       }

       @Override
       public void onServiceDisconnected(ComponentName componentName) {
           // 斷開連結
           startService(new Intent(StepService.this, GuardService.class));
           // 重新系結
           bindService(new Intent(StepService.this, GuardService.class), mServiceConnection, Context.BIND_IMPORTANT);
       }
   };

   @Nullable
   @Override
   public IBinder onBind(Intent intent) {
       return new KeepAliveConnection.Stub() {
       };
   }

   @Override
   public int onStartCommand(Intent intent, int flags, int startId) {
       startForeground(1new Notification());
       // 系結建立連結
       bindService(new Intent(this, GuardService.class), mServiceConnection, Context.BIND_IMPORTANT);
       return START_STICKY;
   }

}

3、對守護行程GuardService進行和2一樣的處理

/**
* 守護行程 雙行程通訊
*
* @author LiGuangMin
* @time Created by 2018/8/17 11:27
*/
public class GuardService extends Service {
   private final static String TAG = GuardService.class.getSimpleName();
   private ServiceConnection mServiceConnection = new ServiceConnection() {
       @Override
       public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
           Logger.d(TAG, "GuardService:建立連結");
           boolean isServiceRunning = ServiceAliveUtils.isServiceAlice();
           if (!isServiceRunning) {
               Intent i = new Intent(GuardService.this, DownloadService.class);
               startService(i);
           }
       }

       @Override
       public void onServiceDisconnected(ComponentName componentName) {
           // 斷開連結
           startService(new Intent(GuardService.this, StepService.class));
           // 重新系結
           bindService(new Intent(GuardService.this, StepService.class), mServiceConnection, Context.BIND_IMPORTANT);
       }
   };

   @Nullable
   @Override
   public IBinder onBind(Intent intent) {
       return new KeepAliveConnection.Stub() {
       };
   }

   @Override
   public int onStartCommand(Intent intent, int flags, int startId) {
       startForeground(1new Notification());
       // 系結建立連結
       bindService(new Intent(this, StepService.class), mServiceConnection, Context.BIND_IMPORTANT);
       return START_STICKY;
   }

}

4、在Activity中在啟動需要保活的DownloadService服務後然後啟動保活的雙行程

public class MainActivity extends AppCompatActivity {
   private TextView mShowTimeTv;
   private DownloadService.DownloadBinder mDownloadBinder;
   private ServiceConnection mServiceConnection = new ServiceConnection() {
       @Override
       public void onServiceConnected(ComponentName name, IBinder service) {
           mDownloadBinder = (DownloadService.DownloadBinder) service;
           mDownloadBinder.setOnTimeChangeListener(new DownloadService.OnTimeChangeListener() {
               @Override
               public void showTime(final String time) {
                   runOnUiThread(new Runnable() {
                       @Override
                       public void run() {
                           mShowTimeTv.setText(time);
                       }
                   });
               }
           });
       }

       @Override
       public void onServiceDisconnected(ComponentName name) {
       }
   };

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

       Intent intent = new Intent(this, DownloadService.class);
       startService(intent);
       bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
       //雙守護執行緒,優先順序不一樣
       startAllServices();
   }

   @Override
   public void onContentChanged() {
       super.onContentChanged();
       mShowTimeTv = findViewById(R.id.tv_show_time);
   }

   @Override
   protected void onDestroy() {
       super.onDestroy();
       unbindService(mServiceConnection);
   }

   /**
    * 開啟所有守護Service
    */
   private void startAllServices() {
       startService(new Intent(this, StepService.class));
       startService(new Intent(this, GuardService.class));
   }
}

二、監聽到鎖屏廣播後使用“1”畫素Activity提升優先順序

1、該Activity的View只要設定為1畫素然後設定在Window物件上即可。在Activity的onDestroy週期中進行保活服務的存活判斷從而喚醒服務。”1畫素”Activity如下

public class SinglePixelActivity extends AppCompatActivity {
   private static final String TAG = SinglePixelActivity.class.getSimpleName();

   @Override
   protected void onCreate(@Nullable Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       Window mWindow = getWindow();
       mWindow.setGravity(Gravity.LEFT | Gravity.TOP);
       WindowManager.LayoutParams attrParams = mWindow.getAttributes();
       attrParams.x = 0;
       attrParams.y = 0;
       attrParams.height = 1;
       attrParams.width = 1;
       mWindow.setAttributes(attrParams);
       ScreenManager.getInstance(this).setSingleActivity(this);
   }

   @Override
   protected void onDestroy() {
       if (!SystemUtils.isAppAlive(this, Constant.PACKAGE_NAME)) {
           Intent intentAlive = new Intent(this, DownloadService.class);
           startService(intentAlive);
       }
       super.onDestroy();
   }
}

2、對廣播進行監聽,封裝為一個ScreenReceiverUtil類,進行鎖屏解鎖的廣播動態註冊監聽

public class ScreenReceiverUtil {
   private Context mContext;
   private SreenBroadcastReceiver mScreenReceiver;
   private SreenStateListener mStateReceiverListener;

   public ScreenReceiverUtil(Context mContext{
       this.mContext = mContext;
   }

   public void setScreenReceiverListener(SreenStateListener mStateReceiverListener{
       this.mStateReceiverListener = mStateReceiverListener;
       // 動態啟動廣播接收器
       this.mScreenReceiver = new SreenBroadcastReceiver();
       IntentFilter filter = new IntentFilter();
       filter.addAction(Intent.ACTION_SCREEN_ON);
       filter.addAction(Intent.ACTION_SCREEN_OFF);
       filter.addAction(Intent.ACTION_USER_PRESENT);
       mContext.registerReceiver(mScreenReceiver, filter);
   }

   public void stopScreenReceiverListener() {
       mContext.unregisterReceiver(mScreenReceiver);
   }

   /**
    * 監聽sreen狀態對外回呼介面
    */
   public interface SreenStateListener {
       void onSreenOn();

       void onSreenOff();

       void onUserPresent();
   }

   public class SreenBroadcastReceiver extends BroadcastReceiver {
       @Override
       public void onReceive(Context context, Intent intent{
           String action = intent.getAction();
           if (mStateReceiverListener == null) {
               return;
           }
           if (Intent.ACTION_SCREEN_ON.equals(action)) { // 開屏
               mStateReceiverListener.onSreenOn();
           } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { // 鎖屏
               mStateReceiverListener.onSreenOff();
           } else if (Intent.ACTION_USER_PRESENT.equals(action)) { // 解鎖
               mStateReceiverListener.onUserPresent();
           }
       }
   }
}

3、對1畫素Activity進行防止記憶體洩露的處理,新建一個ScreenManager類

public class ScreenManager {
   private static final String TAG = ScreenManager.class.getSimpleName();
   private static ScreenManager sInstance;
   private Context mContext;
   private WeakReference mActivity;

   private ScreenManager(Context mContext{
       this.mContext = mContext;
   }

   public static ScreenManager getInstance(Context context{
       if (sInstance == null) {
           sInstance = new ScreenManager(context);
       }
       return sInstance;
   }

   /** 獲得SinglePixelActivity的取用
    * @param activity
    */
   public void setSingleActivity(Activity activity{
       mActivity = new WeakReference<>(activity);
   }

   /**
    * 啟動SinglePixelActivity
    */
   public void startActivity() {
       Intent intent = new Intent(mContext, SinglePixelActivity.class);
       intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
       mContext.startActivity(intent);
   }

   /**
    * 結束SinglePixelActivity
    */
   public void finishActivity() {
       if (mActivity != null) {
           Activity activity = mActivity.get();
           if (activity != null) {
               activity.finish();
           }
       }
   }
}

4、對1畫素的Style進行特殊處理,在style檔案中新建一個SingleActivityStyle

<style name="SingleActivityStyle" parent="android:Theme.Holo.Light.NoActionBar">
       <item name="android:windowBackground">@android:color/transparentitem>
       <item name="android:windowFrame">@nullitem>

<item name=“android:windowNoTitle”>trueitem>
<item name=“android:windowIsFloating”>trueitem>
<item name=“android:windowContentOverlay”>@nullitem>
<item name=“android:backgroundDimEnabled”>falseitem>
<item name=“android:windowAnimationStyle”>@nullitem>
<item name=“android:windowDisablePreview”>trueitem>
<item name=“android:windowNoDisplay”>falseitem>

5、讓SinglePixelActivity使用singleInstance啟動樣式,在manifest檔案中

<activity
           android:name=".activity.SinglePixelActivity"
           android:configChanges="keyboardHidden|orientation|screenSize|navigation|keyboard"
           android:excludeFromRecents="true"
           android:finishOnTaskLaunch="false"
           android:launchMode="singleInstance"
           android:theme="@style/SingleActivityStyle" />

6、在保活服務類DownloadService中對監聽的廣播進行註冊和對SinglePixelActivity進行控制。

public class DownloadService extends Service {
   public static final int NOTICE_ID = 100;
   private static final String TAG = DownloadService.class.getSimpleName();
   private DownloadBinder mDownloadBinder;
   private NotificationCompat.Builder mBuilderProgress;
   private NotificationManager mNotificationManager;

   private ScreenReceiverUtil mScreenListener;
   private ScreenManager mScreenManager;
   private Timer mRunTimer;

   private int mTimeSec;
   private int mTimeMin;
   private int mTimeHour;

   private ScreenReceiverUtil.SreenStateListener mScreenListenerer = new ScreenReceiverUtil.SreenStateListener() {
       @Override
       public void onSreenOn() {
           mScreenManager.finishActivity();
           Logger.d(TAG, "關閉了1畫素Activity");
       }

       @Override
       public void onSreenOff() {
           mScreenManager.startActivity();
           Logger.d(TAG, "開啟了1畫素Activity");
       }

       @Override
       public void onUserPresent() {
       }
   };
   private OnTimeChangeListener mOnTimeChangeListener;

   @Override
   public void onCreate() {
       super.onCreate();

//        註冊鎖屏廣播監聽器
       mScreenListener = new ScreenReceiverUtil(this);
       mScreenManager = ScreenManager.getInstance(this);
       mScreenListener.setScreenReceiverListener(mScreenListenerer);

       mDownloadBinder = new DownloadBinder();
       mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
   }

   @Override
   public int onStartCommand(Intent intent, int flags, int startId) {
       Logger.d(TAG, "onStartCommand");
       startRunTimer();
       return START_STICKY;
   }

   @Nullable
   @Override
   public IBinder onBind(Intent intent) {

       return mDownloadBinder;
   }

   @Override
   public boolean onUnbind(Intent intent) {
       Logger.d(TAG, "onUnbind");
       return super.onUnbind(intent);
   }

   @Override
   public void onDestroy() {
       super.onDestroy();
       NotificationManager mManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
       if (mManager == null) {
           return;
       }
       mManager.cancel(NOTICE_ID);
       stopRunTimer();
//        mScreenListener.stopScreenReceiverListener();
   }

   private void startRunTimer() {
       TimerTask mTask = new TimerTask() {
           @Override
           public void run() {
               mTimeSec++;
               if (mTimeSec == 60) {
                   mTimeSec = 0;
                   mTimeMin++;
               }
               if (mTimeMin == 60) {
                   mTimeMin = 0;
                   mTimeHour++;
               }
               if (mTimeHour == 24) {
                   mTimeSec = 0;
                   mTimeMin = 0;
                   mTimeHour = 0;
               }
               String time = "時間為:" + mTimeHour + " : " + mTimeMin + " : " + mTimeSec;
               if (mOnTimeChangeListener != null) {
                   mOnTimeChangeListener.showTime(time);
               }
               Logger.d(TAG, time);
           }
       };
       mRunTimer = new Timer();
       // 每隔1s更新一下時間
       mRunTimer.schedule(mTask, 10001000);
   }

   private void stopRunTimer() {
       if (mRunTimer != null) {
           mRunTimer.cancel();
           mRunTimer = null;
       }
       mTimeSec = 0;
       mTimeMin = 0;
       mTimeHour = 0;
       Logger.d(TAG, "時間為:" + mTimeHour + " : " + mTimeMin + " : " + mTimeSec);
   }

   public interface OnTimeChangeListener {
       void showTime(String time);
   }

   public class DownloadBinder extends Binder {
       public void setOnTimeChangeListener(OnTimeChangeListener onTimeChangeListener) {
           mOnTimeChangeListener = onTimeChangeListener;
       }
   }
}

三、在後臺播放音樂

1、準備一段無聲的音訊,新建一個播放音樂的Service類,將播放樣式改為無限迴圈播放。在其onDestroy方法中對自己重新啟動。

public class PlayerMusicService extends Service {
   private final static String TAG = PlayerMusicService.class.getSimpleName();
   private MediaPlayer mMediaPlayer;

   @Nullable
   @Override
   public IBinder onBind(Intent intent) {
       return null;
   }

   @Override
   public void onCreate() {
       super.onCreate();
       Logger.d(TAG, TAG + "---->onCreate,啟動服務");
       mMediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.silent);
       mMediaPlayer.setLooping(true);
   }

   @Override
   public int onStartCommand(Intent intent, int flags, int startId) {
       new Thread(new Runnable() {
           @Override
           public void run() {
               startPlayMusic();
           }
       }).start();
       return START_STICKY;
   }

   private void startPlayMusic() {
       if (mMediaPlayer != null) {
           Logger.d(TAG, "啟動後臺播放音樂");
           mMediaPlayer.start();
       }
   }

   private void stopPlayMusic() {
       if (mMediaPlayer != null) {
           Logger.d(TAG, "關閉後臺播放音樂");
           mMediaPlayer.stop();
       }
   }

   @Override
   public void onDestroy() {
       super.onDestroy();
       stopPlayMusic();
       Logger.d(TAG, TAG + "---->onCreate,停止服務");
       // 重啟自己
       Intent intent = new Intent(getApplicationContext(), PlayerMusicService.class);
       startService(intent);
   }
}

2、在保活的DownloadServie服務類的onCreate方法中對PlayerMusicService進行啟動

Intent intent = new Intent(this, PlayerMusicService.class);
startService(intent);

3、在Manifest檔案中進行註冊

<service
           android:name=".service.PlayerMusicService"
           android:enabled="true"
           android:exported="true"
           android:process=":music_service" />

四、使用JobScheduler喚醒Service

1、新建一個繼承自JobService的ScheduleService類,在其onStartJob回呼中對DownloadService進行存活的判斷來重啟。

public class ScheduleService extends JobService {
   private static final String TAG = ScheduleService.class.getSimpleName();

   @Override
   public boolean onStartJob(JobParameters params) {

       boolean isServiceRunning = ServiceAliveUtils.isServiceAlice();
       if (!isServiceRunning) {
           Intent i = new Intent(this, DownloadService.class);
           startService(i);
           Logger.d(TAG, "ScheduleService啟動了DownloadService");
       }
       jobFinished(params, false);
       return false;
   }

   @Override
   public boolean onStopJob(JobParameters params) {
       return false;
   }
}

2、 在DownloadService服務類中進行JobScheduler的註冊和使用

/**
    * 使用JobScheduler進行保活
    */
   private void useJobServiceForKeepAlive() {
       JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
       if (jobScheduler == null) {
           return;
       }
       jobScheduler.cancelAll();
       JobInfo.Builder builder =
           new JobInfo.Builder(1024new ComponentName(getPackageName(), ScheduleService.class.getName()));
       //週期設定為了2s
       builder.setPeriodic(1000 * 2);
       builder.setPersisted(true);
       builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
       int schedule = jobScheduler.schedule(builder.build());
       if (schedule <= 0) {
           Logger.w(TAG, "schedule error!");
       }
   }

3、在manifest檔案中進行許可權設定

<service
           android:name=".service.ScheduleService"
           android:enabled="true"
           android:exported="true"
    android:permission="android.permission.BIND_JOB_SERVICE" />

關於推送類拉活

根據華為官方檔案整合HUAWEI Push

  • 1、華為暢玩5X(6.0):APP全部行程被殺死時可以被拉起。

  • 2、華為nove 3e(8.0):APP全部行程被殺死時無法被拉起,能收到推送。

  • 3、華為榮耀10(8.1):同2

結論:理論情況下,華為推送應該可以拉起華為機器才對,感覺是我沒花錢的原因

補充:ServiceAliveUtils 類如下

public class ServiceAliveUtils {

   public static boolean isServiceAlice() {
       boolean isServiceRunning = false;
       ActivityManager manager =
           (ActivityManager) MyApplication.getMyApplication().getSystemService(Context.ACTIVITY_SERVICE);
       if (manager == null) {
           return true;
       }
       for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
           if ("demo.lgm.com.keepalivedemo.service.DownloadService".equals(service.service.getClassName())) {
               isServiceRunning = true;
           }
       }
       return isServiceRunning;
   }
}
 
贊(0)

分享創造快樂