【远程Service】AIDL进程间通信实例

本文介绍如何使用AIDL实现Android应用程序间的远程Service通信。包括创建远程Service的步骤和客户端如何绑定及调用Service的方法。

对于Service的定义及使用场合等请详见官方定义:http://developer.android.com/guide/components/services.html

Service有两种类型:

1. 本地服务(Local Service):用于应用程序内部

2. 远程服务(Remote Service):用于android系统内部的应用程序之间

本文讲解远程Service服务的使用。

 远程Service通常用于Android内部应用程序之间通信,既然是两个应用程序,所以可以将其理解为一个是服务器提供Service服务,一个是客户端使用Service服务。通常远程Service使用AIDL(Android Interface Define Language)接口定义语言进行进程间通信。

下面编写服务器Service应用的实例代码(三步即可完成):

1)创建一个应用之后,新建一个接口文件,后缀*.adil结尾。如图:

       

文件中的使用Java语言编写一个接口:

package com.example.aidl;
interface CountInterface {
 int getCount();
 //可以继续定义更多方法提供给客户端使用
}

该文件定义好之后,系统会自动生成其对应的*.java 文件。如图:



2)创建一个服务器端提供的Service服务类,继承Service。实例代码如下:

package com.example.a_bindservice_a;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import com.example.aidl.CountInterface;
import com.example.aidl.CountInterface.Stub;

public class MyBindService extends Service {
	Thread t;
	int i = 0;
	/**
	 * 创建一个CountInterface.Stub类型的binder,binder将返回给客户端作为客户端的代理,从而可以调用当前服务的方<span style="white-space:pre">	</span> *法。
	 * Stub是CountInterface接口的一个静态内部类
	 * */
	CountInterface.Stub binder = new Stub() {
		@Override
		public int getCount() throws RemoteException {
			return i;//在这里实现CountInterface计数的方法
		}
	};

	@Override
	public IBinder onBind(Intent intent) {
		// 如果使用远程Service 必须返回一个binder对象。
		return binder;
	}

	@Override
	public void onCreate() {
		super.onCreate();
		System.out.println("bind Oncreate");
		// 通过启动线程在Service中实现一个计数的功能。
		t = new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("Thread run");
				while (true) {
					i++;
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		});
		t.start();
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		System.out.println("onStartCommand");
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public void onDestroy() {
		System.out.println("onDestroy");
		t.interrupt();// 当远程调用unbindService()方法时,当前Service一起被销毁,同时终止子线程。
		super.onDestroy();
	}

	@Override
	public boolean onUnbind(Intent intent) {
		System.out.println("onUnbind");
		return super.onUnbind(intent);
	}
}
需要注意的是:远程Service的onBind()方法中必须返回一个binder对象。binder对象使用CountInterface的内部类Stub 创建。

3)在AndroidManifest.xml文件中注册当前Service并添加Action(不然其他应用找不到这个Service)

注册代码如下:

 <service android:name="MyBindService">
            <intent-filter >
                <action android:name="com.example.a_bindservice_a.MyBindService"/>
            </intent-filter>
        </service>




下面创建客户端使用Service服务的实例代码(两步即可完成):
1)首先将服务器Service创建的接口文件连同报名一同拷贝到客户端应用中。如图:

2)编写客户端使用远程Service的实例代码:

package com.example.a_bindservice_b;

import com.example.aidl.CountInterface;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

/**
 * 远程服务在客户端:首先将服务器端的AIDL包及文件拷贝到当前项目中。
 * 在客户端创建AIDL接口类型的引用对象cInterface,用来作为服务器再本地的代理。
 * 在本地创建ServiceConnection类型的对象sConnection,
 * 并且重写onServiceConnected和onServiceDisconnected两个方法。
 * onServiceConnected方法会在bindService时被回调。
 * 在onServiceConnected方法里面对AIDL接口对象赋值,cInterface =
 * CountInterface.Stub.asInterface(binder);。 在unbindService时清空cInterface对象的引用。
 * bindService(intent, sConnection, BIND_AUTO_CREATE);
 * unbindService(sConnection); Intent对象通过new Intent("Action")方法创建。
 * sConnection对象就是ServiceConnection的对象。
 * 
 * */
public class MainActivity extends Activity implements OnClickListener {
	Intent intent; //通过Intent找到服务器端的Service 
	CountInterface cInterface; // 创建一个接口对象,实现本地代理?
	private Button bind;//绑定Service的按钮
	private Button unbind;//解绑的按钮
	private Button getNum;//调用远程Service中接口方法的按钮

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		intent = new Intent("com.example.a_bindservice_a.MyBindService");
		bind = (Button) findViewById(R.id.btnbind);
		unbind = (Button) findViewById(R.id.btnUnbind);
		getNum = (Button) findViewById(R.id.btngetCount);
		getNum.setOnClickListener(this);
		bind.setOnClickListener(this);
		unbind.setOnClickListener(this);
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		if (cInterface != null) {
			unbindService(sConnection);
			cInterface = null;
		}
	};

	ServiceConnection sConnection = new ServiceConnection() {

		/**
		 * onServiceDisconnected() 在连接正常关闭的情况下是不会被调用的, 该方法只在Service
		 * 被破坏了或者被杀死的时候调用. 例如, 系统资源不足, 要关闭一些Services, 刚好连接绑定的 Service 是<span style="white-space:pre">		</span> *被关闭者之一,
		 * 这个时候onServiceDisconnected() 就会被调用。
		 * */
		@Override
		public void onServiceDisconnected(ComponentName name) {
			System.out.println("onServiceDisconnected");
			cInterface = null;
		}
		
		/**
		 * 在调用bindService方法时会回调此方法。
		 * 远程Service在onBind()方法必须返回一个binder对象,否则当前方法不会被调用。
		 * */
		@Override
		public void onServiceConnected(ComponentName name, IBinder binder) {
			System.out.println("onServiceConnected");
			// 通过asInterface()方法获得接口CountInterface对象的引用实例。binder就是服务器Service返回的<span style="white-space:pre">			</span>//binder对象。
			cInterface = CountInterface.Stub.asInterface(binder);
		}
	};

	// 为按钮添加监听
	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.btnbind:
			bindService(intent, sConnection, BIND_AUTO_CREATE);
			break;
		case R.id.btnUnbind:
			if (cInterface != null) {
				unbindService(sConnection);
				cInterface = null;
			}
			break;
		case R.id.btngetCount:
			try {
				if (cInterface != null) {
					int i =cInterface.getCount();// 通过cInterface对象调用应用A的getCount()方法
					System.out.println("--------------->" + i);
				}
			} catch (RemoteException e) {
				System.out.println("RemoteException");
				e.printStackTrace();
			}
			break;

		default:
			break;
		}
	}
}

需要注意的是:1.客户端使用服务器Service的接口方法时通过CountInterface接口的变量cInterface来实现的。

  2.客户端在bindService时需要使用ServiceConnection类型的变量,创建sConnection变量时使用匿名     内部类,并实现其中的两个方法。


到此运行程序。然后就可以在客户端程序B中使用服务器A中定义的接口方法了。

真正纯自己写的第一个Blog,参考了许多其他大神的博客。如有错误,欢迎探讨~~好开森~大笑大笑




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值