RemoteService之AIDL进程间通信 ---基于AndroidStudio

最近项目中碰到个问题,应用退出之后(通过调用System.exit(0)),弹出的Toast很久的不消失。

原因是项目中使用了环信的SDK,其中有个处理后台推送的Service环信专门为其加了个so文件,目的是为了防止Service被杀死。

同事将该Service设置为android:process = "remote" ,即使Service运行的进程与主进程分开,toast确实是消失了,但是后台就无法接受到推送了。

原因肯定是Service在其他进程了,而之前环信开发时又未做处理,所以已经无法与主进程通信了。


因为之前很少涉及到多进程的项目,所以就专门去研究了下AIDL的用法。

简单来说一下AIDL使用步骤:

1.编写一个AIDL文件。其实就是一个JAVA interface而已,只是文件名需要以.aidl结尾。

如果使用AndroidStudio进行开发,可直接建立AIDL文件,见下图:


建好之后,目录中会多一个名为aidl的文件夹,然后在.aidl文件中实现自己的方法,例如:

// IRemoteServiceStock.aidl
package k.javine.myremoteservice;

interface IRemoteServiceStock {
    //自己实现的方法
    int getPid();
    int getCount();
}

2.建立一个Service类,并在其中实现aidl接口方法,以供客户端调用。

这个过程跟编写正常的Service差不多,只是多了一个Stub的实现,直接上代码吧。

public class MyRemoteService extends Service {
    private static int bindCount = 0;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("Javine", "Create Service pid = "+ Process.myPid());
    }

    //实现AIDL接口
    private final IRemoteServiceStock.Stub mBinder = new IRemoteServiceStock.Stub(){

        @Override
        public int getPid() throws RemoteException {
            return android.os.Process.myPid();
        }

        @Override
        public int getCount() throws RemoteException {
            return bindCount;
        }
    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        bindCount++;
        return mBinder;
    }

    @Override
    public void onDestroy() {
        Log.d("Javine", "Destroy Service");
        super.onDestroy();
    }
}

3.在主进程中调用远端进程的Service中的内容。

我们都知道,如果要调用Serivce中的函数,需要在Activity中实现ServiceConnection接口,并重写其中的方法。这里会将AIDL接口作为IBinder返回给Activity,这样就可以在Acitivy中调用RemoteService中的函数了。

代码如下:

    class MyConnection implements ServiceConnection{

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            if (progressDialog.isShowing())
                progressDialog.dismiss();
            remoteServiceStock = IRemoteServiceStock.Stub.asInterface(service);//获取远端进程Service返回的AIDL接口
            String info = null;
            try {
                servicePid = remoteServiceStock.getPid();
                info = "Process Id: "+remoteServiceStock.getPid()+"\nBind Count: "+remoteServiceStock.getCount();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            if (info!=null){
                textInfo.setText(info);
                unBindBtn.setEnabled(true);
                killBtn.setEnabled(true);
            }else{
                textInfo.setText("获取失败");
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            remoteServiceStock = null;
        }
    }

好了,到此三步骤就走完了。

不过有几个地方需要重要注意一下:

1.在AndroidManifest.xml中声明Service,并且指定android:process = ":remote"属性。这里的remote前面加“:”代表应用内才能调用的远端进程,若没有":"代表其他应用也可调用。

2.如何启动远程service?

如果在同一个应用内,可通过Intent(this,xxxService.class)的方式,直接start或者onbind。

如果不在同一个应用内,则需通过给Service设置<action>属性,然后客户端通过intent.setAction()来隐式启动。


为此,我也编写了一个Demo,并且发现一个有趣的问题。

如果Activity已经绑定了remoteService,然后kill掉remoteService所在的远端进程,大概1s后系统会为remoteService新建一个进程,并且Service还是处于bind状态。

Demo截图



demo源码MyRemoteService

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值