深入淺出 Android核心組件Service(4)
在Android平臺(tái)中,一個(gè)進(jìn)程通常不能訪問其他進(jìn)程中的內(nèi)存區(qū)域的。但是,我們可以使用IDL語(yǔ)言來把對(duì)象偽裝成操作系統(tǒng)能理解的簡(jiǎn)單形式,以便偽裝成對(duì)象跨越邊界訪問。
如果想在應(yīng)用程序中調(diào)用其他進(jìn)程中的Service,則需要用到AIDL,AIDL(android接口描述語(yǔ)言)是一種IDL語(yǔ)言,它可以生成一段代碼,可以使在一個(gè)android設(shè)備上運(yùn)行的兩個(gè)進(jìn)程使用內(nèi)部通信進(jìn)程進(jìn)行交互。如果你需要在一個(gè)進(jìn)程中(例如:在一個(gè)Activity中)訪問另一個(gè)進(jìn)程中(例如:一個(gè)Service)某個(gè)對(duì)象的方法,你就可以使用AIDL來生成這樣的代碼來偽裝傳遞各種參數(shù)。
使用AIDL的方法如下:
1.首先要編寫一個(gè) IMusicService.aidl的服務(wù)接口,ADT會(huì)根據(jù)這個(gè)接口文件幫我們自動(dòng)生成一個(gè) Stub類,這個(gè)類繼承了Binder類,同時(shí)繼承了IMusicService這個(gè)接口,還可以看到其中包含了一個(gè)Proxy代理類,以實(shí)現(xiàn)遠(yuǎn)程代理,訪問不同的進(jìn)程。(aidl和Stub類如下所示)。
- /**
- * IMusicService.aidl
- * com.androidtest.service.mediaplayer
- *
- * Function: TODO
- *
- * ver date author
- * ──────────────────────────────────
- * 2011-5-19 Leon
- *
- * Copyright (c) 2011, TNT All Rights Reserved.
- */
- package com.zuiniuwang.service;
- /**
- * ClassName:IMusicService
- * Function: TODO ADD FUNCTION
- * Reason: TODO ADD REASON
- *
- * @author Leon
- * @version
- * @since Ver 1.1
- * @Date 2011-5-19
- */
- interface IMusicService{
- void play();
- void pause();
- void stop();
- }
2. 生成的Stub類如下,我們暫不做詳細(xì)講解,后面的課程中我們會(huì)嘗試自己來寫一個(gè)類似的類,完成不同進(jìn)程的訪問。
- /*
- * This file is auto-generated. DO NOT MODIFY.
- * Original file: E:\\myworkspace\\musicservice4\\src\\com\\zuiniuwang\\service\\IMusicService.aidl
- */
- package com.zuiniuwang.service;
- /**
- * ClassName:IMusicService
- * Function: TODO ADD FUNCTION
- * Reason: TODO ADD REASON
- *
- * @author Leon
- * @version
- * @since Ver 1.1
- * @Date 2011-5-19
- */
- public interface IMusicService extends android.os.IInterface
- {
- /** Local-side IPC implementation stub class. */
- public static abstract class Stub extends android.os.Binder implements com.zuiniuwang.service.IMusicService
- {
- private static final java.lang.String DESCRIPTOR = "com.zuiniuwang.service.IMusicService";
- /** Construct the stub at attach it to the interface. */
- public Stub()
- {
- this.attachInterface(this, DESCRIPTOR);
- }
- /**
- * Cast an IBinder object into an com.zuiniuwang.service.IMusicService interface,
- * generating a proxy if needed.
- */
- public static com.zuiniuwang.service.IMusicService asInterface(android.os.IBinder obj)
- {
- if ((obj==null)) {
- return null;
- }
- android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
- if (((iin!=null)&&(iin instanceof com.zuiniuwang.service.IMusicService))) {
- return ((com.zuiniuwang.service.IMusicService)iin);
- }
- return new com.zuiniuwang.service.IMusicService.Stub.Proxy(obj);
- }
- public android.os.IBinder asBinder()
- {
- return this;
- }
- @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_play:
- {
- data.enforceInterface(DESCRIPTOR);
- this.play();
- reply.writeNoException();
- return true;
- }
- case TRANSACTION_pause:
- {
- data.enforceInterface(DESCRIPTOR);
- this.pause();
- reply.writeNoException();
- return true;
- }
- case TRANSACTION_stop:
- {
- data.enforceInterface(DESCRIPTOR);
- this.stop();
- reply.writeNoException();
- return true;
- }
- }
- return super.onTransact(code, data, reply, flags);
- }
- private static class Proxy implements com.zuiniuwang.service.IMusicService
- {
- private android.os.IBinder mRemote;
- Proxy(android.os.IBinder remote)
- {
- mRemote = remote;
- }
- public android.os.IBinder asBinder()
- {
- return mRemote;
- }
- public java.lang.String getInterfaceDescriptor()
- {
- return DESCRIPTOR;
- }
- public void play() throws android.os.RemoteException
- {
- android.os.Parcel _data = android.os.Parcel.obtain();
- android.os.Parcel _reply = android.os.Parcel.obtain();
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- mRemote.transact(Stub.TRANSACTION_play, _data, _reply, 0);
- _reply.readException();
- }
- finally {
- _reply.recycle();
- _data.recycle();
- }
- }
- public void pause() throws android.os.RemoteException
- {
- android.os.Parcel _data = android.os.Parcel.obtain();
- android.os.Parcel _reply = android.os.Parcel.obtain();
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- mRemote.transact(Stub.TRANSACTION_pause, _data, _reply, 0);
- _reply.readException();
- }
- finally {
- _reply.recycle();
- _data.recycle();
- }
- }
- public void stop() throws android.os.RemoteException
- {
- android.os.Parcel _data = android.os.Parcel.obtain();
- android.os.Parcel _reply = android.os.Parcel.obtain();
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- mRemote.transact(Stub.TRANSACTION_stop, _data, _reply, 0);
- _reply.readException();
- }
- finally {
- _reply.recycle();
- _data.recycle();
- }
- }
- }
- static final int TRANSACTION_play = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
- static final int TRANSACTION_pause = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
- static final int TRANSACTION_stop = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
- }
- public void play() throws android.os.RemoteException;
- public void pause() throws android.os.RemoteException;
- public void stop() throws android.os.RemoteException;
- }
3. 在Activity中得到Binder的方式,是通過Stub類的IMusicService.Stub.asInterface(binder)方法(這一點(diǎn)和以前不同)。相應(yīng)的代碼如下:
- /**
- * RemoteMusicPlayerActivity.java
- * com.androidtest.activity.musicplayer
- *
- * Function: TODO
- *
- * ver date author
- * ──────────────────────────────────
- * 2011-5-20 Leon
- *
- * Copyright (c) 2011, TNT All Rights Reserved.
- */
- package com.zuiniuwang.playeractivity;
- 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.util.Log;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import com.zuiniuwang.R;
- import com.zuiniuwang.service.IMusicService;
- /**
- * ClassName:RemoteMusicPlayerActivity Function: TODO ADD FUNCTION Reason: TODO
- * ADD REASON
- *
- * @author Leon
- * @version
- * @since Ver 1.1
- * @Date 2011-5-20
- */
- public class RemoteMusicPlayerActivity extends Activity implements
- OnClickListener {
- private static final String TAG = RemoteMusicPlayerActivity.class
- .getSimpleName();
- private Button playButton, pauseButton, stopButton, closeActivityButton,
- exitActivityButton;
- private IMusicService musicServiceInterface;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onCreate(savedInstanceState);
- this.setContentView(R.layout.music_player_layout);
- findViews();
- bindViews();
- connection();
- }
- private void findViews() {
- playButton = (Button) this.findViewById(R.id.play);
- pauseButton = (Button) this.findViewById(R.id.pause);
- stopButton = (Button) this.findViewById(R.id.stop);
- closeActivityButton = (Button) this.findViewById(R.id.close);
- exitActivityButton = (Button) this.findViewById(R.id.exit);
- }
- private void bindViews() {
- playButton.setOnClickListener(this);
- pauseButton.setOnClickListener(this);
- stopButton.setOnClickListener(this);
- closeActivityButton.setOnClickListener(this);
- exitActivityButton.setOnClickListener(this);
- }
- private void connection() {
- Intent intent = new Intent(
- "com.androidtest.service.mediaplayer.RemoteMusicService");
- this.startService(intent);
- this.bindService(intent, myServiceConnection, Context.BIND_AUTO_CREATE);
- }
- private ServiceConnection myServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder binder) {
- musicServiceInterface = IMusicService.Stub.asInterface(binder);
- Log.d(TAG, " onServiceConnected");
- }
- @Override
- public void onServiceDisconnected(ComponentName name) {
- musicServiceInterface = null;
- Log.d(TAG, " onServiceDisconnected");
- }
- };
- @Override
- public void onClick(View view) {
- // TODO Auto-generated method stub
- try {
- switch (view.getId()) {
- case R.id.play:
- Log.d(TAG, "play.......");
- musicServiceInterface.play();
- break;
- case R.id.pause:
- Log.d(TAG, "pause.......");
- musicServiceInterface.pause();
- break;
- case R.id.stop:
- Log.d(TAG, "stop.......");
- musicServiceInterface.stop();
- break;
- case R.id.close:
- //Activity退出之前要解除綁定,不然會(huì)報(bào)錯(cuò)
- this.unbindService(myServiceConnection);
- Log.d(TAG, "close.......");
- this.finish();
- break;
- case R.id.exit:
- Log.d(TAG, "exit.......");
- this.unbindService(myServiceConnection);
- this.stopService(new Intent("com.androidtest.service.mediaplayer.RemoteMusicService"));
- this.finish();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
4. 最后在此Service注冊(cè)的時(shí)候我們需要指定它是在一個(gè)不同的進(jìn)程中運(yùn)行的,本例子指定的是remote進(jìn)程。注意 process參數(shù)。
- <!-- 注冊(cè)Service -->
- <service android:enabled="true"
- android:name=".service.RemoteMusicService" android:process=":remote">
- <intent-filter>
- <action android:name="com.androidtest.service.mediaplayer.RemoteMusicService" />
- </intent-filter>
- </service>
本節(jié)的源代碼可在此下載:http://down.51cto.com/data/326382