深入淺出 Android Service(4)

       在android平臺中,一個進程通常不能訪問其他進程中的內存區域的。但是,我們可以使用IDL語言來把對象僞裝成操作系統能理解的簡單形式,以便僞裝成對象跨越邊界訪問。
       如果想在應用程序中調用其他進程中的Service,則需要用到AIDL,AIDL(android接口描述語言)是一種IDL語言,它可以生成一段代碼,可以使在一個android設備上運行的兩個進程使用內部通信進程進行交互。如果你需要在一個進程中(例如:在一個Activity中)訪問另一個進程中(例如:一個Service)某個對象的方法,你就可以使用AIDL來生成這樣的代碼來僞裝傳遞各種參數。
 

使用AIDL的方法如下:
1.首先要編寫一個IMusicService.aidl的服務接口,ADT會根據這個接口文件幫我們自動生成一個 Stub類,這個類繼承了Binder類,同時繼承了IMusicService這個接口,還可以看到其中包含了一個Proxy代理類,以實現遠程代理,訪問不同的進程。(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類如下,我們暫不做詳細講解,後面的課程中我們會嘗試自己來寫一個類似的類,完成不同進程的訪問。

/*
 * 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)方法(這一點和以前不同)。相應的代碼如下:
/**
 * 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退出之前要解除綁定,不然會報錯
				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註冊的時候我們需要指定它是在一個不同的進程中運行的,本例子指定的是remote進程。注意 process參數。
       <!-- 註冊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>

本節的源代碼可在此下載:http://download.csdn.net/detail/internetman/3967828  
有問題可以發表評論或者微博私信我。

發佈了30 篇原創文章 · 獲贊 34 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章