AIDL全称Android Interface Definition Language,即Android接口定义语言,通过它可以在进程间通讯,今天的例子演示的是在Activity与Service间通讯。 程序结构: 包com.example.aidl中有五个文件 AIDLService.java: Service MainActivity.java: 第一个Activity,在这里启动Service,并与之通讯 People.java: JavaBean,两字段,name,age,一方法say SecondActivity.java: 第二个Activity,与在MainActivity中启动的AIDLService通讯 PeopleAIDL.aidl AIDL定义文件,其实就是一个Interface,但扩展名不是java,添加这个文件后,在gen目录下会自动生成PeopleAIDL.java. 本例使用了AndroidAnnotations框架,没接触过的童鞋可能会看不太懂,但其实这个框架也蛮简单的,参考前文AndroidAnnotations框架@Ebean,@RootContext,@Background,@UiThread,@AfterInject,@AfterTextChange标签的使用方法,一看就明白。 布局:main_activity.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="@string/hello_world"
tools:context=".MainActivity" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="绑服务" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="22dp"
android:layout_toRightOf="@+id/button1"
android:text="setName" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/textView1"
android:text="setAge" />
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/button1"
android:layout_marginTop="16dp"
android:text="say" />
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/button4"
android:layout_alignLeft="@+id/button2"
android:text="SecondActivity" />
</RelativeLayout>
second_activity.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bind Service" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Say" />
</LinearLayout>
接下来是Java代码: People.java:
package com.example.aidl;
import android.content.Context;
import android.widget.Toast;
import com.googlecode.androidannotations.annotations.EBean;
import com.googlecode.androidannotations.annotations.RootContext;
@EBean
public class People {
@RootContext
Context context;
String name;
int age;
public void say()
{
Toast.makeText(context, "I'm "+name+" I "+age+" years old.", Toast.LENGTH_LONG).show();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
用了androidannotations的@RootContext,上面的context会自动取到,不会为空。 PeopleAIDL.aidl:
package com.example.aidl;
interface PeopleAIDL {
void setAge(int age);
void setName(String name);
void say();
}
网上的文章都称这个文件要放在包目录下,如果是多个包,到底是AndroidManifest.xml中声明的package还是其他包,没测试。保存后,ADT会在gen下的同名包下生成PeopleAIDL.java. AIDLService.java:
package com.example.aidl;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import com.googlecode.androidannotations.annotations.Bean;
import com.googlecode.androidannotations.annotations.EService;
@EService
public class AIDLService extends Service {
@Bean
People people=new People();
PeopleAIDL.Stub stub=new PeopleAIDL.Stub() {
//下面的方法都是供远程调用的
public void setName(String name) throws RemoteException {
// TODO Auto-generated method stub
people.setName(name);
}
public void setAge(int age) throws RemoteException {
// TODO Auto-generated method stub
people.setAge(age);
}
public void say() throws RemoteException {
// TODO Auto-generated method stub
people.say();
}
};
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
//onBind方法要返回PeopleAIDL.Stub
return stub;
}
}
MainActivity.java:
package com.example.aidl;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.widget.Button;
import com.googlecode.androidannotations.annotations.Click;
import com.googlecode.androidannotations.annotations.EActivity;
import com.googlecode.androidannotations.annotations.ViewById;
@EActivity(R.layout.activity_main)
public class MainActivity extends Activity {
PeopleAIDL peopleAIDL;
@ViewById
Button button1,button2,button3,button4,button5;
ServiceConnection conn = new ServiceConnection(){
public void onServiceConnected(ComponentName className, IBinder service) {
//服务绑定成功,绑定动作好像是异步的
peopleAIDL=PeopleAIDL.Stub.asInterface(service);
}
public void onServiceDisconnected(ComponentName className) {
}
};
//下面是几个按钮的点击事件
@Click
void button1()
{
//绑定启动服务
bindService(new Intent(this, AIDLService_.class), conn, Context.BIND_AUTO_CREATE);
startService(new Intent(this, AIDLService_.class));
}
@Click
void button2()
{
try {
peopleAIDL.setName("zhangshan");
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Click
void button3()
{
try {
peopleAIDL.setAge(23);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Click
void button4()
{
try {
peopleAIDL.say();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Click
void button5()
{
//SecondActivity后加_是因为用了androidannotations
Intent intent=new Intent(this,SecondActivity_.class);
startActivity(intent);
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
//退出时必须unbindService
unbindService(conn);
//如果Service仍需要在后台运行,不需要下面的这句
stopService(new Intent(this, AIDLService_.class));
}
}
SecondActivity.java:
package com.example.aidl;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.widget.Button;
import com.googlecode.androidannotations.annotations.Click;
import com.googlecode.androidannotations.annotations.EActivity;
import com.googlecode.androidannotations.annotations.ViewById;
@EActivity(R.layout.second_activity)
public class SecondActivity extends Activity {
PeopleAIDL peopleAIDL;
@ViewById
Button button1,button2;
private ServiceConnection conn = new ServiceConnection(){
public void onServiceConnected(ComponentName className, IBinder service) {
peopleAIDL=PeopleAIDL.Stub.asInterface(service);
}
public void onServiceDisconnected(ComponentName className) {
}
};
@Click
void button1()
{
bindService(new Intent(this, AIDLService_.class), conn, Context.BIND_AUTO_CREATE);
//如果调用的是另一个应用的Service,使用new Intent("Service的Action");
}
@Click
void button2()
{
try {
peopleAIDL.say();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
若调用的是另一个应用的Service,需要那个应用声明Service时加上Action,如:
<service android:name=".service.GCService" >
<intent-filter>
<action android:name="com.pocketdigi.service.GCservice" />
</intent-filter>
</service>
在bindService的Intent里传入这个Action. 需要注意的是,两个应用的AIDL文件必须完全一致,包括在包名。