Android進(jìn)程奔砹常活有哪些實(shí)現(xiàn)方案

說到進(jìn)程保活毙驯,忍不住吐槽一下市場上除了微信這樣的白名單大佬倒堕,其他的應(yīng)用很難在后臺(tái)保持長鏈接,北郏活只能是使用一些歪門邪道來延長進(jìn)程的持續(xù)時(shí)間垦巴。總的來說也就這兩種方法:
(1)提供進(jìn)程優(yōu)先級(jí)铭段,降低進(jìn)程被殺死的概率骤宣;(2)在進(jìn)程被殺死后,進(jìn)行拉活.
今天就先來說降低被殺死的概率方法:一像素Activity序愚,雙進(jìn)程守護(hù)Service憔披。

1像素Activity

1像素Activity的特點(diǎn): 需要設(shè)置該activity的style設(shè)置透明,在手機(jī)鎖屏?xí)rstart爸吮;在屏幕解鎖時(shí)finish芬膝,主要作用就是在App退到后臺(tái)之后且鎖屏的時(shí)候啟動(dòng)一個(gè)看不見的Activity,造成一個(gè)該App沒有回退到后臺(tái)的假象形娇,從而降低被殺的幾率锰霜。
代碼:
在onCreate方法里設(shè)定一像素的activity

        window.setGravity(Gravity.START | Gravity.TOP);
        WindowManager.LayoutParams params = window.getAttributes();
        params.x = 0;
        params.y = 0;
        params.height = 1;
        params.width = 1;
        window.setAttributes(params);

在onReceive方法里進(jìn)行操作

public void onReceive(final Context context, Intent intent) {
        Log.i("ScreenStateReceiver", "---屏幕鎖屏監(jiān)聽---");
        if (action.equals(Intent.ACTION_SCREEN_OFF)) {
           //屏幕鎖定,開啟OnePixelActivity

        } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
           //屏幕解鎖桐早,finish OnePixelActivity
        }
    }

說一下詳細(xì)步驟
1.需要注冊(cè)一個(gè)監(jiān)聽屏幕鎖屏和解屏的BroadcastReceiver
關(guān)于這一點(diǎn)有一個(gè)細(xì)節(jié)需要處理癣缅,為了放置用戶快速進(jìn)行鎖屏和解屏的切換操作,而導(dǎo)致OnePixelActivity頻繁開關(guān)友存。需要用一個(gè)Handler發(fā)送一個(gè)延遲消息處理最佳:

    private Handler mHandler;
    private boolean isScreenOn = true;
    private PendingIntent  pendingIntent;
    private List<ScreenStateListener> screenStateListeners = null;
    @Override
    public void onReceive(final Context context, Intent intent) {
        String action = intent.getAction();
      
        if (action.equals(Intent.ACTION_SCREEN_OFF)) {
           //標(biāo)記屏幕為鎖屏狀態(tài)
            isScreenOn = false;
            //開啟一像素的Activity
            startOnePixelActivity(context);

        } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
            //標(biāo)記屏幕為解屏狀態(tài)
            isScreenOn = true;     
            if(pendingIntent!=null){
                pendingIntent.cancel();
            }
     
        }
    }

  //開啟一像素的Activity
    private void startOnePixelActivity(final Context context){
        if(mHandler==null){
            mHandler = new Handler(Looper.myLooper());
        }
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
              //如果屏幕此時(shí)已經(jīng)打開,則不執(zhí)行
                if(isScreenOn){
                    return;
                }
                if(pendingIntent!=null){
                    pendingIntent.cancel();
                }
                
                Intent startOnePixelActivity = new Intent(context, OnePixelActivity.class);
                startOnePixelActivity.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

                //啟動(dòng)一像素包活activity
                pendingIntent = PendingIntent.getActivity(context, 0, startOnePixelActivity, 0);
                try {
                    pendingIntent.send();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                notifyScreenOff();
            }
        },1000);
    }

2爬立、需要將該activity的 android:excludeFromRecents設(shè)置為true
3万哪、需要將該Activity設(shè)置為singleInstance啟動(dòng)模式

<activity android:name=".OnePixelActivity"
            android:theme="@style/onePixelActivity"
            android:launchMode="singleInstance"
            android:excludeFromRecents="true"/>

為什么需要將此Activity的啟動(dòng)模式設(shè)置為singleInstance呢?原因是因?yàn)槿绻O(shè)置成其他模式奕巍,如果按照如下步驟操作的話會(huì)出現(xiàn)不友好的狀況:
1、啟動(dòng)App(比如進(jìn)入MainActivity),按home鍵讓app返回后臺(tái)
2的止、鎖定屏幕檩坚,此時(shí)注冊(cè)好的監(jiān)聽廣播會(huì)啟動(dòng)OnePixelActivity
3匾委、解鎖屏幕,此時(shí)廣播接受到此廣播后會(huì)finish 掉OnePixelActivity.
也就是說氓润,當(dāng)你的app在后臺(tái)的時(shí)候,你解鎖屏幕,創(chuàng)建銷毀OnePixelActvity的同時(shí)會(huì)把整個(gè)棧的activity彈出來,然會(huì)用戶就會(huì)莫名其妙的看到你的app自己打開了。

另外需要注意的是咖气,當(dāng)屏幕解鎖的時(shí)候,OnePixelActivity的onResume得到執(zhí)行崩溪,所以在該Activity的onResume方法執(zhí)行finish效果最好:

//OnePixelActivity的onResume
   protected void onResume() {
        super.onResume();
        if (DeviceUtils.isScreenOn(this)) {//如果屏幕已經(jīng)打開
            finish();
        }
    }

雙進(jìn)程守護(hù)

所謂雙進(jìn)程守護(hù)原理就是很簡單:兩個(gè)進(jìn)程的Service浅役,相互守護(hù);當(dāng)一個(gè)進(jìn)程的Service掛的時(shí)候伶唯,另一個(gè)進(jìn)程的Service負(fù)責(zé)重啟掛掉的Service.因?yàn)橄到y(tǒng)的進(jìn)程回收機(jī)制是一個(gè)個(gè)回收的,利用這個(gè)時(shí)間差來相互喚起,當(dāng)一個(gè)進(jìn)程被磨滅掉,另一個(gè)馬上重啟,缺點(diǎn)是現(xiàn)在大部分機(jī)型只要一鍵清理就玩完了觉既。文中KeepAliveService是跟我們要保活的App處于一個(gè)進(jìn)程的Service乳幸,RemoteService是另外一個(gè)進(jìn)程的Service;將RemoteService設(shè)置成單獨(dú)的進(jìn)程很方便奋救,在AndroidMainfest.xml里面配置 android:process即可。

<service android:name=".KeepAliveService"/>
//將RemoteService和KeepAliveServcie處于不同的進(jìn)程
<service android:name=".RemoteService" android:process=":remote"/>

守護(hù)進(jìn)程其實(shí)是一個(gè)雙向守護(hù)的過程反惕,比如KeepAliveService掛了尝艘,那么RemoteService負(fù)責(zé)將KeepAliveService重啟;同理姿染,如果RemoteService掛了的話背亥,KeepAliveService負(fù)責(zé)將RemoteService重啟秒际!那么二者是怎么知道彼此是否掛了呢?因?yàn)槭俏挥趦蓚€(gè)進(jìn)程狡汉,所以我們可以通過AIDL來確保兩個(gè)不同進(jìn)程的Service可以通信娄徊。
定義一個(gè)AIDL接口

interface GuardAidl {
    void notifyAlive();
}

接著我們重寫KeepAliveSerivice的onBind方法,該方法返回一個(gè)IBinder給RemoteService使用:

 //將keepAliveBinder 交給RemoteService
    public IBinder onBind(Intent intent) {
        return keepAliveBinder;
    }
 
    private GuardAidl.Stub keepAliveBinder = new GuardAidl.Stub(){
        @Override
        public void notifyAlive() throws RemoteException {
            Log.i(null,"Hello RemoteService!");
        }
    };

通過KeepAliveService的onBind方法返回一個(gè)IBinder對(duì)象交給RemoteService使用盾戴,這樣RemoteService就可以通過keepAliveBinder對(duì)象跟KeepAliveServcie進(jìn)行通信寄锐!同樣的RemoteService也是一樣的代碼邏輯:

public class RemoteService extends Service {
    public IBinder onBind(Intent intent) {
        return remoteBinder;
    }
    private GuardAidl.Stub remoteBinder = new GuardAidl.Stub(){
        @Override
        public void notifyAlive() throws RemoteException {
            Log.i(null,"Hello KeepAliveService!");
        }
    };
}

兩個(gè)Servcie相互綁定
現(xiàn)在兩個(gè)Service都重寫onBind返回了自己的IBinder,但是怎么將自己創(chuàng)建的IBinder 交給對(duì)象使用呢尖啡?答案是雙方調(diào)用bindSerice方法相互綁定對(duì)方橄仆,該方法是Service的一個(gè)方法,其簽名如下:

bindService(Intent service, ServiceConnection conn, int flags)

所以我們綁定的時(shí)候除了傳一個(gè)intent之外衅斩,還要傳一個(gè)ServiceConnection盆顾。看看KeepAliveService綁定RemoteService的代碼:

//KeepAliveService的onStartCommand方法
 public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e("KeepAliveService", "---KeepAliveService 啟動(dòng)---");
        //注冊(cè)鎖屏廣播
        registerScreenStateReceiver();
        //初始化播放器
        initMediaPlayer();
        
        //開啟前臺(tái)Service
        startForeground(this);
        
        //start HideNotifactionService
        startHideNotificationService();
        
        //綁定守護(hù)進(jìn)程
        bindRemoteService();
        
        return START_STICKY;
    }
    
   //綁定守護(hù)進(jìn)程
   private void bindRemoteService(){
        Intent intent = new Intent(this,RemoteService.class);
        bindService(intent,connection,Context.BIND_ABOVE_CLIENT);
    }

   private ServiceConnection connection = new ServiceConnection() {
       //調(diào)用此方法說明RemoteServcie已經(jīng)掛掉畏梆,需要重新啟動(dòng)
        public void onServiceDisconnected(ComponentName name) {
         Intent remoteService = new Intent(KeepAliveService.this,
                        RemoteService.class);
                KeepAliveService.this.startService(remoteService);
                
            Intent intent = new Intent(KeepAliveService.this, RemoteService.class);
            //將KeepAliveService和RemoteService進(jìn)行綁定
            KeepAliveService.this.bindService(intent, connection,
                    Context.BIND_ABOVE_CLIENT);
        }
        
        @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
            try {
                //與RemoteService綁定成功
                GuardAidl remoteBinder = GuardAidl.Stub.asInterface(service);
                remoteBinder.notifyAlive();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    };

其中ServiceConnection有兩個(gè)方法onServiceDisconnected和onServiceConnected您宪,當(dāng)RemoteService被異常銷毀掛掉的時(shí)候,onServiceDisconnected會(huì)被調(diào)用奠涌。此時(shí)需要在該方法里面重新啟動(dòng)RemoteService;而onServiceConnected方法則是系統(tǒng)調(diào)用它來傳送在RemoteService的onBind()中返回的IBinder宪巨!同理,RemoteService綁定KeepAlivce的代碼跟上面雷同溜畅,再此就不在貼出來了捏卓,
源碼可以點(diǎn)擊此處查閱

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市达皿,隨后出現(xiàn)的幾起案子天吓,更是在濱河造成了極大的恐慌,老刑警劉巖峦椰,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件汤功,死亡現(xiàn)場離奇詭異,居然都是意外死亡色解,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門科阎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來忿族,“玉大人蝌矛,你說我怎么就攤上這事入撒⊥盅遥” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵献雅,是天一觀的道長惩琉。 經(jīng)常有香客問我夺荒,道長良蒸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任剿吻,我火速辦了婚禮丽旅,結(jié)果婚禮上纺棺,老公的妹妹穿的比我還像新娘。我一直安慰自己茅撞,他們只是感情好巨朦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布糊啡。 她就那樣靜靜地躺著,像睡著了一般堕扶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上挣柬,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天邪蛔,我揣著相機(jī)與錄音,去河邊找鬼勃教。 笑死匠抗,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的绳军。 我是一名探鬼主播矢腻,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼奶是!你這毒婦竟也來了竣灌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤及汉,失蹤者是張志新(化名)和其女友劉穎豁生,沒想到半個(gè)月后漫贞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡芍殖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年豌骏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片计贰。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蒂窒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出秧秉,到底是詐尸還是另有隱情衰抑,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布砾淌,位于F島的核電站拇舀,受9級(jí)特大地震影響逻族,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜薄辅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一站楚、第九天 我趴在偏房一處隱蔽的房頂上張望搏嗡。 院中可真熱鬧,春花似錦采盒、人聲如沸尺栖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至者蠕,卻和暖如春蠢棱,著一層夾襖步出監(jiān)牢的瞬間甩栈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來泰國打工玉转, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留殴蹄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓刺下,卻偏偏與公主長得像稽荧,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子畅卓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

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