AIDL服务

本文详细介绍了 Android 进程间通信 (IPC) 的核心机制 AIDL 的使用方法及注意事项,通过两个实例展示了主进程如何调用 Service 进程的服务以及 Service 进程如何回调主进程的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android的IPC有四种,详见:http://blog.youkuaiyun.com/habbyge/article/details/17796345

AIDL学习文档:http://developer.android.com/guide/components/aidl.html#PassingObjects

重点:AIDL应该注意的事项:

1. AIDL文件的inteface中的成员函数的参数

(1)参数是基本数据类型,则默认是in方向的,可以没有限制的直接使用(包括String);

(2)参数是Java支持的引用类型,必须指明in/out/inout方向,也可以直接使用;

(3)参数是Android中的引用类型,则必须是可以序列化的(Parcelable),且必须指明in/out/inout方向,也就是说,如果Android里的类对象时Parcelable的,才可以传入,不是Parcelable的,不能传入,需用其他方法解决(AIDL接口方法);

(4)对于自定义的类TestData.java,需要另外增加一个AIDL文件TestData.aidl,首先该自定义类TestData.java必须实现Parcelable,然后再写一个声明该类的声明文件(TestData.aidl),该声明文件(TestData.aidl)用于告诉引用该类的aidl文件,此类遵守Parcelable协议,可以在AIDL中使用(其实就是在TestData.aidl文件中声明如下:parcelable TestData,即可):

1) TestData.java

public class TestData implements Parcelable {

    private String name = "";

    public TestData() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.name);
    }

    protected TestData(Parcel in) {
        this.name = in.readString();
    }

    public static final Parcelable.Creator<TestData> CREATOR = new Parcelable.Creator<TestData>() {
        public TestData createFromParcel(Parcel source) {
            return new TestData(source);
        }

        public TestData[] newArray(int size) {
            return new TestData[size];
        }
    };
}
2) TestData.aidl

package com.tencent.qqpim.apps.photo.sdk.aidl;

parcelable TestData;
3) test.aidl

package com.tencent.qqpim.apps.photo.sdk.aidl;

import com.tencent.qqpim.apps.photo.sdk.aidl.TestData;

interface test {
    void fn1(int x, String y);
    List<String> fn2(in TestData td);
}

必须为AIDL文件中的接口成员函数的引用参数类型指明读写方向,这样可以做到优化,因为传输类对象到AIDL的时候,AIDL需要对类对象进行Parcelable(序列化),指明in/out/inout可以做到只写或只读或读写对象,省时。所有的基本数据类型都是默认in的,可以不用显示指定,但是所有非基本类型(对象引用)都必须是Parcelable、且必须显示指定in/out/inout。

【AIDL文件是主进程和Service进程的接口】

【AIDL文件中的接口函数如果是在Service进程中实现,则是在Service进程中执行,并且是为了让主进程调用】

【AIDL文件中的接口函数如果是在主进程中实现,则是在主进程中执行,并且是为了让Service进程调用】

2. Service进程回调主进程中的代码(以更新Activity)

AIDL文件可以有多个,AIDL文件可以在Service进程中运行,也可以在主进程中运行,主要是看改AIDL接口是在哪里实现的,如果在Service进程中实现,则是在Service中运行的;如果是在主进程中实现的,则是在主进程中运行;AIDL全称是Andorid接口定义语言,也就是说只是在AIDL文件中定义进程间都可以使用的接口,具体是在哪个进程中运行,主要是看在哪个进程中实现这些接口;在主进程中实现的AIDL接口,主要是让Service进程来调用(回调)主进程中接口的,在Service进程中是实现的接口,主要是让主进程调用(回调)Service进程中接口的。

AIDL文件接口如果是主进程中实现,则表示该接口是在主进程中运行的,用来让Service进程来调用的;如果是在Service进程中实现,则表示是在Service线程中执行,用来让主进程来调用。

例子如下:


(1)MainActivity.class

package com.habby.test;

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.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
import android.widget.TextView;

import com.example.com.habby.test.R;
import com.habby.test.aidl.IRemoteCallback;
import com.habby.test.aidl.IRemoteService;

/**
 * 主进程
 * 让Service进程回调主进程中的修改界面的回调函数
 */
public class MainActivity extends Activity {
	private final String TAG = "MainActivity";
	
	private TextView mNameTv;	// 被更改的View
	
	private IRemoteService mRemoteService;	// Service进程中执行的远程接口
	private static final int sCHANGE_VIEW_SUCCESS = 1;
	
	/**
	 * 主进程中执行的接口,更新主进程中的界面。
	 */
	public IRemoteCallback.Stub mCallback = new IRemoteCallback.Stub() {
		@Override
		public void changeView() throws RemoteException {
			Log.d(TAG, "activity pid = " + Process.myPid());
			Message.obtain(mHandler, sCHANGE_VIEW_SUCCESS).sendToTarget();
		}
	};
	
	/**
	 * 当主进程的Activity连接上Service进程中的Service后,回调该对象
	 */
	private ServiceConnection mConnection = new ServiceConnection() {
		@Override
		public void onServiceDisconnected(ComponentName name) {	// 连接断开
			Log.d(TAG, "onServiceDisconnected()");
		}
		
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {	// 连接成功
			
			// 获得Service进程中的远程接口
			mRemoteService = IRemoteService.Stub.asInterface(service);
			if (mRemoteService != null) {
				try {
					/**
					 * 主进程获取Service进程中的数据、执行Service进程中的方法;
					 */
					mRemoteService.getPid();
					mRemoteService.basicTypes(1, 2L, true, 2.0f, 2.0D, "I love Merry");
					
					/**
					 * 主进程把主进程中的更改View的接口(IRemoteCallback.aidl)传入Service进程,
					 * 让Service进程可以更改主进程中的数据(View)。
					 */
					mRemoteService.setCallback(mCallback);
				} catch (android.os.RemoteException e) {
					e.printStackTrace();
				}
			}
		}
	};
	
	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case sCHANGE_VIEW_SUCCESS:
				mNameTv.setText(R.string.name);
				break;

			default:
				break;
			}
	    }
	};
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate()");
        setContentView(R.layout.activity_main);
        mNameTv = (TextView) findViewById(R.id.name);
        
        Log.d(TAG, "pid = " + Process.myPid());
        
        // 绑定服务
        Intent intent = new Intent(this, AIDLService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    public void onDestroy() {
    	Log.d(TAG, "onDestroy()");
    	unbindService(mConnection);	// 取消服务
    	super.onDestroy();
    }
}
(2)AIDLService.class

package com.habby.test;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Process;
import android.util.Log;

import com.habby.test.aidl.IRemoteCallback;
import com.habby.test.aidl.IRemoteService;
// Service进程
public class AIDLService extends Service {
	private final String TAG = "AIDLService";
	
	private IRemoteCallback mViewCallback;
	
	public class RemoteService extends IRemoteService.Stub {
    	@Override
    	public int getPid() {
    		int pid = Process.myPid();
    		Log.d(TAG, 	"AIDLService pid = " + pid);
    		return pid;
    	}
    	
    	@Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, 
        		float aFloat, double aDouble, String aString) {
    		
        	Log.d(TAG, "/" + anInt + "/" + aLong + "/" + aBoolean + "/" + 
        			aFloat + "/" + aDouble + "/" + aString + "/");
        }
    	
    	@Override
    	public void setCallback(IRemoteCallback callback) {
    		Log.d(TAG, "setCallback()");
    		try {
    			callback.changeView();
    		} catch (android.os.RemoteException e) {
    			e.printStackTrace();
    		}
    		
    		mViewCallback = callback;
    	}
    }
	
	@Override
	public void onCreate() {
		super.onCreate();
		Log.d(TAG, "onCreate()");
	}
	
	@Override
	public IBinder onBind(Intent intent) {
		Log.d(TAG, "onBind()");
		return new RemoteService();
	}
	
	@Override
	public void onDestroy() {
		Log.d(TAG, "onDestroy()");
		super.onDestroy();
    }
}
(3)IRemoteService.aidl,Service进程中的调用,在Service进程中实现

package com.habby.test.aidl;

import com.habby.test.aidl.IRemoteCallback;

interface IRemoteService {
    int getPid();
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, 
            double aDouble, String aString);
    void setCallback(IRemoteCallback callback);
}
(4)IRemoteCallback.aidl,主进程中的调用,在主进程中实现

package com.habby.test.aidl;

interface IRemoteCallback {
    void changeView();
}

(5)AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.com.habby.test"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        
        <activity
            android:name="com.habby.test.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    
        <service
            android:name="com.habby.test.AIDLService"
            android:process="com.habby.remote" />
    </application>

</manifest>

3. 主进程调用Service进程的代码(Service进程提供的服务)

例子如下:


(1)RemoteCallExampleActivity.java

package com.habby.remote;

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.os.RemoteException;

import com.habby.remote.aidl.IRemoteCall;

public class RemoteCallExampleActivity extends Activity {
	private IRemoteCall iRemoteCall;	// aidl服务接口
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		// 启动Service
		Intent remotecall = new Intent(this, RemoteCallService.class);
		bindService(remotecall, new ServiceConnection() {
			@Override
			public void onServiceDisconnected(ComponentName name) {
			}
			
			@Override
			public void onServiceConnected(ComponentName name, IBinder service) {
				iRemoteCall = IRemoteCall.Stub.asInterface(service);
				try {
					String args = "I love Merry !";
					iRemoteCall.setListener(args);
				} catch(RemoteException e) {
					e.printStackTrace();
				}
			}
		}, Context.BIND_AUTO_CREATE);
	}
	
	@Override
	protected void onResume() {
		super.onResume();
	}
	
	@Override
	public void onDestroy() {
		super.onDestroy();
	}
}
(2)RemoteCallService.java
package com.habby.remote;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

import com.habby.remote.aidl.IRemoteCall;

public class RemoteCallService extends Service {
	private final String TAG = "Habby";
	
	/**
	 * Service实现的aidl策略
	 */
	public class RemoteCall extends IRemoteCall.Stub {
		@Override
		public void setListener(String listener) {
			Log.i(TAG, "Service RemoteCall() setListener()" + listener);
		}
	}

	@Override
	public IBinder onBind(Intent arg0) {
		return new RemoteCall();
	}

	@Override
	public void onCreate() {
		super.onCreate();
		Log.d(TAG,"Service onCreate()");
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.d(TAG,"Service onStartCommand()");
		return super.onStartCommand(intent, flags, startId);
	}
	
	@Override
	public void onDestroy() {
		Log.d(TAG,"Service onDestroy()");
		super.onDestroy();
	}
}
(3)IRemoteCall.aidl,在包com.habby.remote.aidl中:

package com.habby.remote.aidl;

interface IRemoteCall {
	void setListener(String listener);
}
(4)AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.com.habby.remote"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        
        <activity
            android:name="com.habby.remote.RemoteCallExampleActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
        <service
            android:name="com.habby.remote.RemoteCallService"
            android:process="com.habby.subprocess" > <!-- 把Service作为一个的进程 -->
            <intent-filter>
                <action android:name="com.habby.remote.RemoteCallService.action" />
            </intent-filter>
        </service>
    </application>

</manifest>

注意:在做类似项目的过程中,遇到一个问题值得注意:

Service的onBind(),在没有调用unbindService()的时候,无论调用多少次bindService()该onBind()都只会被调用一次(但是ServiceConnection会每次都被调用),且是在第一次bindSerivce()的时候被调用,也就说只绑定一次(前提是没有调用unbindService())。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值