最近在学习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(); } } //根据EditView控件etName中输入的名称删除记录 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(); } }} 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 下载