我的Android进阶之旅------>Android Service学习之AIDL, Parcelable和远程服务实例

简介: 通过上一篇(Android Service学习之AIDL, Parcelable和远程服务)的介绍,这一篇写一个小实例来实践一下 step1:建立两个应用,分别为RemoteService和RemoteServiceClient                                         先编写服务器端的内容 step2:开始编写一个StudentQuery.aidl文件      AIDL(Android Interface Definition Language),用来定义远程接口。

通过上一篇(Android Service学习之AIDL, Parcelable和远程服务)的介绍,这一篇写一个小实例来实践一下

step1:建立两个应用,分别为RemoteService和RemoteServiceClient

                                       


先编写服务器端的内容

step2:开始编写一个StudentQuery.aidl文件

     AIDL(Android Interface Definition Language),用来定义远程接口。AIDL接口定义语言的语法十分简单,这种接口定义语言并不是一种真正的编程语言,它只是定义两个进程之间的通信接口,因此语法非常简单。AIDL的语法与Java接口很相似,但是也存在以下几点差异:

  • AIDL定义接口的源代码必须以 .aidl 结尾
  • AIDL接口中用到的数据类型,除了基本类型、String、List、Map、CharSequence之外,其他类型全部都需要导入包,即使它们在同一个包中也需要导包。

package cn.roco.aidl;

interface StudentQuery {
	String queryStudent(int number);
}

系统会根据此aidl文件生成一个类StudentQuery.java接口

StudentQuery接口中包含一个Stub内部类,该内部类实现了IBinder和StudentQuery接口,这个Stub类将会作为远程Service的回调类,它实现了IBinder接口,因此可以作为Service的onBind()方法的返回值。

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: C:\\Documents and Settings\\student\\android\\RemoteService\\src\\cn\\roco\\aidl\\StudentQuery.aidl
 */
package cn.roco.aidl;
public interface StudentQuery extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements cn.roco.aidl.StudentQuery
{
private static final java.lang.String DESCRIPTOR = "cn.roco.aidl.StudentQuery";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an cn.roco.aidl.StudentQuery interface,
 * generating a proxy if needed.
 */
public static cn.roco.aidl.StudentQuery 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 cn.roco.aidl.StudentQuery))) {
return ((cn.roco.aidl.StudentQuery)iin);
}
return new cn.roco.aidl.StudentQuery.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_queryStudent:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _result = this.queryStudent(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements cn.roco.aidl.StudentQuery
{
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 java.lang.String queryStudent(int number) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(number);
mRemote.transact(Stub.TRANSACTION_queryStudent, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_queryStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public java.lang.String queryStudent(int number) throws android.os.RemoteException;
}


step3:编写服务类StudentQueryService.java

该Service实现类的onBind()方法所返回的IBinder对象应该是的StudentQuert.Stub的子类的实例。

package cn.roco.remote.service;

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

public class StudentQueryService extends Service {
	private String[] names = new String[100];
	private IBinder binder = new StudentQueryBinder();

	@Override
	public IBinder onBind(Intent intent) {
		return binder;
	}

	/**
	 * 通过学号查询学生姓名
	 * 
	 * @param no
	 * @return
	 * @throws Exception
	 */
	public String query(int no) {
		if (no > 0 && no < names.length + 1) {
			return names[no - 1];
		} else {
			return null;
		}
	}

	/**
	 * 创建服务的时候做初始化操作
	 */
	@Override
	public void onCreate() {
		for (int i = 0; i < names.length; i++) {
			names[i] = "RemoteQuery_" + (i + 1);
		}
		super.onCreate();
	}

	/**
	 * 关闭服务的时候,释放资源
	 */
	@Override
	public void onDestroy() {
		for (int i = 0; i < names.length; i++) {
			names[i] = null;
		}
	}
	/**
	 * cn.roco.aidl.StudentQuery.Stub 由系统根据StudentQuery.aidl自动生成
	 */
	private final class StudentQueryBinder extends
			cn.roco.aidl.StudentQuery.Stub {
		@Override
		public String queryStudent(int number) {
			return query(number);
		}
	}
}

step4:在AndroidManifest.xml文件中配置此服务

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="cn.roco.remote.service"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="8" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
		<service android:name=".StudentQueryService" >
			<intent-filter>
				<action android:name="cn.roco.remote.service.student.query"/>
			</intent-filter>
		</service>
    </application>
</manifest>


编写完服务器端的代码后,编写客户端的代码

step5:在客户端也要讲StudentQuery.aidl文件导入到客户端中


step6:设计客户端的UI界面,main.xml文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical" android:layout_width="fill_parent"
	android:layout_height="fill_parent">
	<TextView android:layout_width="fill_parent"
		android:layout_height="wrap_content" android:text="@string/student_no" />

	<EditText android:layout_width="fill_parent"
		android:layout_height="wrap_content" android:id="@+id/student_no" />

	<Button android:layout_width="fill_parent"
		android:layout_height="wrap_content" android:text="@string/button_query"
		android:id="@+id/button_query" />
		
	<TextView android:layout_width="fill_parent"
		android:layout_height="wrap_content" android:id="@+id/resultView" />

</LinearLayout>

string.xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, MainActivity!</string>
    <string name="app_name">远程学生查询系统</string>
    <string name="student_no">学号</string>
    <string name="button_query">查询</string>
</resources>


step7:客户端访问AIDLService

客户端绑定远程Service与绑定本地Service区别不大,同样之需要两步。

  • 1.创建ServiceConnection对象。
  • 2.以ServiceConnection对象作为参数,调用Context的bindService()方法绑定远程Service即可。

     与绑定本地Service不同的是,绑定远程Service的ServiceConnection并不能直接获取Service的onBind()方法所返回的对象,它只能返回onBind()方法所返回的对象的代理因此在ServiceConnection的onServiceConnected方法中需要通过如下代码进行处理:

// 调用该方法将远程的IBinder转换
			studentQuery = cn.roco.aidl.StudentQuery.Stub.asInterface(service);


MainActivity.java文件

package cn.roco.remoteservice.client;

import cn.roco.aidl.StudentQuery;
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.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
	private EditText student_no;
	private TextView resultView;
	private ServiceConnection conn = new StudentServiceConnection();
	private StudentQuery studentQuery;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		
		resultView = (TextView) findViewById(R.id.resultView);
		student_no = (EditText) findViewById(R.id.student_no);
		Button button_query = (Button) findViewById(R.id.button_query);
		button_query.setOnClickListener(new ButtonClickListener());
		/**
		 *  该Intent是RemoteService项目中的Service
		 *  "cn.roco.remote.service.student.query"为
		 *  <service android:name=".StudentQueryService" >
				<intent-filter>
					<action android:name="cn.roco.remote.service.student.query"/>
				</intent-filter>
			</service>
		 */
		Intent service = new Intent("cn.roco.remote.service.student.query");
		// 绑定服务
		bindService(service, conn, BIND_AUTO_CREATE);
	}

	@Override
	protected void onDestroy() {
		unbindService(conn); // 解绑服务
		super.onDestroy();
	}

	/**
	 * 该类中的两个方法都是回调函数
	 */
	private class StudentServiceConnection implements ServiceConnection {
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			// 调用该方法将远程的IBinder转换
			studentQuery = cn.roco.aidl.StudentQuery.Stub.asInterface(service);   //重点理解
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			studentQuery=null;
		}

	}

	private final class ButtonClickListener implements View.OnClickListener {
		@Override
		public void onClick(View v) {
			String studentNo = student_no.getText().toString();
			String studentName;
			try {
				studentName = studentQuery.queryStudent(Integer
						.parseInt(studentNo));
				if (studentName!=null) {
					resultView.setText(studentName);
				}else{
					Toast.makeText(getApplicationContext(), "您输入的学号不在规定的学号内,请输入1到100的数字", 1).show();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}
}



step8:将服务和客户端安装完后,查看运行的效果

             




==================================================================================================

  作者:欧阳鹏  欢迎转载,与人分享是进步的源泉!

  转载请保留原文地址http://blog.csdn.net/ouyang_peng

==================================================================================================


相关文章
|
3月前
|
Java Maven 开发工具
第一个安卓项目 | 中国象棋demo学习
本文是作者关于其第一个安卓项目——中国象棋demo的学习记录,展示了demo的运行结果、爬坑记录以及参考资料,包括解决Android Studio和maven相关问题的方法。
第一个安卓项目 | 中国象棋demo学习
|
6月前
|
调度 Android开发
43. 【Android教程】服务:Service
43. 【Android教程】服务:Service
59 2
|
2月前
|
Web App开发 编解码 视频直播
视频直播技术干货(十二):从入门到放弃,快速学习Android端直播技术
本文详细介绍了Android端直播技术的全貌,涵盖了从实时音视频采集、编码、传输到解码与播放的各个环节。文章还探讨了直播中音视频同步、编解码器选择、传输协议以及直播延迟优化等关键问题。希望本文能为你提供有关Andriod端直播技术的深入理解和实践指导。
52 0
|
7月前
|
监控 Unix 应用服务中间件
Android-音视频学习系列-(八)基于-Nginx-搭建(rtmp、http)直播服务器
Android-音视频学习系列-(八)基于-Nginx-搭建(rtmp、http)直播服务器
|
3月前
|
Android开发
Android学习 —— 测试init.rc中的条件触发的处理顺序
Android学习 —— 测试init.rc中的条件触发的处理顺序
|
4月前
|
搜索推荐 Android开发
学习AOSP安卓系统源代码,需要什么样的电脑?不同配置的电脑,其编译时间有多大差距?
本文分享了不同价位电脑配置对于编译AOSP安卓系统源代码的影响,提供了从6000元到更高价位的电脑配置实例,并比较了它们的编译时间,以供学习AOSP源代码时电脑配置选择的参考。
266 0
学习AOSP安卓系统源代码,需要什么样的电脑?不同配置的电脑,其编译时间有多大差距?
|
4月前
|
编解码 网络协议 Android开发
Android平台GB28181设备接入模块实现后台service按需回传摄像头数据到国标平台侧
我们在做Android平台GB28181设备对接模块的时候,遇到这样的技术需求,开发者希望能以后台服务的形式运行程序,国标平台侧没有视频回传请求的时候,仅保持信令链接,有发起视频回传请求或语音广播时,打开摄像头,并实时回传音视频数据或接收处理国标平台侧发过来的语音广播数据。
|
5月前
|
API Android开发
Android 监听Notification 被清除实例代码
Android 监听Notification 被清除实例代码
|
6月前
|
安全 Java Android开发
使用Unidbg进行安卓逆向实例讲解
使用Unidbg进行安卓逆向实例讲解
142 2
|
6月前
|
存储 算法 Java
Android 进阶——代码插桩必知必会&ASM7字节码操作
Android 进阶——代码插桩必知必会&ASM7字节码操作
253 0