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

在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 ( IBinder iBinder ) ,它返回接口类型的实例,对于远程服务调用,远程服务返回给客户端的对象为代理对象,客户端在 onServiceConnected ( ComponentName name, IBinder service) 方法引用该对象时不能直接强转成接口类型的实例,而应该使用 asInterface ( IBinder iBinder ) 进行类型转换。
编写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 配置代码如下:
<service android: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();
		}
    	
    }
}









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值