android IPC_service

来源:互联网 发布:cf卡数据恢复软件 mac 编辑:程序博客网 时间:2024/06/01 15:05


                                                                                             android IPC_service




 Android中进程间的通信提供了四种方式,分别是四大组件,其中Activity可以通过Intent跨进程调用其他应用程序的ActivityContentProvider可以跨进程访问其他应用程序中的数据(以Cursor对象形式返回),当然,也可以对其他应用程序的数据进行增、删、改操作;Broadcast可以向android系统中所有应用程序发送广播,而需要跨进程通讯的应用程序可以监听这些广播;ServiceContentProvider类似,也可以访问其他应用程序中的数据,但不同的是,Content Provider返回的是Cursor对象,Service返回的是IBinder对象,这种可以跨进程通讯的服务叫AIDL服务。




Android Service分为两种:
  本地服务(Local Service): 同一个apk内被调用
  远程服务(Remote Service):被另一个apk调用
远程服务需要借助AIDL
(Android InterfaceDefinition Language)或者Messenger来完成,其实Messenger也是用AIDL实现的,只不过是google对其进行了封装,使用比AIDL相对简单一些。

  实现一下AIDL使其在两个应用程序(两个进程)中进行进程间通信(interprocess communication,IPC),新建两个android应用程序,我们在src目录下新建一个com.aidls包,com.aidl包下新建一个后缀为.aidl的文件,文件中添加一段代码:

package com.aidls;
interface holdService {
 void play();
 void stop();
}

   这个感觉和接口interface的使用差不多,只不过interface定义在.java文件中,但是aidl中不能加public等修饰符,保存后编译器会在gen目录下生成一个holdService.java文件,这时候这个aidl文件就建成功了

然后我们在com.services中建一个后台播放音乐的service

publicclass PlayerServiceextends Service {

 

   publicstaticfinal StringTAG ="PlayerService";

 

   privateMediaPlayer mplayer;

 

   @Override

   publicIBinder onBind(Intent intent) {

      Log.i(TAG,"serviceonbind");

      if(mplayer==null){

          mplayer =new MediaPlayer();

          try {

             FileDescriptor fd =getResources().openRawResourceFd(R.raw.lost).getFileDescriptor(); //获取音乐数据源

             mplayer.setDataSource(fd); //设置数据源

             mplayer.setLooping(true); //设为循环播放

          }catch (IOException e) {

             //TODO Auto-generated catch block

             e.printStackTrace();

          }

          Log.i(TAG,"playercreated");

      }

      returnmBinder;

   }

 

   //实现aidl文件中定义的接口

   privateIBinder mBinder =newholdService.Stub() {

 

      @Override

      publicvoid stop()throwsRemoteException {

          try {

             if (mplayer.isPlaying()) {

                 mplayer.stop();

             }

          }catch (Exception e) {

             //TODO: handle exception

             e.printStackTrace();

          }

      }

 

      @Override

      publicvoid play()throwsRemoteException {

          try {

             if (mplayer.isPlaying()) {

                 return;

             }

             mplayer.prepare();

             mplayer.start();

          }catch (Exception e) {

             //TODO: handle exception

             e.printStackTrace();

          }

      }

   };

   @Override

   publicboolean onUnbind(Intent intent){

      if(mplayer !=null) {

          mplayer.release();

      }

      Log.i(TAG,"serviceonUnbind");

      returnsuper.onUnbind(intent);

   }

}

  这里的播放服务就不用多说,主要看service,继承service后必须要实现onBind()方法,这个方法返回的是一个IBinder,进程间的通信离不开Binder,所以这里我们new holdService.Stud(),他返回的刚好是一个IBinder对象,我们可以看一下holdService.Stud()方法的源码,他也是exendsandroid.os.Binder,实例化后会必须实现play()和stop()方法,我们发现两个方法刚好是上面在com.aidls->holdservice.aidl中定义的两个方法,我们分别在play(),和stop()中实现音乐的播放和停止,然后在清单文件中注册这个服务 ,必须在过滤intent中定义action

 <serviceandroid:name=".PlayerService" android:process=":remote">
           <intent-filter >
               <action android:name="com.example.playerserver.PlayerService"/>
           </intent-filter>
         </service>

到此地一个应用程序就结束了

新建第二应用程序,这时候必须把com.aidls和下面的aidl原封不动的一起复制过来,当然,自己在敲一边aidl文件保存一下,也是一样的,然后在com.activity中做一个activity

publicclass sextends Activityimplements OnClickListener{

   privateholdService holdservice=null;

   privateButtonplay;

   privateButtonstop;

   publicvoid onCreate(Bundle savedInstanceState){

      super.onCreate(savedInstanceState);

      setContentView(R.layout.main);

      Intent service =new Intent("com.example.playerserver.PlayerService ");

      bindService(service, mConnection,BIND_AUTO_CREATE);

      play=findViewById(R.id.play);

      stop=findViewById(R.id.stop);

   }

   privateServiceConnection mConnection =newServiceConnection(){

 

      @Override

      publicvoidonServiceConnected(ComponentName name, IBinder service) {

          //TODO Auto-generated method stub

          holdservice = holdService.Stub.asInterface(service);

      }

 

      @Override

      publicvoidonServiceDisconnected(ComponentName name) {

          //TODO Auto-generated method stub

          holdservice =null;

      }

 

   };

   @Override

   publicvoid onClick(View v) {

      //TODO Auto-generated method stub

      switch (v.getId()) {

      caseR.id.play:

          holdservice.play();

          break;

      caseR.id.stop:

          holdservice.stop();

          break;

      default:

          break;

      }

   }

   @Override

   protectedvoid onDestroy() {

      //TODO Auto-generated method stub

      super.onDestroy();

      unbindService(mConnection);

   }

 

}

先绑定服务,这里绑定的时候要实现ServiceConnectionServiceConnection下要实现两个方法,在onServiceConnected绑定服务,他有两个参数,其中service就是上一个应用程序的serviceonBind返回的IBinder,这里通过holdService.Stub

.asInterface方法获取Service建立本地代理,这时候我们在第二个应用程序中就可以控制第一个应用程序应用的播放和停止

      这里我们可以看出在第二个应用程序可以调用地一个应用程序service中的play(),stop(),这两个函数是void类型,那么我们也可以是intchar的类型来传递数据了,但是我们需要注意的是:

AIDL服务只支持有限的数据类型,如果用AIDL服务传递一些复杂的数据就需要做更一步处理,  AIDL 服务支持的数据类型如下:
1. Java
的原生类型
2. String
CharSequence
3. List
Map ,ListMap对象的元素必须是AIDL支持的数据类型;  以上三种类型都不需要导入(import)
4. AIDL
自动生成的接口  需要导入(import)
5.
实现android.os.Parcelable接口的类.  需要导入(import) 

那么我们要自定义Bean——Person类传递过去,Person是一个序列化的类,这里使用Parcelable接口来序列化,ParcelableAndroid提供的一个比Serializable效率更高的序列化类。

我们在地一个应用程序的aidl文件中添加

package com.aidls;

import com.entity.Book;
interface holdService {
 void play();
 void stop();

Book getBook();
}

注意这里要导入Book

我们去生成一个Book实现Parcelable接口

publicclass Bookimplements Parcelable{

   

   privateString bookName;

   privateint bookPrice;

   

   publicBook(){

      

   }

   publicBook(Parcel parcel){

      bookName = parcel.readString();

      bookPrice = parcel.readInt();

   }

   publicString getBookName() {

      returnbookName;

   }

   publicvoid setBookName(StringbookName) {

      this.bookName= bookName;

   }

   publicint getBookPrice() {

      returnbookPrice;

   }

   publicvoid setBookPrice(int bookPrice) {

      this.bookPrice= bookPrice;

   }

   @Override

   publicint describeContents() {

      //TODO Auto-generated method stub

      return0;

   }

 

   @Override

   publicvoid writeToParcel(Parcel dest,int flags) {

      //TODO Auto-generated method stub

      dest.writeString(bookName);

      dest.writeInt(bookPrice);

   }

   

   publicstaticfinal Parcelable.Creator<Book>CREATOR =newCreator<Book>(){

 

      @Override

      publicBook createFromParcel(Parcel source) {

          //TODO Auto-generated method stub

          returnnewBook(source);

      }

 

      @Override

      publicBook[] newArray(int size) {

          //TODO Auto-generated method stub

          returnnewBook[size];

      }

      

   };

}

因为我们在aidl文件中加了getBook()方法,这时候在service private IBinder mBinder =new holdService.Stub() {}

中我们就必须实现getBook方法,这里我们直接赋值

//实现aidl文件中定义的接口

   privateIBinder mBinder =newholdService.Stub() {

 

      @Override

      publicvoid stop()throws RemoteException {

          try {

             if (mplayer.isPlaying()) {

                 mplayer.stop();

             }

          }catch (Exception e) {

             //TODO: handle exception

             e.printStackTrace();

          }

      }

@Override

      publicBook getBook()throws RemoteException{

          Book mBook =new Book();

          mBook.setBookName("Android应用开发");

          mBook.setBookPrice(50);

          return mBook;

      }

 

      @Override

      publicvoid play()throws RemoteException {

          try {

             if (mplayer.isPlaying()) {

                 return;

             }

             mplayer.prepare();

             mplayer.start();

          }catch (Exception e) {

             //TODO: handle exception

             e.printStackTrace();

          }

      }

   };

在第二个程序用(当然Bookaidl同样要复制到第二个应用程序中)

@Override

      publicvoidonServiceConnected(ComponentName name, IBinder service) {

          //TODO Auto-generated method stub

          holdservice = holdService.Stub.asInterface(service);

Stringbookname=holdservice.getBook().getBookName();

      }

 

以此就可以得到book对象

 


0 0