Android Service 远程服务
来源:互联网 发布:oss 阿里云 编辑:程序博客网 时间:2024/05/16 06:00
远程服务的创建和调用需要使用AIDL语言,步骤如下:
使用AIDL语言定义远程服务的接口
通过继承Service类实现接口中定义的方法和属性
绑定和使用远程服务
以下为一个简单Demo ,RemoteMathCallerDemo界面如下:
绑定远程服务后,调用RemoteMathServiceDemo中的MathService服务进行加法运算。
1.使用AIDL语言定义远程服务的接口
以Android Studio为例,首先需要建立对应目录及aidl文件,如下:
(比如直接在java目录下的包上右键新建aidl文件 IDE会自动生成aidl目录及该目录下的包和文件这样的小技巧我可不会随便告诉别人)
IMathService.aidl文件内容如下:
// IMathService.aidlpackage com.example.remotemathservicedemo;// Declare any non-default types here with import statementsinterface IMathService { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ long Add(long a,long b);}
然后在build目录下会自动生成与该aidl文件对应的java接口文件,(若没有生成则重新make project) 如下:
在看IMathService.java内容之前呢,不知道你有没有注意到,我前两张截图都截到了上面的一个Module:remotemathcallerdemo,这个就是调用端,目前我们编辑的remotemathservicedemo是服务端。
下面为IMathService.java的完整代码,加上了我自己的理解和注释:
/* * 这个文件是自动生成的。不要修改 */package com.example.remotemathservicedemo;/* 在这里声明任何非默认类型 所有使用AIDL建立的接口都必须继承 android.os.IInterface 基类接口 这个基类接口中定义了 asBinder()方法 用来获取Binder对象 */public interface IMathService extends android.os.IInterface { /** * 本地IPC实现stub类 */ public static abstract class Stub extends android.os.Binder implements com.example.remotemathservicedemo.IMathService { private static final java.lang.String DESCRIPTOR = "com.example.remotemathservicedemo.IMathService"; public Stub() { this.attachInterface(this, DESCRIPTOR); } //asInterface(IBinder) 是Stub内部的远程服务接口,调用者可以通过该方法获得远程服务的实例 public static com.example.remotemathservicedemo.IMathService asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); //判断android.os.IInterface实例是否为本地服务 若是返回android.os.IInterface //若不是本地服务 构造Proxy对象并返回之 if (((iin != null) && (iin instanceof com.example.remotemathservicedemo.IMathService))) { return ((com.example.remotemathservicedemo.IMathService) iin); } return new com.example.remotemathservicedemo.IMathService.Stub.Proxy(obj); } //实现了android.os.IInterface接口定义的asBinder()方法 @Override public android.os.IBinder asBinder() { return this; } /* Parcel是Android系统应用程序间传递数据的容器,能够在两个进程中完成打包和拆包的工作 但Parcel不同于通用意义上的序列化 Parcel的设计目的是用于高性能IPC传输 不能将其保存在持久存储设备上 */ //接收Parcel对象,并从中逐一读取每个参数,然后调用Service内部制定的方法,将结果写进另一个Parcel对象, // 准备将这个Parcel对象返回给远程的调用者 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_Add: { data.enforceInterface(DESCRIPTOR); long _arg0; _arg0 = data.readLong(); long _arg1; _arg1 = data.readLong(); long _result = this.Add(_arg0, _arg1); reply.writeNoException(); reply.writeLong(_result); return true; } } return super.onTransact(code, data, reply, flags); } //用来实现远程服务调用 private static class Proxy implements com.example.remotemathservicedemo.IMathService { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } //以一定顺序将所有参数写入Parcel对象,以供Stub内部的onTransact()方法获取参数 @Override public long Add(long a, long b) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); long _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeLong(a); _data.writeLong(b); mRemote.transact(Stub.TRANSACTION_Add, _data, _reply, 0); _reply.readException(); _result = _reply.readLong(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_Add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); }public long Add(long a, long b) throws android.os.RemoteException;}
IMathService.aidl是对远程服务接口的定义,自动生成的IMathService.java内部实现了远程服务数据传递的相关方法,下一步介绍如何实现远程服务,这需要建立一个Service类,并在该类中通过onBind()方法返回IBinder对象,这样调用者使用获取的IBinder对象就可以访问远程服务。
下面是MathService.java的完整代码:
package com.example.remotemathservicedemo;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.support.annotation.Nullable;import android.widget.Toast;/** * Created by yinghao on 2016/5/7. */public class MathService extends Service { /* 1. 建立 IMathService.Stub的实例mBinder并实现AIDL文件定义的远程服务接口 2. 在onBind()方法中将mBinder返回给远程调用者 */ private final IMathService.Stub mBinder = new IMathService.Stub(){ @Override public long Add(long a, long b) throws RemoteException { return a + b; } }; @Nullable @Override public IBinder onBind(Intent intent) { Toast.makeText(MathService.this, "远程绑定:MathService", Toast.LENGTH_SHORT).show(); return mBinder; } //Return true if you would like to have the service's onRebind method later called when new clients bind to it. @Override public boolean onUnbind(Intent intent) { Toast.makeText(MathService.this, "取消远程绑定", Toast.LENGTH_SHORT).show(); return false; }}
最后一步,注册service:
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.remotemathservicedemo"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <service android:name=".MathService" android:process=":remote"> <intent-filter> <action android:name="com.example.remote.MathService" /> </intent-filter> </service> </application></manifest>
到这里我们的服务端Module : remotemathservicedemo 就完成了。
这完成了文章开头所列举的三个步骤的前两步,最后一步,让我们来看看怎么绑定和使用远程服务吧。
首先,我们需要引入与服务端相同的aidl文件并确保自动生成对应的IMathService.java接口文件。
那么为什么要这样做呢? 这就需要我们了解aidl文件和对应接口文件的用处到底是什么,为了时数据能穿越进程边界,所有数据都必须是“打包”,而自动生成的IMathService.java内部实现了远程服务数据传递的相关方法,那么服务端就有了将数据打包、拆包的能力。而调用端也需要发出数据和接收数据,也需要有将数据打包、拆包的能力,所以它也需要IMathService.java这个类。
然后对远程服务的绑定与调用,其实与本地服务的绑定区别不大,不同之处主要包括两处:
使用IMathService生命远程服务实例
通过IMathService.Stub的asInterface()方法获取服务实例
下面为remotemathcallerdemo Module中MainActivity.java的完整代码:
package com.example.remotemathcallerdemo;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.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.TextView;import com.example.remotemathservicedemo.IMathService;import org.w3c.dom.Text;public class MainActivity extends AppCompatActivity { private TextView textView; private Button bind; private Button unbind; private Button add; private boolean isBound = false; private IMathService mathService; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mathService = IMathService.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { mathService = null; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.textView); bind = (Button) findViewById(R.id.bind); unbind = (Button) findViewById(R.id.unbind); add = (Button) findViewById(R.id.add); bind.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (!isBound) { final Intent serviceIntent = new Intent(); serviceIntent.setAction("com.example.remote.MathService"); bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE); isBound = true; } } }); unbind.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (isBound) { unbindService(mConnection); isBound = false; mathService = null; } } }); add.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mathService == null) { textView.setText("未绑定远程服务"); return; } long a = Math.round(Math.random() * 100); long b = Math.round(Math.random() * 100); long result = 0; try { result = mathService.Add(a, b); } catch (RemoteException e) { e.printStackTrace(); } String msg = String.valueOf(a) + "+" + String.valueOf(b) + "=" + String.valueOf(result); textView.setText(msg); } }); }}
在此例中传递的数据类型为基本数据类型,打包过程是自动完成的,但对于自定义的数据类型,用户则需要实现Parcelable接口,使自定义的数据类型能够转换为系统级原语保存在Parcel对象中,穿越进程边界后可再转换为初始格式,关于自定义数据类型的传递,在下一篇文章中归纳总结。
- android远程服务service
- Android Service 远程服务
- Android Service -远程服务
- 48.android服务service-启动远程服务
- Android中的服务(service)--AIDL远程服务
- android之服务service远程服务
- android之服务service远程服务
- android之服务service远程服务
- 服务(service)-----远程服务
- service(二) Android Studio 编写远程服务
- Android Service学习之远程服务
- Android Service 调用远程服务中的方法
- android后台服务service全解析(下)--service远程通信
- Android Service(服务)绑定远程服务一个小demo
- Service之《远程服务》
- Service (aidl远程服务)
- Service(远程服务)
- Service(远程服务)
- 学好C语言的推荐途径
- AOJ 0118: Property Disribution(dfs)
- JavaScript字符串操作
- iOS多线程
- 迁移discuz
- Android Service 远程服务
- View的事件分发和工作机制
- enum 在c++中的使用
- 用html5新增的js媒体 API手写的一个视频播放器
- 完美解决myBase Desktop 破解
- 命令使用 su passwd ls
- 文件打开时open系统调用
- Linux 文件系统
- Java面试题集(一)