码迷,mamicode.com
首页 > 移动开发 > 详细

AndroidStudio通过AIDL开启、绑定远程Service

时间:2016-04-17 22:52:13      阅读:286      评论:0      收藏:0      [点我收藏+]

标签:

前言

  关于服务的启动方式(startService()、stopService()、bindService()、unbindService()),我这里就不多说了,可以参考这篇博文

示例原理图

  本文以一个简单的案例,记录一下怎么使用AIDL结合服务实现进程间的通信:
  首先,创建两个项目,一个项目(RemoteService)作为远程服务提供端,另一个(RemoteServiceTest)作为调用远程服务的客户端.然后,当客户端绑定远程服务后,可以通过AIDL接口调用远程服务中的方法,原理过程如图:
技术分享

远程服务RemoteService 项目

1.创建AIDL文件,选中要提供的服务类所在的包名,右键 -> New -> AIDL -> AIDL File文件,如图
技术分享
这里将AIDL文件命名为RemoteInterface,创建完成后,会在main下生成一个aidl文件夹,一个包名与刚刚选中的包名相同的包,包下生成了一个RemoteInterface.aidl,如图
技术分享

2.打开RemoteInterface.aidl文件,定义一个接口方法 remotePrintInterface(); 重新编译一下项目,如果成功编译那么会在如下目录中生成一个RemoteInterface接口文件
技术分享
注意不要修改这个接口文件,接口中有一个重要的 Stub类,是之后要用的,Stub类继承了Binder,并实现了RemoteInterface接口。
技术分享

3.创建一个服务类如RemoteService让其继承自Service, 服务中定义一个方法remotePrint(),并定义一个内部类 MyBinder 继承自 Stub, 实现Stub或者说RemoteInterface接口中的remotePrintInterface()的方法,让这个方法去调用服务的remotePrint()方法,代码如下:

package com.yu.remoteservice;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.Toast;

/**
 * Created by yu on 2016/4/15.
 */
public class RemoteService extends Service {

    private static final String TAG = "RemoteService";

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG,"RemoteService 绑定 ------------------------------------------");
        Toast.makeText(this,"远程服务绑定",Toast.LENGTH_SHORT).show();
        return new MyBinder();//一定要记得返回 MyBinder 对象
    }

    //内部类继承自Stub
    class MyBinder extends RemoteInterface.Stub{
        //实现RemoteInterface中的方法
        @Override
        public void remotePrintInterface() {
            //调用服务的方法
            remotePrint();
        }
    }

    public void remotePrint() {
        Log.d(TAG,"通过接口调用 RemoteService 的 remotePrint 方法");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG,"RemoteService 创建 ------------------------------------------");
        Toast.makeText(this,"远程服务创建",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG,"RemoteService 销毁 ------------------------------------------");
        Toast.makeText(this,"远程服务销毁",Toast.LENGTH_SHORT).show();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(TAG,"RemoteService 解绑 ------------------------------------------");
        Toast.makeText(this,"远程服务绑定",Toast.LENGTH_SHORT).show();
        return super.onUnbind(intent);
    }
}

4.在清单文件中注册服务

<service android:name=".RemoteService">
    <intent-filter>
        <action android:name="com.yu.remote"/>
    </intent-filter>
</service>

通过上面的步骤,服务端就算码完了,客户端绑定服务后,可以通过onBind方法返回的MyBinder对象中的方法来间接调用服务中的方法。

客户端RemoteServiceTest 项目:

1.目的是要在main下生成一个跟RemoteService中的aidl一毛一样的文件,做法是:
  1)在main下创建一个aidl文件夹
  2)在aidl文件夹下创建一个包,包名跟服务端aidl文件所在的包名一样,此处即为com.yu.remoteservice
  3)拷贝服务端的RemoteInterface.aidl文件到包下。
  4)rebuild project,结束后,应该会生成和服务端一毛一样的接口
结果如图
技术分享

2.绑定服务,得到服务返回的Ibinder对象,强转为接口的类型,并调用接口的方法,去间接调用服务中的方法

客户端代码如下:

package com.yu.remoteservicetest;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.yu.remoteservice.RemoteInterface;

public class MainActivity extends AppCompatActivity {

    private final String TAG = "RemoteServiceTest";
    //远程服务的包名
    private final String RemoteServicePackage = "com.yu.remoteservice";
    //绑定服务时的连接对象
    private ServiceConnection conn = null;
    //通过aidl创建的接口类的对象
    private RemoteInterface ri = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void start(View view) {
        Intent intent = new Intent();
        //设置意图对象要匹配的action
        intent.setAction("com.yu.remote");
        //android 5.0之后
        //设置包名,这里测试了一下,必须是服务所在的包名才可以
        intent.setPackage(RemoteServicePackage);
        startService(intent);
    }
    public void stop(View view) {
        Intent intent = new Intent();
        intent.setAction("com.yu.remote");
        intent.setPackage(RemoteServicePackage);
        stopService(intent);
    }
    //绑定服务
    public void bind(View view) {
        Intent intent = new Intent();
        intent.setAction("com.yu.remote");
        intent.setPackage(RemoteServicePackage);
        if (conn == null) {
            //创建连接服务的对象
            conn = new RemoteServiceConnection();
        }
        bindService(intent,conn,BIND_AUTO_CREATE);
    }
    public void unbind(View view) {
        if (conn != null) {
            unbindService(conn);
            conn = null;
        }

    }
    //调用服务的方法
    public void callRemotePrint(View view) {

        Log.d(TAG,"callRemotePrint........................");
        if (ri != null) {
            try {
                //通过调用接口对象的remotePrintInterface方法,简介调用服务的remotePrint方法
                ri.remotePrintInterface();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        } else {
            Toast.makeText(this,"remote interface is null",Toast.LENGTH_SHORT).show();
        }
    }

    //实现ServiceConnection类,用于创建连接服务的对象
    class RemoteServiceConnection implements ServiceConnection {

        //当使用bindService方法绑定服务,并且服务返回IBinder对象的时候会调用
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG,"onServiceConnected........................");

            //强转为接口对象
            ri = RemoteInterface.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (conn != null) {
            unbindService(conn);
            conn = null;
        }
    }
}

客户端界面
技术分享

文件目录结构

客户端文件目录结构
技术分享

远程服务文件目录结构
技术分享

遇到的问题:

1.在创建aidl文件后,没有去自动生成相应的接口,reBuild后报以下错误:

Error:Execution failed for task ‘:app:compileDebugAidl’.
java.lang.RuntimeException:
com.android.ide.common.process.ProcessException:
org.gradle.process.internal.ExecException: Process ‘command
‘F:\Study\Android\soft\adt-bundle-windows-x86_64-20140321\sdk\build-tools\24.0.0-preview\aidl.exe”
finished with non-zero exit value 1

搜了一下,大概是说 项目的编译版本和编译工具的版本不一致。。。蛋碎。。。
最后解决的办法是:
右键项目 open Moudle Setting -> app -> 修改Compile Sdk Version 和Build Tools Version 版本一致。

2.无论是startService还是bindService都没有能够启动远程服务:
原因是android5.0以后表面上是不能隐式启动Service的,参考这篇文章
而且,intent.setPackage(RemoteServicePackage);必须设置为服务所在的包名,否则是不能开启服务的,而且没有任何错误或警告给出。。。

AndroidStudio通过AIDL开启、绑定远程Service

标签:

原文地址:http://blog.csdn.net/man_help/article/details/51173450

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!