zoukankan      html  css  js  c++  java
  • android进程间通信:使用AIDL

    android 的binder其实是基于 openbinder实现的,openbinder的地址:http://www.angryredplanet.com/~hackbod/openbinder/docs/html/

    http://blog.csdn.net/saintswordsman/article/details/5130947

    欢迎阅读本文,你能关注本文,你知道你需要进程间通信、需要AIDL(以及Binder),那么可以默认你对这些概念已经有了一些了解,你(大致) 知道它们是什么,它们有什么用,所以为了节约大家的眼力和时间,在此我不复制粘贴网上泛滥的博客或者翻译冗长的android文档。

          关于AIDL的介绍在文档:docs/guide/developing/tools/aidl.html

          关于IBinder的介绍在文档:docs/reference/android/os/IBinder.html

          以及Binder:docs/reference/android/os/Binder.html

          在后文中,我将以我自己的理解向你介绍相关的概念。以我目前粗浅的经验,应用程序使用AIDL的地方,几乎都和Service有关,所以你也需要知道一些关于Service的知识。日后得闲我也会继续写一些关于Service的贴。

          本文将以一个例子来和你分享使用AIDL的基础技能,这个例子里有:

    1、一个类mAIDLActivity,继承Activity。里面有三个按钮,text分别为StartService,StopService,CallbackTest。

    2、一个类mAIDLService,继承Service。为了充分展示ADIL的功能,它做以下工作:当用户点击CallbackTest按钮时,从mAIDLActivity调用mAIDLService中的Stub 对象的一个方法invokCallBack(),而这个方法又会调用mAIDLActivity中Stub 对象的一个方法performAction(),这个方法在屏幕上显示一个toast。没什么意义,只是展示一下AIDL如何使用。

    3、两个AIDL文件:forService.aidl和forActivity.aidl。对应名字,在Service和Activity中分别有对象需要用到它们定义的接口。

    4、相关XML文件,略过。关于manifest中Service的语法,见docs/guide/topics/manifest /service-element.html。你也可以简单地在<application></application>中加入

         <service android:name=".mAIDLService" android:process=":remote"> </service>

    开发环境为Eclipse。

    拣重要的先说,来看看aidl文件的内容:

    文件:forActivity.aidl

    package com.styleflying.AIDL;  
    interface forActivity {  
        void performAction();  
    }  

    文件:forService.aidl

    package com.styleflying.AIDL;  
    import com.styleflying.AIDL.forActivity;  
    interface forService {  
        void registerTestCall(forActivity cb);  
        void invokCallBack();  
    }  

    这两个文件和Java文件放置的地方一样,看包名。

    在Eclipse中它们将被自动编译为forActivity.java和forService.java,它们存放在gen目录下。为了方便手头无法演练的读者,代码不贴,不用细看。

    再看mAIDLActivity.java:

    package com.styleflying.AIDL;  
    import android.app.Activity;  
    import android.content.ComponentName;  
    import android.content.Context;  
    import android.content.Intent;  
    import android.content.ServiceConnection;  
    import android.os.Bundle;  
    import android.os.IBinder;  
    import android.os.RemoteException;  
    import android.util.Log;  
    import android.view.View;  
    import android.view.View.OnClickListener;  
    import android.widget.Button;  
    import android.widget.Toast;  
    public class mAIDLActivity extends Activity {  
        private static final String TAG = "AIDLActivity";  
        private Button btnOk;  
        private Button btnCancel;  
        private Button btnCallBack;  
    
        private void Log(String str) {  
            Log.d(TAG, "------ " + str + "------");  
        }  
    
        private forActivity mCallback = new forActivity.Stub() {  
            public void performAction() throws RemoteException  
            {  
                Toast.makeText(mAIDLActivity.this, "this toast is called from service", 1).show();  
            }  
        };  
    
        forService mService;  
        private ServiceConnection mConnection = new ServiceConnection() {  
            public void onServiceConnected(ComponentName className,  
                    IBinder service) {  
                mService = forService.Stub.asInterface(service);  
                try {  
                    mService.registerTestCall(mCallback);}  
                catch (RemoteException e) {  
    
                }  
            }  
            public void onServiceDisconnected(ComponentName className) {  
                Log("disconnect service");  
                mService = null;  
            }  
        };  
        @Override  
            public void onCreate(Bundle icicle) {  
                super.onCreate(icicle);  
                setContentView(R.layout.main);  
                btnOk = (Button)findViewById(R.id.btn_ok);  
                btnCancel = (Button)findViewById(R.id.btn_cancel);  
                btnCallBack = (Button)findViewById(R.id.btn_callback);  
                btnOk.setOnClickListener(new OnClickListener() {  
                        public void onClick(View v) {  
                        Bundle args = new Bundle();  
                        Intent intent = new Intent(mAIDLActivity.this, mAIDLService.class);  
                        intent.putExtras(args);  
                        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);  
                        startService(intent);  
                        }  
                        });  
                btnCancel.setOnClickListener(new OnClickListener() {  
                        public void onClick(View v) {  
                        unbindService(mConnection);  
                        //stopService(intent);  
                        }  
                        });  
                btnCallBack.setOnClickListener(new OnClickListener() {  
    
                        @Override  
                        public void onClick(View v)  
                        {  
                        try  
                        {  
                        mService.invokCallBack();  
                        } catch (RemoteException e)  
                        {  
                        // TODO Auto-generated catch block  
                        e.printStackTrace();  
                        }  
                        }  
                        });  
            }  
    }

    很短,相信大家很容易看明白。注意mConnection,它的onServiceConnected()中有一句mService = forService.Stub.asInterface(service);给mService赋值了,这个mService是一个 forService,而service是onServiceConnected()传进来的参数,onServiceConnected()会在连接 Service的时候被系统调用,这个service参数的值来自哪里呢?

    看mAIDLService.java:

    package com.styleflying.AIDL;  
    import android.app.Service;  
    import android.content.Intent;  
    import android.os.IBinder;  
    import android.os.RemoteCallbackList;  
    import android.os.RemoteException;  
    import android.util.Log;  
    public class mAIDLService extends Service {  
        private static final String TAG = "AIDLService";    
        private forActivity callback;  
        private void Log(String str) {  
            Log.d(TAG, "------ " + str + "------");  
        }  
        @Override  
            public void onCreate() {  
                Log("service create");  
            }  
        @Override  
            public void onStart(Intent intent, int startId) {  
                Log("service start id=" + startId);  
            }  
    
        @Override  
            public IBinder onBind(Intent t) {  
                Log("service on bind");  
                return mBinder;  
            }  
        @Override  
            public void onDestroy() {  
                Log("service on destroy");  
                super.onDestroy();  
            }  
        @Override  
            public boolean onUnbind(Intent intent) {  
                Log("service on unbind");  
                return super.onUnbind(intent);  
            }  
        public void onRebind(Intent intent) {  
            Log("service on rebind");  
            super.onRebind(intent);  
        }  
        private final forService.Stub mBinder = new forService.Stub() {  
            @Override  
                public void invokCallBack() throws RemoteException  
                {  
                    callback.performAction();  
    
                }  
            @Override  
                public void registerTestCall(forActivity cb) throws RemoteException  
                {  
                    callback = cb;  
    
                }  
    
        };  
    }

    注意onBind(),它的返回类型为IBinder,返回了一个mBinder,看看mBinder的定义:

        private final forService.Stub mBinder = new forService.Stub() {

            @Override
            public void invokCallBack() throws RemoteException
            {
                callback.performAction();
             }

            @Override
            public void registerTestCall(forActivity cb) throws RemoteException
            {
                callback = cb;

            }

           };

    它是实现了我们在AIDL中定义的方法,这个mBinder最终返回给了mAIDLActivity中的mService,于是在 mAIDLActivity中可以使用mBinder中的方法了。在mAIDLActivity中也有一个类似mBinder的对象,看看定义:   

            private forActivity mCallback = new forActivity.Stub()

        {
            public void performAction() throws RemoteException
            {
                Toast.makeText(mAIDLActivity.this, "this toast is called from service", 1).show();
            }
          };

    我们要在界面上显示一个toast,就是在这里实现的。这个对象,在mConnection的onServiceConnected()被调用时, 通过调用mService(也就是远程的mAIDLService中的mBinder)的registerTestCall(),传递给了 mAIDLService,于是在mAIDLService中可以调用performAction()了。

    很啰嗦,只为了能把这个细节说清楚。请大家认真看,我尽量避免错别字、混乱的大小写和逻辑不清的语法,相信你会看明白。是不是很简单?再啰嗦一下,做一个大致总结,我们使用AIDL是要做什么呢:

    让Acticity(或者说一个进程/一个类?)和Service(或者说远端进程/远端类/对象?)获取对方的一个Stub对象,这个对象在定义 时实现了我们在AIDL中定义的方法,于是这些远程对象中的方法可以在本地使用了。如果这种使用(通信)是单向的,比如只是Activity需要通知 Service做什么,那么只要Service中有一个Stub对象,并且传给Acticity就够了。

    至于如何获得远程的Stub,参看上面的代码,看mConnection、registerTestCall、onRebind,它们展示了一种方法。

    另外,有时候我们可能在一个类中有多个Stub对象,它们都要给远程交互的类的实例,这个时候可以考虑使用RemoteCallbackList<>(docs/reference/android/os/RemoteCallbackList.html)。

    =============================

    Service的生命周期 Service的生命周期方法比Activity少一些,只有onCreate, onStart, onDestroy 
    我们有两种方式启动一个Service,他们对Service生命周期的影响是不一样的。

    1 通过startService 
        Service会经历 onCreate -> onStart 
       stopService的时候直接onDestroy 

       如果是调用者(TestServiceHolder)自己直接退出而没有调用stopService的 
       话,Service会一直在后台运行。 
       下次TestServiceHolder再起来可以stopService。

      2 通过bindService    
        Service只会运行onCreate, 这个时候 TestServiceHolder 和TestService绑定在一起 

       TestServiceHolder 退出了,Srevice就会调用onUnbind->onDestroyed 
       所谓绑定在一起就共存亡了。 

    那有同学问了,要是这几个方法交织在一起的话,会出现什么情况呢? 
    一 个原则是Service的onCreate的方法只会被调用一次,就是你无论多少次的startService又 bindService,Service只被创建一次。如果先是bind了,那么start的时候就直接运行Service的onStart方法,如果先 是start,那么bind的时候就直接运行onBind方法。如果你先bind上了,就stop不掉了,对啊,就是stopService不好使了,只 能先UnbindService, 再StopService,所以是先start还是先bind行为是有区别的。 


    服 务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可 以启动Service,但是它们的使用场合有所不同。使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务 仍然运行。使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特 点。

    如 果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用 onStart()方法。如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服 务,但会导致多次调用onStart()方法。采用startService()方法启动的服务,只能调用Context.stopService()方 法结束服务,服务结束时会调用onDestroy()方法。

    如 果打算采用Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用 onBind()方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的onUnbind()方法,接着调用onDestroy() 方法。如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法并不会导致多次创建服务及绑定(也就是说 onCreate()和onBind()方法并不会被多次调用)。如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方 法,调用该方法也会导致系统调用服务的onUnbind()-->onDestroy()方法.

    你可以绑定一个已经通过startService()方法启动的服务。例如:一 个后台播放音乐服务可以通过startService(intend)对象来播放音乐。可能用户在播放过程中要执行一些操作比如获取歌曲的一些信息,此时 activity可以通过调用bindServices()方法与Service建立连接。这种情况下,unbindService() 及 stopServices()方法实际上不会停止服务,直到最后一次的绑定被关闭。

    ================================================================

    Android之进程间传递自定义类型参数

    【0】AIDL默认支持的类型包话java基本类型(int、long、boolean等)和(String、List、Map、CharSequence)(好像数组也可以,只要实现了Parcelable接口),如果要传递自定义的类型该如何实现呢?

    要传递自定义类型,首先要让自定义类型支持parcelable协议,实现步骤如下:

    1>自定义类型必须实现Parcelable接口,并且实现Parcelable接口的public void writeToParcel(Parcel dest, int flags)方法 。

    2>自定义类型中必须含有一个名称为CREATOR的静态成员,该成员对象要求实现Parcelable.Creator接口及其方法。

    3>创建一个aidl文件声明你的自定义类型。

    Parcelable接口的作用:实现了Parcelable接口的实例可以将自身的状态信息(状态信息通常指的是各成员变量的值)写入Parcel,也可以从Parcel中恢复其状态。 Parcel用来完成数据的序列化传递。 

    【1】进程间传递自定义类型的实现过程 

    1> 创建自定义类型,并实现Parcelable接口,使其支持parcelable协议。如:在com.hoo.domin创建Person.java:

    1. public class Person implements Parcelable  
    2.   private Integer id;  
    3.   private String name;  
    4.    
    5.   public Person(){}  
    6.   public Person(Integer id, String name) {  
    7.   this.id = id;  
    8.   this.name = name;  
    9.   }  
    10.   public Integer getId() {  
    11.   return id;  
    12.   }  
    13.   public void setId(Integer id) {  
    14.   this.id = id;  
    15.   }  
    16.   public String getName() {  
    17.   return name;  
    18.   }  
    19.   public void setName(String name) {  
    20.   this.name = name;  
    21.   }   
    22.   @Override  
    23.   public int describeContents() {  
    24.   return 0;  
    25.   }  
    26.   @Override  
    27.   public void writeToParcel(Parcel dest, int flags) {//把javanbean中的数据写到Parcel   
    28.   dest.writeInt(this.id);  
    29.   dest.writeString(this.name);  
    30.   }  
    31.   //添加一个静态成员,名为CREATOR,该对象实现了Parcelable.Creator接口   
    32.   public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>(){  
    33.   @Override  
    34.   public Person createFromParcel(Parcel source) {//从Parcel中读取数据,返回person对象   
    35.   return new Person(source.readInt(), source.readString());  
    36.   }  
    37.   @Override  
    38.   public Person[] newArray(int size) {  
    39.   return new Person[size];  
    40.   }  
    41.   };  
    42. }  

    2> 在自定义类型所在包下创建一个aidl文件对自定义类型进行声明,文件的名称与自定义类型同名。

    package com.hoo.domin

    parcelable Person; 

    3> 在接口aidl文件中使用自定义类型,需要使用import显式导入,本例在com.hoo.aidl包下创建IPersonService.aidl文件,内容如下:

    1. package com.hoo.aidl;  
    2. import cn.itcast.domain.Person;  
    3. interface IPersonService {  
    4.       void save(in Person person);  
    5. }   

    4> 在实现aidl文件生成的接口(本例是IPersonService),但并非直接实现接口,而是通过继承接口的Stub来实现(Stub抽象类内部实现了aidl接口),并且实现接口方法的代码。内容如下:

    1. public class ServiceBinder extends IPersonService.Stub {  
    2.        @Override  
    3.        public void save(Person person) throws RemoteException {  
    4.   Log.i("PersonService", person.getId()+"="+ person.getName());  
    5.        }   
    6. }  

    5> 创建一个Service(服务),在服务的onBind(Intent intent)方法中返回实现了aidl接口的对象(本例是ServiceBinder)。内容如下:

    1. public class PersonService extends Service {  
    2.   private ServiceBinder serviceBinder = new ServiceBinder();  
    3.   @Override  
    4.   public IBinder onBind(Intent intent) {  
    5.   return serviceBinder;  
    6.   }  
    7. public class ServiceBinder extends IPersonService.Stub {  
    8.        @Override  
    9.        public void save(Person person) throws RemoteException {  
    10.   Log.i("PersonService", person.getId()+"="+ person.getName());  
    11.        }  
    12. }  
    13. }  

    其他应用可以通过隐式意图访问服务,意图的动作可以自定义,AndroidManifest.xml配置代码如下:

    1. <service android:name=".PersonService" >  
    2.   <intent-filter>  
    3.   <action android:name="com.hoo.process.aidl.PersonService " />  
    4.   </intent-filter>  
    5. </service> 
  • 相关阅读:
    2013.4.15 Particle Swarm Optimization with Skyline Operator for Fast Cloudbased Web Service Composition
    Adaptive service composition in flexible processes
    2013.4.13 DomainSpecific Service Selection for Composite Services
    2013.4.14 Modeling and Algorithms for QoSAware Service Composition in VirtualizationBased Cloud Computing
    2013.5.29 Towards Networkaware Service Composition in the Cloud
    Efficient algorithms for Web services selection with endtoend QoS constraints
    SQL Server中常用的SQL语句
    接口限流自定义注解
    linux服务器生产环境搭建
    MVEL自定义函数重复掉用报错:duplicate function
  • 原文地址:https://www.cnblogs.com/welhzh/p/4683465.html
Copyright © 2011-2022 走看看