前言
看了很多优快云大牛的博客,心血澎湃决定以后要把自己学的东西用博客记录下来。之前也陆陆续续写了一些 但是都随便潦草应付,后来发现排名靠前的博客都是那么认真负责,我以后也不能随便吧,我最看不起坑队友,误人子弟的事了。呵呵 也要锻炼自己的意志吧,相信自己日积月累,水滴石穿!废话不多说了进入正题。
很多程序员从Eclipse开发编写AIDL的流程已经是了如指掌了,但是在Android Studio上我百度了一下很多人没有把创建AIDL 进行跨进程通讯的例子步骤写的很详细,在这里我主要讲解一下Android Studio创建AIDL的流程,帮助AS新手快速创建AIDL。
1、先建立一个android工程,用作服务端
AS 右键》NEW 》 Module 创建了一个 aidl 的Module
2、创建一个实例Student.java
在com.example.zdq 这个包下 NEW》Package 创建了一个aidl的空包
新建一个Student 实例 implement Parcelable这个接口才能进行IPC通讯
package com.example.zdq.aidl;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by Administrator on 2017/8/24.
*/
public class Student implements Parcelable {
public int sno;
public String name;
public int sex;
public int age;
public Student(){
}
protected Student(Parcel in) {
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(sno);
dest.writeString(name);
dest.writeInt(sex);
dest.writeInt(age);
}
public void readFromParcel(Parcel in){
sno=in.readInt();
name=in.readString();
sex=in.readInt();
age=in.readInt();
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<Student> CREATOR = new Creator<Student>() {
@Override
public Student createFromParcel(Parcel in) {
return new Student(in);
}
@Override
public Student[] newArray(int size) {
return new Student[size];
}
};
}
需要注意的是,readFromParcel和writeToParcel操作数据成员的顺序要一致
3、创建IStudentService.aidl
鼠标点击放在 aidl这个包下 AS自带新建AIDL文件功能 按照如图所示 创建一个IStudentService的AIDL文件 然后系统自动会生成 跟java同级目录aidl 同包名com.example.zdq.aidl 大家可以看图 IStudentService.aidl就在这个目录下面 IStudentService.aidl 里面的代码先别管 都是系统生成的
注意这里我先创建IStudentService.aidl 而不是创建Student.aidl 是因为AS有个BUG 不能创建跟实例同名的aidl
4、创建Student.aidl
ok接下来我们再创建一个跟Student实例一模一样的Student.aidl 鼠标放在com.example.zdq.aidl这个包上 右键 NEW》AIDL 命名为Student.aidl
// ad.aidl
package com.example.zdq.aidl;
// Declare any non-default types here with import statements
parcelable Student;
注意的就是 parcelable 这个是小写 是一个类型 不是 Parcelable 接口
5、编写IStudentService.aidl 提供给客户端使用的方法
// IStudentService.aidl
package com.example.zdq.aidl;
import com.example.zdq.aidl.Student;
// Declare any non-default types here with import statements
interface IStudentService {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
List<Student> getStudents();
void addStudent(in Student student);
}
到了这个一步 Build》Rebuild Project 如图所示就证明aidl创建ok了
6、创建服务端StudentService并且在AndroidMenifest中声明StudentService
StudentService代码
package com.example.zdq;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.example.zdq.aidl.IStudentService;
import com.example.zdq.aidl.Student;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2017/8/24.
*/
public class StudentService extends Service {
private final static String TAG = "StudentService";
private static final String PACKAGE_SAYHI = "com.example.test";
private NotificationManager mNotificationManager;
private boolean mCanRun = true;
private List<Student> mStudents = new ArrayList<Student>();
//这里实现了aidl中的抽象函数
private final IStudentService.Stub mBinder=new IStudentService.Stub(){
@Override
public List<Student> getStudents() throws RemoteException {
return mStudents;
}
@Override
public void addStudent(Student stu) throws RemoteException {
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onCreate() {
super.onCreate();
ServiceWorker sw=new ServiceWorker();
new Thread(sw).start();
synchronized (mStudents) {
for (int i = 1; i < 6; i++) {
Student student = new Student();
student.name = "student#" + i;
student.age = i * 5;
mStudents.add(student);
}
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
class ServiceWorker implements Runnable
{
long counter = 0;
@Override
public void run()
{
// do background processing here.....
while (mCanRun)
{
Log.d("scott", "" + counter);
counter++;
try
{
Thread.sleep(2000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
}
AndroidManifest.xml 代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.zdq">
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme">
<activity android:name="com.example.zdq.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name="com.example.zdq.StudentService"
android:process=":remote"
android:exported="true"
>
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="com.exmaple.aidl.StudentService" />
</intent-filter>
</service>
</application>
</manifest>
7、整个项目包结构截图让大家看的更清楚
在这里我故意把build.gradle 文件也截图出来 就是看applicationId “com.example.aidl” 这个属性 这里跟我创建的包名是不一样的 有真机的朋友可以跑起来 用ps命令看一下 进程名就是com.example.aidl
这跟在客户端开启远程服务也有关系
Intent intent=new Intent(“com.exmaple.aidl.StudentService”); intent.setPackage(“com.example.aidl”);
bindService(intent,conn, Service.BIND_AUTO_CREATE);
如果 intent.setPackage(“com.example.zdq”);这样是调用不起来的
服务端ok了 下面编写客户端
8、然后创建android工程 命名aidlClient
9、创建一个跟服务端aidl文件所在一模一样的包名com.example.zdq.aidl
把Student.java文件copy过来
然后鼠标点击所在的包名 NEW》AIDL 随便取个名字 系统就会生成跟java同级目录aidl 同包名com.example.zdq.aidl 的一个aidl文件 删除该aidl文件 把服务端的IStudentService.aidl 和Student.aidl copy过来
当然记得跟服务端一样 Build》RebuildProject
10、然后在MainActivity中连接远程service 获取IBinder实例 调用IStudentService中的方法
package com.example.aidlclient;
import android.app.AlertDialog;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.example.zdq.aidl.IStudentService;
import com.example.zdq.aidl.Student;
public class MainActivity extends AppCompatActivity {
private final static String TAG="client";
private IStudentService mStudentBinder;
ServiceConnection conn=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.i(TAG,"onServiceConnected>");
mStudentBinder= IStudentService.Stub.asInterface(iBinder) ;
try {
Student stu= mStudentBinder.getStudents().get(0);
showDialog(stu.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.i(TAG,"onServiceDisconnected");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button start_btn= (Button) findViewById(R.id.start_btn);
start_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.i(TAG,"onclick");
Intent intent=new Intent("com.exmaple.aidl.StudentService");
intent.setPackage("com.example.aidl");
bindService(intent,conn, Service.BIND_AUTO_CREATE);
if(mStudentBinder!=null){
Log.i(TAG,"mStudentBinder="+mStudentBinder);
try {
Student stu= mStudentBinder.getStudents().get(0);
showDialog(stu.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
}
public void showDialog(String message)
{
new AlertDialog.Builder(MainActivity.this)
.setTitle("scott")
.setMessage(message)
.setPositiveButton("确定", null)
.show();
}
}
11、客户端aidlClient项目结构截图
用真机 先跑服务端 再跑客户端 看看效果吧。第一次这么认真写博客,有些写的不好地方请多多指教,可以一起交流交流!以后我也会坚持分享干货的。