最近在学习Android开发,学到了使用AIDL进行Android的进程间通信,网上找了些视频资料看了下,都是基于eclipse的,而我使用的是AndroidStudio,那么在AndroidStudio中该如何实现呢?我参考了这哥们的文章,基本实现了两个app之间的通信,下面来看具体实现.
新建了三个module,分别是:aidlmodels(放序列化model的,项目类型为Android Library),aidlservice(远程service),app(调用者)
aidlmodels Module
先创建aidl文件,然后创建实体类.
右键选中项目-->New-->AIDL-->AIDL File,新建一个aidl文件,我的文件命名为person.这时AndroidStudio就为我们创建好了一个aidl文件夹,里面有我们刚创建的aidl文件
在person.aidl中定义好要创建的实体类.
person.aidl:
// person.aidl
package com.my.open.aidlmodels;
parcelable person;
里面的 parcelable person中的person就是我们要创建的实体类,用于序列化后再进程间传输.
在main-->java中创建person 实体类:
person.java:
package com.my.open.aidlmodels;
import android.os.Parcel;
import android.os.Parcelable;
public class person implements Parcelable {
private String name;
//0:男,1:女
private int sex;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
private String hobby;
protected person(Parcel in) {
this.name=in.readString();
this.sex=in.readInt();
this.age=in.readInt();
this.hobby=in.readString();
}
public person()
{
}
public static final Creator<person> CREATOR = new Creator<person>() {
@Override
public person createFromParcel(Parcel in) {
return new person(in);
}
@Override
public person[] newArray(int size) {
return new person[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.name);
dest.writeInt(this.sex);
dest.writeInt(this.age);
dest.writeString(this.hobby);
}
}
model类需实现的Parcelable接口
注意:person.java类的包名要和person.aidl的包名相同
最后工程目录结构:
这时,选中工程,按下Ctrl+F9,编译生成一下.
aidlservice Module
先添加对aidlmodels项目的引用,在aidlservice Module的build.gradle文件中添加对aidlmodels项目的引用:
然后同步一下.
远程服务具体要实现哪些功能,我们把这些功能定义在一个接口中,右键选中项目-->New-->AIDL-->AIDL File,新建一个aidl文件,我的文件命名为IPersonActive.aidl
// IPersonActive.aidl
package com.my.open.aidlservice;
import com.my.open.aidlmodels.person;
// Declare any non-default types here with import statements
interface IPersonActive {
person addPerson(String name,int sex,int age,String hobby);
person getPerson(String name);
boolean deletePerson(String name);
}
我定义了几个简单的方法,下一步我们在aidl文件夹下创建一个包,包名和aidlmodels项目中的person.aidl所在的包名相同,把person.aidl文件拷贝到此包下.现在选中项目,按下Ctrl+F9编译一下,应该就可以看到AndroidStudio为我们 生成的IPersonActive文件
接下来就是定义service了,文件如下
package com.my.open.aidlservice;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import com.my.open.aidlmodels.person;
import java.util.HashMap;
import java.util.Map;
public class myRemoteService extends Service {
private Map<String,person> personMap;
//IPersonActive接口的具体实现
private class myPersonBinder extends IPersonActive.Stub{
@Override
public person addPerson(String name, int sex, int age, String hobby) throws RemoteException {
if (personMap.keySet().contains(name))
{
return null;
}
person _person= new person();
_person.setName(name);
_person.setSex(sex);
_person.setAge(age);
_person.setHobby(hobby);
personMap.put(name,_person);
return _person;
}
@Override
public person getPerson(String name) throws RemoteException {
return personMap.get(name);
}
@Override
public boolean deletePerson(String name) throws RemoteException {
return null!=personMap.remove(name)?true:false;
}
}
@Override
public void onCreate() {
super.onCreate();
personMap=new HashMap<String,person>();
}
@Override
public int onStartCommand(Intent intent,int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return new myPersonBinder();
}
}
别忘了在AndroidManifest.xml文件中定义好service
aidlservice module项目结构:
app Module
先在app module的build.gradle文件中添加对aidlmodels module的引用.
接下来,同前面一样,新建一个aidl文件夹,将aidlmodels models中的person.aidl文件和aidlservice module中的IPersonActive.aidl文件拷贝到app Module的aidl文件夹下,各个aidl文件的包名也要和它们在原module中的包名相同.
然后按Ctrl+F9编译一下.
接下来就是客户端的具体实现了,App module 的MainActivity.java文件如下:
package com.my.open.ipcdemo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
import com.my.open.aidlmodels.person;
import com.my.open.aidlservice.IPersonActive;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("Service is Connected.....");
remoteService = IPersonActive.Stub.asInterface(service);
isBind = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
System.out.println("service is Disconnected.........");
isBind = false;
}
};
private IPersonActive remoteService;
private EditText etName;
private Spinner spSex;
private EditText etAge;
private EditText etHobby;
private Intent _intent;
private boolean isBind = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etName = (EditText) findViewById(R.id.etName);
spSex = (Spinner) findViewById(R.id.spSex);
etAge = (EditText) findViewById(R.id.etAge);
etHobby = (EditText) findViewById(R.id.etHobby);
Button btnBindService = (Button) findViewById(R.id.btnBindService);
Button btnUnBindService = (Button) findViewById(R.id.btnUnBindService);
Button btnAdd = (Button) findViewById(R.id.btnAdd);
Button btnDel = (Button) findViewById(R.id.btnDel);
Button btnQuery = (Button) findViewById(R.id.btnQuery);
btnBindService.setOnClickListener(this);
btnUnBindService.setOnClickListener(this);
btnAdd.setOnClickListener(this);
btnDel.setOnClickListener(this);
btnQuery.setOnClickListener(this);
}
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.btnBindService:
_intent = new Intent();
_intent.setAction("com.my.open.aidlservice");
bindService(_intent, conn, Context.BIND_AUTO_CREATE);
break;
case R.id.btnUnBindService:
if (isBind)
{
unbindService(conn);
isBind = false;
}else
Toast.makeText(this, "服务未绑定,无需解绑", Toast.LENGTH_SHORT).show();
break;
case R.id.btnAdd:
addPersonToService();
break;
case R.id.btnDel:
delPersonFromService();
break;
case R.id.btnQuery:
queryPersonFromService();
break;
default:
break;
}
}
//根据EditView控件etName中输入的名称查找记录 private void queryPersonFromService() { if (!isBind) { Toast.makeText(this, "远程服务没有绑定或被系统kill", Toast.LENGTH_SHORT).show(); return; } String name = etName.getText().toString().trim(); if (TextUtils.isEmpty(name)) { Toast.makeText(this, "姓名不能为空!", Toast.LENGTH_SHORT).show(); return; } try { person _person = remoteService.getPerson(name); if (null != _person) { etAge.setText(String.valueOf(_person.getAge())); etHobby.setText(_person.getHobby()); int position = _person.getSex(); spSex.setSelection(position); Toast.makeText(this, "查询数据成功!", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "查询的记录不存在", Toast.LENGTH_SHORT).show(); } } catch (Exception e) { Toast.makeText(this, "查询记录出现异常:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } }
private void delPersonFromService() { if (!isBind) { Toast.makeText(this, "远程服务没有绑定或被系统kill", Toast.LENGTH_SHORT).show(); return; } String name = etName.getText().toString().trim(); if (TextUtils.isEmpty(name)) { Toast.makeText(this, "姓名不能为空!", Toast.LENGTH_SHORT).show(); return; } try { boolean success=remoteService.deletePerson(name); if (success) { Toast.makeText(this, "删除数据成功!", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "删除的记录不存在", Toast.LENGTH_SHORT).show(); } } catch (Exception e) { Toast.makeText(this, "删除记录出现异常:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } } private void addPersonToService() { if (!isBind) { Toast.makeText(this, "远程服务没有绑定或被系统kill", Toast.LENGTH_SHORT).show(); return; } String name = etName.getText().toString().trim(); int sex = spSex.getSelectedItemPosition(); String strAge=etAge.getText().toString().trim(); int age = Integer.valueOf(strAge); String hobby = etHobby.getText().toString().trim(); if (TextUtils.isEmpty(name)) { Toast.makeText(this, "请输入姓名!", Toast.LENGTH_SHORT).show(); return; } try { person _person = remoteService.addPerson(name, sex, age, hobby); if (null==_person) { Toast.makeText(this, "姓名已存在,请更改", Toast.LENGTH_SHORT).show(); return; } etName.setText(""); spSex.setSelection(0); etAge.setText("0"); etHobby.setText(""); etName.requestFocus(); Toast.makeText(this, "新增数据成功!", Toast.LENGTH_SHORT).show(); } catch (Exception e) { Toast.makeText(this, "新增数据出现异常:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } }}//根据EditView控件etName中输入的名称删除记录
activity_main.xml布局文件如下(太丑了,demo就凑合着用)
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.my.open.ipcdemo.MainActivity">
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button android:id="@+id/btnBindService"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="绑定远程服务">
</Button>
<Button android:id="@+id/btnUnBindService"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="解除绑定">
</Button>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="姓名"/>
<EditText
android:id="@+id/etName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="性别"/>
<Spinner
android:id="@+id/spSex"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:entries="@array/sex"></Spinner>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="年龄"/>
<EditText
android:id="@+id/etAge"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:inputType="number"
android:text="0"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="爱好"/>
<EditText
android:id="@+id/etHobby"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"/>
</LinearLayout>
<Button
android:id="@+id/btnAdd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="保存"/>
<Button
android:id="@+id/btnDel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="删除"/>
<Button
android:id="@+id/btnQuery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="查询"/>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
性别下拉框的item resource定义在values目录的sex_item.xml文件中,内容如下
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="sex">
<item>男</item>
<item>女</item>
</string-array>
</resources>
app module的项目结构:
由于本人刚接触Android开发,水平非常有限,所以这个demo还有不足之处,仅仅实现了最简单的进程间的通信,但也希望对那些刚刚接触AndroidStudio的同学们有帮助.
demo
下载