本地服务和远程服务AIDL

来源:互联网 发布:淘宝网上禁止出售滥用 编辑:程序博客网 时间:2024/04/27 18:42
AIDL            使用场景:从字面意思理解  Android Interface Definition Language,安卓接口定义语言,用于生成可以在Android设备上两个进程之间进行进程间通信(IPC improcess comunication)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。

AIDL IPC机制是面向接口的,它是使用代理类(stub)在客户端和实现端传递数据。

在Android中,每个应用程序都有自己的进程,当需要在不同的进程之间传递对象时,该如何实现呢?显然,Java中是不支持跨进程内存共享的,因此要传递对象,需要把对象解析成操作系统能够理解的数据格式,以达到跨界对象访问的目的。在Android中,则采用AIDL(Android Interface Definition Language :接口定义语言)方式实现。  

  1.     使用场景:当仅有2个应用要互相通讯时,我们使用Messenger类,而不使用AIDL的方式,

  2.     Android使用AIDL来完成进程间通信(IPC),AIDL全程为Android Interface Definition Language。在服务需要接受不同应用多线程的请求时才需要使用AIDL,如果是同一个应用内的请求使用Binder实现即可,见应用内交互的服务;如果只是应用间通信而不是多线程处理的话使用Messenger,当然这两种情况也可以使用AIDL。本地进程和远程进程使用AIDL有所不同,本地进程内调用时会都在调用的线程内执行,远程进程使用是通过Service进程内一个由系统维护的线程池发出调用,所以可能是未知线程同时调用,需要注意线程安全问题。            

  3.     使用场景:当我们有多个客户端(应用程序)要与服务端进行通讯时,即在服务需要接受不同应用多线程的请求时才需要使用AIDL。
  1. 所有相关代码及例子:

  2. http://www.cnblogs.com/trinea/archive/2012/11/08/2701390.html
  3. http://www.cnblogs.com/trinea/archive/2012/11/08/2699856.html

 Service在工作中也用的很多,但是AIDL就用的很少了,感觉也很生疏,之前也看过一些技术文章,但是感觉依然朦朦胧胧的。现在把AIDL又看了一遍,发现其实并不用理解的那么复杂,其实很简单的一个RPC(IPC)机制。

使用AIDL涉及到的前提是:需要跟其他应用的Service进行数据交换或者是方法调用。(也就是远程操作其他Service)。否则如果没有数据交换或方法调用,直接使用startService()即可;本地Service更加无需AIDL。 

明确这个大前提后,来看AIDL所涉及的几个知识点:

1.ServiceConnection接口:实现这个接口后可以实现Service连接状态的回调方法onServiceConnected(ComponentName component, IBinder service)和onServiceDisconnected(ComponentName component)。

2.IBinder接口

3.Binder类:Binder可以想象成一个内存共享对象,这个对象只有方法暴露出来给客户端调用。

4.Stub静态内部类:其实就是继承了Binder和实现了自己定义的AIDL接口的一个类(所谓的代理),就是一个实现了自己定义的接口的一个Binder。

5.实现了Parcelable序列化接口的自定义Java Bean:如果传输简单数据,根本没必要。(顺便说两句:1.要想把数据存储到磁盘或者是通过网络传输,一定要序列化;2.最为经常使用的Bundle其实就是一个Parcelable,可以通过Bundle来理解Parcelable)

使用AIDL要注意的地方:

1.文件名字一定要以.aidl结尾

2..aidl文件的包名很重要,Service端和调用端包名一定要保持一致。

    为什么要使用AIDL,他的优势有哪些呢?
    AIDL服务更像是 一个Server,可以为多个应用提供服务。由于使用了IDL这样类似COM组件或者说中间语言的设计,可以让后续的开发者无需了解内部,根据暴漏的接口实现相关的操作,AIDL可以工作在独立的进程中。
     
    作为Android上服务的扩展,首先你要了解Android Service模型,Android Serivice我们可以分为两种模式,三个类型,1.最简单的Service就是无需处理onBind方法,一般使用广播通讯,效率比较低。2. 使用Binder模式处理Service和其他组件比如Activity通讯和交互。3.两个进程之间进行进程间通信(IPC improcess comunication)
以下的例子为转载:

编写不需和Activity交互的本地服务示例

本地服务编写比较简单。首先,要创建一个Service类,该类继承android的Service类。这里写了一个计数服务的类,每秒钟为计数器加一。在服务类的内部,还创建了一个线程,用于实现后台执行上述业务逻辑。

package com.easymorse;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.util.Log;public class CountService extends Service {    private boolean threadDisable;    private int count;    @Override    public IBinder onBind(Intent intent) {        return null;    }    @Override    public void onCreate() {        super.onCreate();        new Thread(new Runnable() {            @Override            public void run() {                while (!threadDisable) {                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                    }                    count++;                    Log.v("CountService", "Count is " + count);                }            }        }).start();    }    @Override    public void onDestroy() {        super.onDestroy();        this.threadDisable = true;        Log.v("CountService", "on destroy");    }    public int getCount() {        return count;    }}
需要将该服务注册到配置文件AndroidManifest.xml中,否则无法找到:

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.easymorse" android:versionCode="1" android:versionName="1.0">    <application android:icon="@drawable/icon" android:label="@string/app_name">        <activity android:name=".LocalServiceDemoActivity"            android:label="@string/app_name">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>        <service android:name="CountService" />    </application>    <uses-sdk android:minSdkVersion="3" /></manifest> 
在Activity中启动和关闭本地服务。
package com.easymorse;import android.app.Activity;import android.content.Intent;import android.os.Bundle;public class LocalServiceDemoActivity extends Activity {    /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        this.startService(new Intent(this, CountService.class));    }    @Override    protected void onDestroy() {        super.onDestroy();        this.stopService(new Intent(this, CountService.class));    }}

可通过日志查看到后台线程打印的计数内容。

编写本地服务和Activity交互的示例

上面的示例是通过startService和stopService启动关闭服务的。适用于服务和activity之间没有调用交互的情况。如果之间需要传递参数或者方法调用。需要使用bind和unbind方法。

具体做法是,服务类需要增加接口,比如ICountService,另外,服务类需要有一个内部类,这样可以方便访问外部类的封装数据,这个内部类需要继承Binder类并实现ICountService接口。还有,就是要实现Service的onBind方法,不能只传回一个null了。

这是新建立的接口代码:

 
package com.easymorse;public interface ICountService {    public abstract int getCount();}
修改后的CountService代码:

package com.easymorse;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.util.Log;public class CountService extends Service implements ICountService {    private boolean threadDisable;    private int count;        private ServiceBinder serviceBinder=new ServiceBinder();        public class ServiceBinder extends Binder implements ICountService{        @Override        public int getCount() {            return count;        }    }    @Override    public IBinder onBind(Intent intent) {        return serviceBinder;    }    @Override    public void onCreate() {        super.onCreate();        new Thread(new Runnable() {            @Override            public void run() {                while (!threadDisable) {                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                    }                    count++;                    Log.v("CountService", "Count is " + count);                }            }        }).start();    }    @Override    public void onDestroy() {        super.onDestroy();        this.threadDisable = true;        Log.v("CountService", "on destroy");    }    /* (non-Javadoc)     * @see com.easymorse.ICountService#getCount()     */    public int getCount() {        return count;    }}

服务的注册也要做改动,AndroidManifest.xml文件:
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.easymorse" android:versionCode="1" android:versionName="1.0">    <application android:icon="@drawable/icon" android:label="@string/app_name">        <activity android:name=".LocalServiceDemoActivity"            android:label="@string/app_name">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>        <service android:name="CountService">            <intent-filter>                <action android:name="com.easymorse.CountService"/>            </intent-filter>        </service>    </application>    <uses-sdk android:minSdkVersion="3" /></manifest> 

Acitity代码不再通过startSerivce和stopService启动关闭服务,另外,需要通过ServiceConnection的内部类实现来连接Service和Activity。

package com.easymorse;import android.app.Activity;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.util.Log;public class LocalServiceDemoActivity extends Activity {    private ServiceConnection serviceConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            countService = (ICountService) service;            Log.v("CountService", "on serivce connected, count is "                    + countService.getCount());        }        @Override        public void onServiceDisconnected(ComponentName name) {            countService = null;        }    };    private ICountService countService;    /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        this.bindService(new Intent("com.easymorse.CountService"),                this.serviceConnection, BIND_AUTO_CREATE);    }    @Override    protected void onDestroy() {        super.onDestroy();        this.unbindService(serviceConnection);    }}

编写传递基本型数据的远程服务

上面的示例,可以扩展为,让其他应用程序复用该服务。这样的服务叫远程(remote)服务,实际上是进程间通信(RPC)。

这时需要使用android接口描述语言(AIDL)来定义远程服务的接口,而不是上述那样简单的java接口。扩展名为aidl而不是java。可用上面的ICountService改动而成ICountSerivde.aidl,eclipse会自动生成相关的java文件。

package com.easymorse;interface ICountService {    int getCount();}


编写服务(Service)类,稍有差别,主要在binder是通过远程获得的,需要通过桩(Stub)来获取。桩对象是远程对象的本地代理。

package com.easymorse;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;public class CountService extends Service {    private boolean threadDisable;    private int count;    private ICountService.Stub serviceBinder = new ICountService.Stub() {        @Override        public int getCount() throws RemoteException {            return count;        }    };    @Override    public IBinder onBind(Intent intent) {        return serviceBinder;    }    @Override    public void onCreate() {        super.onCreate();        new Thread(new Runnable() {            @Override            public void run() {                while (!threadDisable) {                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                    }                    count++;                    Log.v("CountService", "Count is " + count);                }            }        }).start();    }    @Override    public void onDestroy() {        super.onDestroy();        this.threadDisable = true;        Log.v("CountService", "on destroy");    }}


配置文件AndroidManifest.xml和上面的类似,没有区别。

在Activity中使用服务的差别不大,只需要对ServiceConnection中的调用远程服务的方法时,要捕获异常。

private ServiceConnection serviceConnection = new ServiceConnection() {    @Override    public void onServiceConnected(ComponentName name, IBinder service) {        countService = (ICountService) service;        try {            Log.v("CountService", "on serivce connected, count is "                    + countService.getCount());        } catch (RemoteException e) {            throw new RuntimeException(e);        }    }    @Override    public void onServiceDisconnected(ComponentName name) {        countService = null;    }};

这样就可以在同一个应用程序中使用远程服务的方式和自己定义的服务交互了。

如果是另外的应用程序使用远程服务,需要做的是复制上面的aidl文件和相应的包构到应用程序中,其他调用等都一样。




0 0
原创粉丝点击