Android双进程守护

双进程守护:开两个服务,一个是本地进程服务localservice,一个是远程进程服务remoteservice,同时使用aidl来进行通信,在onstartcommand方法里启动并绑定服务,在各自的serverconnection里监听对方服务是否被kill,一旦监测到被kill,立马start对方服务,在ondestroy中解绑服务,代码逻辑写在onstartcommand方法里

以上是我理解的双进程守护,如有错误,还望路过的大佬指出,小弟在此先行谢过
测试机型:小米Note3
系统版本:Android 9

一、单进程服务

正常情况下只开一个本地服务的话,代码如下

public class LocalService extends Service {

    private Vibrator vibrator;
    
	@Override
    public IBinder onBind(Intent intent) {
        return null;
    }

  	public LocalService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
    }
    
 	@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("LocalService onStartCommand: LocalService 启动");
        Toast.makeText(LocalService.this, " 本地服务started", Toast.LENGTH_SHORT).show();
        new Thread(new BackgroundRun()).start();
        return START_STICKY;
    }

 class BackgroundRun implements Runnable {

        @Override
        public void run() {
            while (true) {
                System.out.println("Background Run ......");
                vibrator.vibrate(500);
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

然后在manifest中配置

		<service
            android:name=".service.LocalService"
            android:exported="true"
            android:enabled="true" />

再到Application中去启动service

public class MyApp extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        if (isMainProcess(getApplicationContext())) {
            startService(new Intent(this, LocalService.class));
        } else {
            return;
        }
	}
	
	/**
     * 获取当前进程名
     */
    public String getCurrentProcessName(Context context) {
        int pid = android.os.Process.myPid();
        String processName = "";
        ActivityManager manager = (ActivityManager) context.getApplicationContext().getSystemService
                (Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningAppProcessInfo process : manager.getRunningAppProcesses()) {
            if (process.pid == pid) {
                processName = process.processName;
            }
        }
        return processName;
    }

 	/**
     * 是否为主进程
     */
    public boolean isMainProcess(Context context) {
       
        boolean isMainProcess;
        isMainProcess = context.getApplicationContext().getPackageName().equals
                (getCurrentProcessName(context));
        return isMainProcess;
    }

以上代码运行后,控制台会每隔10秒打印一条日志,震动0.5秒,此时如果把应用退到后台运行,或者直接息屏,那么一分钟后,日志将不再打印,震动也同时停止,因为此时服务已被系统kill掉了

二、双进程守护

对localservice添加一些代码

	MyBinder binder;
	
 	@Override
    public IBinder onBind(Intent intent) {
        binder = new MyBinder();
        return binder;
    }

 	class MyBinder extends IMyAidlInterface.Stub {
        @Override
        public String getServiceName() throws RemoteException {
            return LocalService.class.getSimpleName();
        }
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("LocalService onStartCommand: LocalService 启动");
        Toast.makeText(LocalService.this, " 本地服务started", Toast.LENGTH_SHORT).show();
        new Thread(new BackgroundRun()).start();
        startService(new Intent(LocalService.this, RemoteService.class));
        bindService(new Intent(LocalService.this, RemoteService.class), conn, Context.BIND_IMPORTANT);
        return START_STICKY;
    }

 private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            IMyAidlInterface iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            try {
                System.out.println( "LocalService connected with " + iMyAidlInterface.getServiceName());
                //TODO whh 本地service被拉起,检测如果mainActivity不存在则拉起
                if (MyApp.getMainActivity() == null) {
                    Intent intent = new Intent(LocalService.this.getBaseContext(), MainActivity.class);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    getApplication().startActivity(intent);
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Toast.makeText(LocalService.this, "远程服务killed", Toast.LENGTH_SHORT).show();
            System.out.println( "LocalService 远程服务killed");
            //开启远程服务
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                LocalService.this.startForegroundService(new Intent(LocalService.this, RemoteService.class));
            } else {
                LocalService.this.startService(new Intent(LocalService.this, RemoteService.class));
            }
//            LocalService.this.startService((new Intent(LocalService.this, RemoteService.class)));
            //绑定远程服务
            LocalService.this.bindService(new Intent(LocalService.this, RemoteService.class), conn, Context.BIND_IMPORTANT);
        }
    };

    @Override
    public void onDestroy() {
        unbindService(conn);
        super.onDestroy();
    }

MyApp中也要添加一些代码,MainActivity就是manifest配置的入口类

 public static MainActivity getMainActivity() {
        return mainActivity;
    }

新建一个aidl文件
在这里插入图片描述

// IMyAidlInterface.aidl
package com.xmliu.locationdemo;

// Declare any non-default types here with import statements

interface IMyAidlInterface {

    String getServiceName();
}

之后clean项目,会生成aidl相关文件供调用
接下来看远程服务remoteservice

package com.xmliu.locationdemo.service;

import android.app.Notification;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.widget.Toast;

import com.xmliu.locationdemo.IMyAidlInterface;

/**
 * Date: 2019/11/13 10:47
 * Email: diyangxia@163.com
 * Author: diyan
 * Description: TODO
 */
public class RemoteService extends Service {
     MyBinder binder;

    public RemoteService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        binder = new MyBinder();
        return binder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        startForeground(1,new Notification());
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("RemoteService 远程服务started");
        Toast.makeText(this, " 远程服务started", Toast.LENGTH_SHORT).show();
        this.bindService(new Intent(this, LocalService.class), conn, Context.BIND_IMPORTANT);

        return START_STICKY;
    }

    class MyBinder extends IMyAidlInterface.Stub {
        @Override
        public String getServiceName() throws RemoteException {
            return RemoteService.class.getSimpleName();
        }
    }

    private ServiceConnection conn = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            IMyAidlInterface iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            try {
                System.out.println("RemoteService connected with " + iMyAidlInterface.getServiceName());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            System.out.println("RemoteService 本地服务killed");
            Toast.makeText(RemoteService.this, "本地服务killed", Toast.LENGTH_SHORT).show();

            //开启本地服务
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                RemoteService.this.startForegroundService(new Intent(RemoteService.this, LocalService.class));
            } else {
                RemoteService.this.startService(new Intent(RemoteService.this, LocalService.class));
            }
//            RemoteService.this.startService(new Intent(RemoteService.this, LocalService.class));
            //绑定本地服务
            RemoteService.this.bindService(new Intent(RemoteService.this, LocalService.class), conn, Context.BIND_IMPORTANT);
        }

    };

    @Override
    public void onDestroy() {
        unbindService(conn);
        super.onDestroy();
    }
}

manifest中添加配置

  <!--运行在“:RemoteService”线程,防止两个服务一起被杀死-->
        <service
            android:name=".service.RemoteService"
            android:process=":remoteservice"
            android:enabled="true"
            android:exported="true"></service>

注意点:

  • startservice要区分api版本使用不同方法,不然会报错Not allowed to start service Intent
  • bindservice后记得在ondestroy中解绑服务,不然会报错that was originally bound here

三、参考博文

  1. android双进程守护,让程序崩溃后一定可以重启
  2. Android 双进程守护(分分钟实现)
  3. android双进程守护(aidl通信)
  4. Android Service保活方法总结(不被杀死)双进程守护
  5. Android实现双进程守护
  6. Android SERVICE后台服务进程的守护
发布了96 篇原创文章 · 获赞 105 · 访问量 32万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览