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

Android四大组件之Service(笔记)续

2014-02-18 10:29 549 查看
在Android中,每个应用程序都有自己的进程,当需要在不同的进程之间进行通信,该如何来实现呢?进程间的通信即IPC通信,这个是android最核心的内容,熟悉了ipc通信android就熟悉了一大半。

在java中是不支持跨进程的内存共享,因此要传递对象就必须把对象解析成系统能够理解的数据编码,以便达到跨进程通信的目的。

在这里就采用AIDL(Android Interface Definition Language 接口定义语言 )方式来实现

AIDL是一种接口定义语言,用于约束两个进程通讯规则,提供给编译器生成代码,实现android设备上两个进程间IPC的通信,AIDL的进程之间的通讯信息首先被转换成AIDL协议信息,然后发送给对方,对方接收到AIDL协议信息后又转换成相应的对象。由于进程间通信信息需要双向转换,所以android采用代理类的形式在背后执行双向转换,代理类由android编译器生成,对开发人员来说是透明的,不需要知道如何实现。

实现跨进程通信一般需要四个步骤:

假如A应用需要跨进程调用B应用的一个方法,B应用以service的方式为A应用提供服务

1.在B应用中编写.aidl文件

package com.android.aidl;

interface QueryService {
String queryStudent(int no);

}

当.aidl文件创建完成之后,刷新eclipse会自动在gen目录下生成QueryService.java接口文件

—类里面包括aidl定义的方法,还包括一些其它辅助方法。值得关注的是接口文件中生成一个Stub的抽象asInterface(IBinderiBinder),它返回接口类型的实例,对于远程服务调用,远程服务返回给客户端的对象为代理对象,客户端在onServiceConnected(ComponentName
name, IBinder service)方法引用该对象时不能直接强转成接口类型的实例,而应该使用asInterface(IBinderiBinder)进行类型转换。
编写aidl文件时应该注意:

— 1.接口名和aidl文件名必须相同。
— 2.接口和方法前不用加访问权限修饰符public,private,protected等,也不能用final,static。
— 3.Aidl默认支持的类型包话java基本类型(int、long、boolean等)和(String、List、Map、CharSequence),使用这些类型时不需要import声明。对于List和Map中的元素类型必须是Aidl支持的类型。如果使用自定义类型作为参数或返回值,自定义类型必须实现Parcelable接口。
— 4.自定义类型和AIDL生成的其它接口类型在aidl描述文件中,应该显式import,即便在该类和定义的包在同一个包中。
— 5.在aidl文件中所有非Java基本类型参数必须加上in、out、inout标记,以指明参数是输入参数、输出参数还是输入输出参数。
— 6.Java原始类型默认的标记为in,不能为其它标记。
2.在B应用中实现aidl生成的接口,并非直接实现接口,而且通过继承Stub来实现(Stub实现了aidl的接口)

代码如下:

private final class StudentBinder extends QueryService.Stub{
public String queryStudent(int no) throws RemoteException {
Log.i("StudentService", no+"");
return query(no);
}
}

3.在B应用中创建一个Service,在服务的onBind(Intent intent) 方法中返回实现了aidl接口的对象,在这里是StudentBinder对象
代码如下:

package com.android.remoteservice;

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

import com.android.aidl.QueryService;

public class StudentService extends Service {
private String[] names = {"成龙", "李连杰", "洪金宝"};
private IBinder binder = new StudentBinder();

private String query(int no){
if(no > 0 && no <4){
return names[no - 1];
}
return null;
}

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

private final class StudentBinder extends QueryService.Stub{
public String queryStudent(int no) throws RemoteException {
Log.i("StudentService", no+"");
return query(no);
}
}

}

—在其他其他应用可以通过隐式意图访问服务,意图的动作可以自定义,AndroidManifest.xml配置代码如下:
—<serviceandroid:name=".QueryService" >
—  <intent-filter>
—  <action
android:name=“com.android.process.aidl.QueryService" />
—  </intent-filter>
—</service>

4.把B应用中aidl文件所在package连同aidl文件一起拷贝到客户端A应用,eclipse会自动在A应用的gen目录中为aidl文件同步生成QueryService.java接口文件,接下来就可以在A应用中实现与B应用通信

A应用布局文件:

<?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/number"
/>

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

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button"
android:onClick="query"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/resultView"
/>
</LinearLayout>

strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, MainActivity!</string>
<string name="app_name">访问远程服务</string>
<string name="number">学号</string>
<string name="button">查询</string>
</resources>



MainActivity.java
package com.android.service.client;

import com.android.aidl.QueryService;
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.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {
private EditText numberText;
private TextView resultView;
private StudentConnection conn = new StudentConnection();
private QueryService queryService;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

numberText = (EditText) this.findViewById(R.id.number);
resultView = (TextView) this.findViewById(R.id.resultView);
Intent service = new Intent("com.android.process.aidl.QueryService");
bindService(service, conn, BIND_AUTO_CREATE);
}

private final class StudentConnection implements ServiceConnection{
public void onServiceConnected(ComponentName name, IBinder service) {
queryService = QueryService.Stub.asInterface(service);
}
public void onServiceDisconnected(ComponentName name) {
queryService = null;
}

}

public void query(View v){
String number = numberText.getText().toString();
try {
String name = queryService.queryStudent(Integer.valueOf(number));
resultView.setText(name);
} catch (Exception e) {
e.printStackTrace();
}

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: