您的位置:首页 > 移动开发 > Android开发

深入浅出 Android核心组件Service(4)

2013-09-09 21:04 190 查看
本文51CTO专栏作者傻蛋将向我们介绍深入浅出 Android核心组件Service第四部分的系列文章。

AD: 2013云计算架构师峰会超低价抢票中

在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://down.51cto.com/data/326382
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: