接上移篇 Android AIDL 学习(服务端)我们今天来看看客户端怎么实现调用。
我们还是先创建个客户端项目,AClient
开发环境:Android Studio 3.6.2
保存的地方,你根据你的习惯随便找个地方保存。
要实现AIDL的调用,需要有AIDL的服务放提供为我们AIDL接口文件,还有必须的类别才行。
那我们BService服务端,需要提供给我慢AIDL接口,还有用到的Book类的定义。
还需要提供给我们调用服务的action:com.example.bservice.bookService
服务器提供的AIDL接口:IMyBookManager
// IMyBookManager.aidl
package com.example.bservice;
// Declare any non-default types here with import statements
//需要采用全部包名的引入。
import com.example.bservice.Book;
//需要说明我们引入的book 是个序列化的类。
parcelable Book;
interface IMyBookManager {
/**
* 默认添加的基础类型接口,不用可以删掉
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
String login(String userName, String pwd);
Book queryByName(String bookName);
}
服务端提供Book类的定义
package com.example.bservice;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
public class Book implements Parcelable {
private int price;
private String name = "";
public Book(){}
protected Book(Parcel in) {
price = in.readInt();
name = in.readString();
}
public static final Creator CREATOR = new Creator() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@NonNull
@Override
public String toString() {
return "name:" + name + ",price:" + price;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(price);
dest.writeString(name);
}
}
我们把这两个类添加到我们的项目中
在main右键选择新建一个文件夹,命名为aidl
在didl上点击右键新建包 com.example.bservice 这个报名就是服务提供给我们AIDL文件的报名。必须要一样。
在这个包中我们添加服务端给我们的aidl 文件
处理完了接口文件,我们来处理接口文件返回来的类Book。
在src\main\java\新建包 com.example.bservice;
在新建的包上右键新建Book类。
把服务端提供的Book类的结构保存到文件。
到这类服务器提供给我们的接口文件、类文件,我们按照要求一模一样的添加到了我们的项目中,那接下来就是要如何的调用接口了。
既然AIDL是采用绑定服务的方式向外提供服务,那我们第一步要做的就是需要启动绑定服务,服务启动后,获取返回的binder对象。获取到对象后就可以通过调用对象提供的接口来完成相应的工作。
我们实现一个简单的调用功能,有个连接按钮来绑定服务,有个登录来进行模拟登录验证,有个图书的查询功能,并显示返回的图书信息。
好了这个功能我就从mainactivity的布局文件中实现。
代码如下
这就是一个连接AIDL的学习示例不要太纠结具体的功能是否有意义。
界面定义完成之后,我们来看看具体的diam实现
我先来定义下我需要的控件。
package com.example.aclient;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private Button btnConnection;
private TextView txtConnectionState;
private EditText etName;
private EditText etPwd;
private Button btnLogin;
private TextView etLoginState;
private EditText etBookInfo;
private Button btnQuery;
private EditText etBookName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews(){
btnConnection = findViewById(R.id.btnConnection);
txtConnectionState = findViewById(R.id.txtConnectionState);
etName = findViewById(R.id.etName);
etPwd = findViewById(R.id.etPwd);
btnLogin = findViewById(R.id.btnLogin);
etLoginState = findViewById(R.id.etLoginState);
etBookInfo = findViewById(R.id.etBookInfo);
btnQuery = findViewById(R.id.btnQuery);
etBookName = findViewById(R.id.etBookName);
}
}
定义好控件之后,我们先来看看连接怎么实现。给btnConnection 添加点击事件,从中调用bindService来开启服务。
boolean bindService( Intent service, ServiceConnection conn, int flags);
开发服务需要三个参数
service 传入要绑定的服务。
conn 连接成功后返回绑定对象。
在写服务端的时候,服务端有定义了一个action:com.example.bservice.bookService
定义一个ServiceConnection 的对象conn;
public class MainActivity extends AppCompatActivity {
//控件定义
......
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
......
}
再定义个IMyBookManager用于接受连接返回的对象,后续的调用也需要此对象。
public class MainActivity extends AppCompatActivity {
//控件定义
......
private IMyBookManager bookManager = null;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
bookManager = IMyBookManager.Stub.asInterface(service);
txtConnectionState.setText("连接成功!");
}
@Override
public void onServiceDisconnected(ComponentName name) {
bookManager = null;
}
};
......
}
我来实现btnConnection 按钮的点击事件。
btnConnection.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("com.example.bservice.bookService");
intent.setPackage("com.example.bservice");
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
});
在事件中,我们定义了一个intent 并发送bindSevice进行绑定。
我来实现登录的事件
btnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(bookManager == null)
{
Toast.makeText(MainActivity.this, "还没有绑定服务。", Toast.LENGTH_LONG).show();
return;
}
if(etName.getText().toString().isEmpty() || etPwd.getText().toString().isEmpty()){
Toast.makeText(MainActivity.this, "用户名或密码不能为空。", Toast.LENGTH_LONG).show();
return;
}
try {
String resStr = bookManager.login(etName.getText().toString(), etPwd.getText().toString());
if(resStr.compareToIgnoreCase("success") == 0){
etLoginState.setText("登录成功!");
} else{
throw new RemoteException("登录失败");
}
} catch (RemoteException e) {
e.printStackTrace();
etLoginState.setText("登录成功!");
}
}
});
最后我们来实现图书查询的事件:
btnQuery.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(bookManager == null)
{
Toast.makeText(MainActivity.this, "还没有绑定服务。", Toast.LENGTH_LONG).show();
return;
}
if(etBookName.getText().toString().isEmpty()){
Toast.makeText(MainActivity.this, "请输入您要查找的图书。", Toast.LENGTH_LONG).show();
return;
}
try {
Book book = bookManager.queryByName(etBookName.getText().toString());
if(book != null){
etBookInfo.setText(book.toString());
} else{
throw new RemoteException("查询失败");
}
} catch (RemoteException e) {
e.printStackTrace();
etBookInfo.setText("查询失败");
}
}
});
全部的代码:
package com.example.aclient;
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.os.RemoteException;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.example.bservice.Book;
import com.example.bservice.IMyBookManager;
public class MainActivity extends AppCompatActivity {
private Button btnConnection;
private TextView txtConnectionState;
private EditText etName;
private EditText etPwd;
private Button btnLogin;
private TextView etLoginState;
private EditText etBookInfo;
private Button btnQuery;
private EditText etBookName;
private IMyBookManager bookManager = null;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
bookManager = IMyBookManager.Stub.asInterface(service);
txtConnectionState.setText("连接成功!");
}
@Override
public void onServiceDisconnected(ComponentName name) {
bookManager = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews(){
btnConnection = findViewById(R.id.btnConnection);
btnConnection.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("com.example.bservice.bookService");
intent.setPackage("com.example.bservice");
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
});
txtConnectionState = findViewById(R.id.txtConnectionState);
etName = findViewById(R.id.etName);
etPwd = findViewById(R.id.etPwd);
btnLogin = findViewById(R.id.btnLogin);
btnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(bookManager == null)
{
Toast.makeText(MainActivity.this, "还没有绑定服务。", Toast.LENGTH_LONG).show();
return;
}
if(etName.getText().toString().isEmpty() || etPwd.getText().toString().isEmpty()){
Toast.makeText(MainActivity.this, "用户名或密码不能为空。", Toast.LENGTH_LONG).show();
return;
}
try {
String resStr = bookManager.login(etName.getText().toString(), etPwd.getText().toString());
if(resStr.compareToIgnoreCase("success") == 0){
etLoginState.setText("登录成功!");
} else{
throw new RemoteException("登录失败");
}
} catch (RemoteException e) {
e.printStackTrace();
etLoginState.setText("登录成功!");
}
}
});
etLoginState = findViewById(R.id.etLoginState);
etBookInfo = findViewById(R.id.etBookInfo);
btnQuery = findViewById(R.id.btnQuery);
btnQuery.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(bookManager == null)
{
Toast.makeText(MainActivity.this, "还没有绑定服务。", Toast.LENGTH_LONG).show();
return;
}
if(etBookName.getText().toString().isEmpty()){
Toast.makeText(MainActivity.this, "请输入您要查找的图书。", Toast.LENGTH_LONG).show();
return;
}
try {
Book book = bookManager.queryByName(etBookName.getText().toString());
if(book != null){
etBookInfo.setText(book.toString());
} else{
throw new RemoteException("查询失败");
}
} catch (RemoteException e) {
e.printStackTrace();
etBookInfo.setText("查询失败");
}
}
});
etBookName = findViewById(R.id.etBookName);
}
}
运行结果