zoukankan      html  css  js  c++  java
  • 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(1, new 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(1, new 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<Activity> 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/transparent</item>
            <item name="android:windowFrame">@null</item>
            <item name="android:windowNoTitle">true</item>
            <item name="android:windowIsFloating">true</item>
            <item name="android:windowContentOverlay">@null</item>
            <item name="android:backgroundDimEnabled">false</item>
            <item name="android:windowAnimationStyle">@null</item>
            <item name="android:windowDisablePreview">true</item>
            <item name="android:windowNoDisplay">false</item>
    

    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, 1000, 1000);
        }
    
        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;
            }
        }
    }
    
    

    3、在后台播放音乐

    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" />
    

    4、使用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(1024, new 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;
        }
    }
    

    作者:minminaya
    链接:https://www.jianshu.com/p/b5371df6d7cb

    阅读更多

    做后台是选择Java 、Go ,还是 PHP?

    NDK项目实战—高仿360手机助手之卸载监听

    AndroidUtils:Android开发不得不收藏的Utils

    (Android)面试题级答案(精选版)

    Google开发者大会:你不得不知的Tensorflow小技巧

    相信自己,没有做不到的,只有想不到的

    在这里获得的不仅仅是技术!

  • 相关阅读:
    iis 站点部署后 Microsof .Net Framework异常
    数据库中GUID的生成
    影响世界的100个经典管理定律
    帕金森定律(Parkinson's Law)
    eclipse 弹出智能提示、代码自动换行
    eclipse 快捷键
    extjs grid 分页
    extjs gride 显示序号
    SharePoint 2013 Deploy Master Page And Page Layout
    正则表达式匹配并替换字符串
  • 原文地址:https://www.cnblogs.com/gooder2-android/p/9722231.html
Copyright © 2011-2022 走看看