2018年Android的保活方案效果統(tǒng)計

一剃执、常見笔慕活方案

  • 1、監(jiān)聽廣播:監(jiān)聽全局的靜態(tài)廣播肾档,比如時間更新的廣播摹恰、開機(jī)廣播、解鎖屏怒见、網(wǎng)絡(luò)狀態(tài)俗慈、解鎖加鎖亮屏暗屏(3.1版本),高版本需要應(yīng)用開機(jī)后運(yùn)行一次才能監(jiān)聽這些系統(tǒng)廣播遣耍,目前此方案失效闺阱。可以更換思路舵变,做APP啟動后的焙ɡ#活(監(jiān)聽廣播啟動保活的前臺服務(wù))

  • 2纪隙、定時器赊豌、JobScheduler:假如應(yīng)用被系統(tǒng)殺死,那么定時器則失效绵咱,此方案失效碘饼。JobService在5.0,5.1,6.0作用很大,7.0時候有一定影響(可以在電源管理中給APP授權(quán))

  • 3麸拄、雙進(jìn)程(NDK方式Fork子進(jìn)程)派昧、雙Service守護(hù):高版本已失效,5.0起系統(tǒng)回收策略改成進(jìn)程組拢切。雙Service方案也改成了應(yīng)用被殺蒂萎,任何后臺Service無法正常狀態(tài)運(yùn)行

  • 4、提高Service優(yōu)先級:只能一定程度上緩解Service被立馬回收


二淮椰、蔽宕龋活

  • 1纳寂、AIDL方式單進(jìn)程、雙進(jìn)程方式毙豪梗活Service
  • 2毙芜、降低oom_adj的值:常駐通知欄(可通過啟動另外一個服務(wù)關(guān)閉Notification,不對oom_adj值有影響)争拐、使用”1像素“的Activity覆蓋在getWindow()的view上腋粥、循環(huán)播放無聲音頻(黑科技,7.0下殺不掉)
  • 3架曹、監(jiān)聽鎖屏廣播:使Activity始終保持前臺
  • 4隘冲、使用自定義鎖屏界面:覆蓋了系統(tǒng)鎖屏界面。
  • 5绑雄、通過android:process屬性來為Service創(chuàng)建一個進(jìn)程
  • 6展辞、跳轉(zhuǎn)到系統(tǒng)白名單界面讓用戶自己添加app進(jìn)入白名單

三、復(fù)活

  • 1万牺、JobScheduler:原理類似定時器罗珍,5.0,5.1,6.0作用很大,7.0時候有一定影響(可以在電源管理中給APP授權(quán))
  • 2脚粟、推送互相喚醒復(fù)活:極光覆旱、友盟、以及各大廠商的推送
  • 3珊楼、同派系A(chǔ)PP廣播互相喚醒:比如今日頭條系通殃、阿里系

方案實(shí)現(xiàn)效果統(tǒng)計

1、雙進(jìn)程守護(hù)方案(基于onStartCommand() return START_STICKY)

  • 1厕宗、原生5.0画舌、5.1:原生任務(wù)欄滑動清理app,Service會被殺掉已慢,然后被拉起曲聂,接著一直存活
  • 2、金立F100(5.1):一鍵清理直接殺掉整個app佑惠,包括雙守護(hù)進(jìn)程朋腋。不手動清理情況下,經(jīng)測試能鎖屏存活至少40分鐘
  • 3膜楷、華為暢享5x(6.0):一鍵清理直接殺掉整個app旭咽,包括雙守護(hù)進(jìn)程。不手動清理下赌厅,鎖屏只存活10s穷绵。結(jié)論:雙進(jìn)程守護(hù)方案失效。
  • 4特愿、美圖m8s(7.1.1):一鍵清理直接殺掉整個app仲墨,包括雙守護(hù)進(jìn)程勾缭。不清理情況下,鎖屏?xí)斜粴⑦^程(9分鐘左右被殺)目养,之后重新復(fù)活俩由,之后不斷被干掉然后又重新復(fù)活。結(jié)論:雙守護(hù)進(jìn)程可在后臺不斷拉起Service癌蚁。
  • 5幻梯、原生7.0:任務(wù)欄清除APP后,Service存活匈勋。使用此方案后Service照樣存活礼旅。
  • 6、LG V30+(7.1.2):不加雙進(jìn)程守護(hù)的時候洽洁,一鍵清理無法殺掉服務(wù)。加了此方案之后也不能殺掉服務(wù)菲嘴,鎖屏存活(測試觀察大于50分鐘)
  • 7饿自、小米8(8.1):一鍵清理直接干掉app并且包括雙守護(hù)進(jìn)程。不清理情況下龄坪,不加守護(hù)進(jìn)程方案與加守護(hù)進(jìn)程方案Service會一直存活昭雌,12分鐘左右closed。結(jié)論:此方案沒有起作用

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

2烛卧、監(jiān)聽鎖屏廣播打開1像素Activity(基于onStartCommand() return START_STICKY)

  • 1、原生5.0妓局、5.1:鎖屏后3s服務(wù)被干掉然后重啟(START_STICKY字段起作用)
  • 2总放、華為暢享5x(6.0):鎖屏只存活4s。結(jié)論:方案失效好爬。
  • 3局雄、美圖m8s(7.1.1):同原生5.0
  • 4、原生7.0:同美圖m8s存炮。
  • 5炬搭、LG V30+(7.1.2):鎖屏后情況跟不加情況一致,服務(wù)一致保持運(yùn)行穆桂,結(jié)論:此方案不起作用
  • 6宫盔、小米8(8.1):關(guān)屏過2s之后app全部被干掉。結(jié)論:此方案沒有起作用

結(jié)論此方案無效果

3享完、故意在后臺播放無聲的音樂(基于onStartCommand() return START_STICKY)

  • 1灼芭、原生5.0、5.1:鎖屏后3s服務(wù)被干掉然后重啟(START_STICKY字段起作用)
  • 2驼侠、華為暢享5x(6.0):一鍵清理后服務(wù)依然存活姿鸿,需要單獨(dú)清理才可殺掉服務(wù)谆吴,鎖屏8分鐘后依然存活。結(jié)論:此方案適用
  • 3苛预、美圖m8s(7.1.1):同5.0
  • 4句狼、原生7.0:任務(wù)管理器中關(guān)閉APP后服務(wù)被干掉,大概過3s會重新復(fù)活(同僅START_STICKY字段模式)热某。結(jié)論:看不出此方案有沒有其作用
  • 5腻菇、LG V30+(7.1.2):使用此方案前后效果一致。結(jié)論:此方案不起作用
  • 6昔馋、小米8(8.1):一鍵清理可以殺掉服務(wù)筹吐。鎖屏后保活超過20分鐘

結(jié)論:成功對華為手機(jī)泵囟簦活丘薛。小米8下也成功突破20分鐘

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

  • 1邦危、原生5.0洋侨、5.1:任務(wù)管理器中干掉APP,服務(wù)會在周期時間后重新啟動倦蚪。結(jié)論:此方案起作用
  • 2希坚、華為暢享5x(6.0):一鍵清理直接殺掉APP,過12s左右會自動重啟服務(wù)陵且,JobScheduler起作用
  • 3裁僧、美圖m8s(7.1.1):一鍵清理直接殺掉APP,無法自動重啟
  • 4慕购、原生7.0:同美圖m8s(7.1.1)
  • 5聊疲、小米8(8.1):同美圖m8s(7.1.1)

結(jié)論:只對5.0,5.1脓钾、6.0起作用

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

  • 1可训、原生5.0昌妹、5.1:任務(wù)管理器中干掉APP,服務(wù)會在周期時間后重新啟動握截。鎖屏超過11分鐘存活
  • 2飞崖、華為暢享5x(6.0):一鍵清理后服務(wù)依然存活,需要單獨(dú)清理才可殺掉服務(wù)谨胞。結(jié)論:方案適用固歪。
  • 3、美圖m8s(7.1.1):一鍵清理APP會被殺掉。正常情況下鎖屏后服務(wù)依然存活牢裳。
  • 4逢防、原生7.0:任務(wù)管理器中關(guān)閉APP后服務(wù)被干掉,過2s會重新復(fù)活
  • 5蒲讯、小米8(8.1):一鍵清理可以殺掉服務(wù)忘朝,鎖屏下后臺保活時間超過38分鐘
  • 6判帮、榮耀10(8.0):一鍵清理殺掉服務(wù)局嘁,鎖屏下后臺保活時間超過23分鐘

結(jié)論:高版本情況下可以使用彈出通知欄晦墙、雙進(jìn)程悦昵、無聲音樂提高后臺服務(wù)的保活概率


實(shí)現(xiàn)具體過程

一晌畅、雙進(jìn)程實(shí)現(xiàn)方案
使用AIDL綁定方式新建2個Service優(yōu)先級(防止服務(wù)同時被系統(tǒng)殺死)不一樣的守護(hù)進(jìn)程互相拉起對方但指,并在每一個守護(hù)進(jìn)程的```ServiceConnection```的綁定回調(diào)里判斷保活Service是否需要重新拉起和對守護(hù)線程進(jìn)行重新綁定踩麦。
  • 1枚赡、新建一個AIDL文件KeepAliveConnection
interface KeepAliveConnection  {
}
  • 2、新建一個服務(wù)類StepService谓谦,onBind()方法返回new KeepAliveConnection.Stub()對象,并在ServiceConnection的綁定回調(diào)中對守護(hù)進(jìn)程服務(wù)類GuardService的啟動和綁定贪婉。
/**
 * 主進(jìn)程 雙進(jìn)程通訊
 *
 * @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反粥、對守護(hù)進(jìn)程GuardService進(jìn)行和2一樣的處理
/**
 * 守護(hù)進(jìn)程 雙進(jìn)程通訊
 *
 * @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中在啟動需要逼S兀活的DownloadService服務(wù)后然后啟動辈哦伲活的雙進(jìn)程
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);
        //雙守護(hù)線程,優(yōu)先級不一樣
        startAllServices();
    }

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

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

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

二尤蒿、監(jiān)聽到鎖屏廣播后使用“1”像素Activity提升優(yōu)先級
  • 1郑气、該Activity的View只要設(shè)置為1像素然后設(shè)置在Window對象上即可。在Activity的onDestroy周期中進(jìn)行毖兀活服務(wù)的存活判斷從而喚醒服務(wù)尾组。"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、對廣播進(jìn)行監(jiān)聽示弓,封裝為一個ScreenReceiverUtil類讳侨,進(jìn)行鎖屏解鎖的廣播動態(tài)注冊監(jiān)聽
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;
        // 動態(tài)啟動廣播接收器
        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);
    }

    /**
     * 監(jiān)聽sreen狀態(tài)對外回調(diào)接口
     */
    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進(jìn)行防止內(nèi)存泄露的處理奏属,新建一個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);
    }

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

  • 4跨跨、對1像素的Style進(jìn)行特殊處理,在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忱嘹、在保活服務(wù)類DownloadService中對監(jiān)聽的廣播進(jìn)行注冊和對SinglePixelActivity進(jìn)行控制耕渴。
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, "關(guān)閉了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();

//        注冊鎖屏廣播監(jiān)聽器
        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、準(zhǔn)備一段無聲的音頻萨螺,新建一個播放音樂的Service類窄做,將播放模式改為無限循環(huán)播放。在其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,啟動服務(wù)");
        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, "關(guān)閉后臺播放音樂");
            mMediaPlayer.stop();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopPlayMusic();
        Logger.d(TAG, TAG + "---->onCreate,停止服務(wù)");
        // 重啟自己
        Intent intent = new Intent(getApplicationContext(), PlayerMusicService.class);
        startService(intent);
    }
}
  • 2椭盏、 在保活的DownloadServie服務(wù)類的onCreate方法中對PlayerMusicService進(jìn)行啟動
 Intent intent = new Intent(this, PlayerMusicService.class);
 startService(intent);
  • 3吻商、在Manifest文件中進(jìn)行注冊
  <service
            android:name=".service.PlayerMusicService"
            android:enabled="true"
            android:exported="true"
            android:process=":music_service" />

4掏颊、使用JobScheduler喚醒Service
  • 1、新建一個繼承自JobService的ScheduleService類艾帐,在其onStartJob回調(diào)中對DownloadService進(jìn)行存活的判斷來重啟乌叶。
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服務(wù)類中進(jìn)行JobScheduler的注冊和使用

 /**
     * 使用JobScheduler進(jìn)行逼獍郑活
     */
    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()));
        //周期設(shè)置為了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文件中進(jìn)行權(quán)限設(shè)置
 <service
            android:name=".service.ScheduleService"
            android:enabled="true"
            android:exported="true"
            android:permission="android.permission.BIND_JOB_SERVICE" />

關(guān)于推送類拉活

根據(jù)華為官方文檔集成HUAWEI Push

  • 1捎稚、華為暢玩5X(6.0):APP全部進(jìn)程被殺死時可以被拉起乐横。
  • 2、華為nove 3e(8.0):APP全部進(jìn)程被殺死時無法被拉起今野,能收到推送葡公。
  • 3、華為榮耀10(8.1):同2

結(jié)論:理論情況下条霜,華為推送應(yīng)該可以拉起華為機(jī)器才對催什,感覺是我沒花錢的原因

補(bǔ)充: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;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市宰睡,隨后出現(xiàn)的幾起案子蒲凶,更是在濱河造成了極大的恐慌,老刑警劉巖夹厌,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件豹爹,死亡現(xiàn)場離奇詭異,居然都是意外死亡矛纹,警方通過查閱死者的電腦和手機(jī)臂聋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人孩等,你說我怎么就攤上這事艾君。” “怎么了肄方?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵冰垄,是天一觀的道長。 經(jīng)常有香客問我权她,道長虹茶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任隅要,我火速辦了婚禮蝴罪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘步清。我一直安慰自己要门,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布廓啊。 她就那樣靜靜地躺著欢搜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谴轮。 梳的紋絲不亂的頭發(fā)上炒瘟,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機(jī)與錄音第步,去河邊找鬼唧领。 笑死,一個胖子當(dāng)著我的面吹牛雌续,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播胯杭,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼驯杜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了做个?” 一聲冷哼從身側(cè)響起鸽心,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎居暖,沒想到半個月后顽频,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡太闺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年糯景,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡蟀淮,死狀恐怖最住,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情怠惶,我是刑警寧澤涨缚,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站策治,受9級特大地震影響脓魏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜通惫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一茂翔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧讽膏,春花似錦檩电、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至奄侠,卻和暖如春卓箫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背垄潮。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工烹卒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人弯洗。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓旅急,卻偏偏與公主長得像,于是被迫代替她去往敵國和親牡整。 傳聞我的和親對象是個殘疾皇子藐吮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容