求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
深入浅出 Android核心组件Service(二)
 

发布于2012-2-20

 

在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

在远程的Service调用中,Activity和Service到底是怎么沟通的?对于Service的远程调用,一般会在不同的工程中也就是两个不同的进程,那么进程的沟通机制是什么?傻蛋画了一个图来说明。

Android进程在进行远程通讯时会:

1.产生一个主线程。

2. 产生Looper对象

3.产生一个消息队列。

4.产生一个虚拟机对象来实现Java和C++之间的沟通。

5.通过C/C++层的IPC来实现远程通讯。

所谓的 进程间通讯:Android通过IBinder接口来实现进程间的通讯,MyActivity会调用IBinder的transact()函数通过IPC来调用远程的onTransact()函数。注意: 在默认情况下,如果Service和Activity、 BroadcastReceiver在同一个工程里面,那么这些组件都会在同一个进程中执行,并且由主线程负责执行,当然也可以通过配置让其在不同的组件里面执行,比如上一节我们就让Service在Remote进程中运行。


相关文章

深度解析:清理烂代码
如何编写出拥抱变化的代码
重构-使代码更简洁优美
团队项目开发"编码规范"系列文章
相关文档

重构-改善既有代码的设计
软件重构v2
代码整洁之道
高质量编程规范
相关课程

基于HTML5客户端、Web端的应用开发
HTML 5+CSS 开发
嵌入式C高质量编程
C++高级编程

 
分享到
 
 
     


android人机界面指南
Android手机开发(一)
Android手机开发(二)
Android手机开发(三)
Android手机开发(四)
iPhone消息推送机制实现探讨
手机软件测试用例设计实践
手机客户端UI测试分析
手机软件自动化测试研究报告
更多...   


Android高级移动应用程序
Android应用开发
Android系统开发
手机软件测试
嵌入式软件测试
Android软、硬、云整合


领先IT公司 android开发平台最佳实践
北京 Android开发技术进阶
某新能源领域企业 Android开发技术
某航天公司 Android、IOS应用软件开发
阿尔卡特 Linux内核驱动
艾默生 嵌入式软件架构设计
西门子 嵌入式架构设计
更多...