要点
如何在一个app里开启两个进程
manifest.xml配置:<!--实现了在另一个进程里运行的Service,android:process=".remoteservice"--> <!--必须是双进程,不然起一堆Service也没用,杀死一个进程就全都杀死了--> <service android:name=".RemoteService" android:enabled="true" android:exported="true" android:process=".remoteservice"> </service>
为什么要开启两个进程
如果,你在同一个进程里开启了两个Service,进行互相守护(一个死之前,调用另外一个),是不行的,因为系统杀死一个进程时,会把这个进程里的所有Service全部杀死,两个同时死亡了,如何守护呢。但是双进程就不同了,cpu切换的再快,他也是杀死一个,再去杀死另一个,只要不是同时死亡,就能实现守护
如何实现一个进程的服务杀死之前,去开启另一个进程的服务
关键是绑定服务的时候,实现的一个接口ServiceConnection,这里重写的第二个方法onServiceDisconnected(),这个方法不会在unBind时候调用,而是在其绑定的服务在异常终止时,才会调用,ok就是这里,我们的Service被第三方应用杀死了,就属于异常终止,这里我们就能在这个回调里去实现再次开启另一个Service的操作,即守护操作在这里进行
class MyConn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e("qqq","连接远程服务成功了");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e("qqq","远程服务意外中断了,注意如果解绑不会调用此方法");
Toast.makeText(LocalService.this, "远程服务意外中断了", Toast.LENGTH_SHORT).show();
LocalService.this. startService(new Intent(LocalService.this,RemoteService.class));
LocalService.this. bindService(new Intent(LocalService.this, RemoteService.class), conn, Context.BIND_IMPORTANT);
}
}
基础知识
- aidl:用于进程间通讯(IPC机制),因为我们这里的Service在两个5进程中,要互相通讯,必须aidl
- 开启服务:当开启一个服务后StartService,他会一直运行在后台,即使开启他的组件(Activity或者Service)死亡了,他依然存活着,但是第三方把他杀死或者手机设置—进行中的服务—停止服务,这样会把这个服务杀死,我们创建不死的Service,就是在这种情况下,他依然会重启。
- 绑定服务:绑定一个Service,通过binder进行通讯,可以调用Service内部的方法(StartService不可调用Service内部方法)
一个坑
不要重写onStart()方法了,已经过时了,特别是在6.0以上系统运行时,使用该方法会出现问题,要使用onStartCommand()
上代码
MainActivity
package com.mine.keepervicealive;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 开启两个服务,这两个服务永远在后台启动,不随着启动他的Activity死亡而死亡
// 当然此刻,你手动杀死他的话,他会死的
this.startService(new Intent(MainActivity.this, LocalService.class));
this.startService(new Intent(MainActivity.this, RemoteService.class));
}
}
IMyAidlInterface.aidl
// IMyAidlInterface.aidl
package com.mine.keepervicealive;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
String getServiceName();
}
LocalService
package com.mine.keepervicealive;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;
/**
* 相互绑定服务,使用aidl
*/
public class LocalService extends Service {
private MyBinder mBinder;
private MyConn conn;
public LocalService() {
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onCreate() {
super.onCreate();
mBinder = new MyBinder();
if (conn == null) {
conn = new MyConn();
}
}
// 注意不要写到onStart方法里,他过时了,导致进程守护失败
/* @Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
// 绑定另一个服务
bindService(new Intent(LocalService.this, RemoteService.class), conn, Context.BIND_IMPORTANT);
}*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 绑定另一个服务
bindService(new Intent(LocalService.this, RemoteService.class), conn, Context.BIND_IMPORTANT);
return super.onStartCommand(intent, flags, startId);
}
class MyConn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e("qqq","连接远程服务成功了");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e("qqq","远程服务意外中断了,注意如果解绑不会调用此方法");
Toast.makeText(LocalService.this, "远程服务意外中断了", Toast.LENGTH_SHORT).show();
LocalService.this. startService(new Intent(LocalService.this,RemoteService.class));
LocalService.this. bindService(new Intent(LocalService.this, RemoteService.class), conn, Context.BIND_IMPORTANT);
}
}
class MyBinder extends IMyAidlInterface.Stub {
@Override
public String getServiceName() throws RemoteException {
return "本地服务";
}
}
}
RemoteService
package com.mine.keepervicealive;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;
public class RemoteService extends Service {
private MyBinder1 mBinder1;
private MyConn1 mConn1;
public RemoteService() {
}
@Override
public IBinder onBind(Intent intent) {
return mBinder1;
}
@Override
public void onCreate() {
super.onCreate();
mBinder1 = new MyBinder1();
if (mConn1==null){
mConn1 = new MyConn1();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 绑定另一个服务
bindService(new Intent(RemoteService.this, LocalService.class), mConn1, Context.BIND_IMPORTANT);
return super.onStartCommand(intent, flags, startId);
}
class MyBinder1 extends IMyAidlInterface.Stub {
@Override
public String getServiceName() throws RemoteException {
return "111";
}
}
class MyConn1 implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e("qqq","连接服务本地成功了");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Toast.makeText(RemoteService.this, "本地服务意外中断了", Toast.LENGTH_SHORT).show();
RemoteService.this. startService(new Intent(RemoteService.this,LocalService.class));
RemoteService.this. bindService(new Intent(RemoteService.this, LocalService.class), mConn1, Context.BIND_IMPORTANT);
}
}
}
Manifest .xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mine.keepervicealive">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!--传统的本地线程-->
<service
android:name=".LocalService"
android:enabled="true"
android:exported="true">
</service>
<!--实现了在另一个线程里运行的Service,android:process=".remoteservice"-->
<!--必须是双进程,负责起一堆Service也没用,杀死一个线程就全都杀死了-->
<service
android:name=".RemoteService"
android:enabled="true"
android:exported="true"
android:process=".remoteservice">
</service>
</application>
</manifest>