Binder

服务端

在清单中申请权限

application外

<uses-permission android:name="android.permission.IINTERNET"></uses-permission>

application内

<service android:name=".MyService"
android:exported="true"
android:enabled="true"//用于指定一个组件是否启用可用)。它通常用于表明组件是否可以响应用户交互操作如点击或者触摸等
android:process=":server">//android:process 是一个用于指定组件应该运行的进程名称的属性。
在 Android 中,默认情况下,所有的组件(活动、服务、接收器等)都在应用的主进程中运行。这意味着它们共享同一个进程空间和资源。
通过设置 android:process 属性,可以使得特定的组件在一个独立的进程中运行,而不是与主进程共享
<intent-filter>
<action android:name="android.intent.action.server.student"></action>
</intent-filter>
</service>

MainActivity.java没有特别的代码


MyService.java

public class MyService extends Service
{
public static final int REQUEST_CODE = 1000;
private final Binder mBinder = new Binder();
@Override
protected boolean onTransact(int code,@NonNull Parcel data,@Nullable Parcel reply,int flags) throws RemoteException//表示在进行跨进程通信(IPC)时可能发生的异常情况。
{
/*code:这是一个整数参数,表示客户端请求的操作代码(或者称为事务码)。客户端和服务端之间的通信通过这个代码来区分不同的请求或操作。在客户端调用远程服务的方法时,通常会将一个特定的事务码作为参数传递给服务端,服务端在 onTransact 方法中根据这个事务码来确定具体要执行的操作。

data:这是一个 Parcel 对象,用于在客户端和服务端之间传输数据。Parcel 是 Android 中用于高效传输数据的类,可以将对象序列化为字节流,然后在不同进程之间进行传递。在 onTransact 方法中,data 参数包含了客户端传递给服务端的请求数据和参数。

reply:这也是一个 Parcel 对象,用于存储服务端向客户端返回的响应数据。在 onTransact 方法中,服务端可以通过修改 reply 对象来返回处理结果给客户端。客户端在调用远程方法后,会等待服务端处理完成并将结果填充到 reply 中,然后解析并处理返回结果。

flags:
这是一个整数参数,用于指示当前事务的特性或标志。在 onTransact 方法中,flags 可以用来描述事务的一些额外信息,例如事务的方向(入站或出站)、是否需要将数据进行回复等。具体的标志值和含义可以根据具体的 IPC 使用场景而定,例如 FLAG_ONEWAY 表示单向通信,不需要返回结果。*/
if(code == REQUEST_CODE)
{
String studentName = data.readSting();//readString() 是 Parcel 类提供的方法之一,用于在跨进程通信中读取字符串数据
ing age = getStudentAge(studentName);
if(reply != null)
{
reply.writeInt(age);
}
return true;
}
return super.onTransact(code,data,reply,flags);
}
public int getStudentAge(String name)
{
Student student = new Student();
return student.getAge(name);
}
@Nullable
@Override
public IBinder onBind(Intent intent)
{
return mBinder;
}
}

Student.java

public class Student
{
private static Map<String,Integer> info = new HashMap<>();
public Student()
{
info.put("zhangsan",23);
info.put("lisi",19);
info.put("wangwu",20);
}
public int getAge(String name)
{
return info.get(name);
}
public void setAge(String name, int age)
{
info.put(name,age);
}
}

客户端

在清单中申请权限(application外)

<uses-permisson android:name="android.permissoin.INTERNET"></uses-permisson>
<queries>
<package android:name="a.b.c.usebindrserver"/>
</queries>
<!--<queries> 元素是 Android 11(API 级别 30)引入的新特性,用于声明应用程序需要访问的其他应用程序的信息。它允许开发者在应用安装时就声明需要访问的其他应用程序,以便系统在运行时检查和控制访问权限。-->

MainActivity.java,部分代码

public class MainActivity extends AppCompatActivity
{
TextView tv;
Button btn_bindService,btn_searchAge;
IBinder binder;
public static final int REQUEST_CODE = 1000;
private final ServiceConnection serviceConnection = new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName componentName,IBinder iBinder)
{
binder = IBinder;
/*componentName 参数:
ComponentName 对象用于表示你所连接的服务组件的名称。
它包含两部分信息:包名和类名,用于唯一标识服务组件。
你可以通过 componentName 参数获取到服务组件的详细信息,如输出日志或者进行其他逻辑处理。*/
}
@Override
public void onServiceDisconnected(ComponentName componentName)
{
binder = null;
}
};
private void bindRemoteService()
{
String action = "android.intent.action.server.student";
Intent intent = new Intent(action);
intnt.setPackage("a.b.c.usebinderserver");//setPackage 方法用于设置 Intent 的目标包名,即指定你希望发送这个 Intent 给哪个应用程序。
boolean bt = this.bindService(intent,serviceConnection,BIND_AUTO_CREATE);
Log.i("qqqqqqqq","bindRemoteService result:" + bt);
}
protected void onCreate(Bundle saveInstanceState)
{
tv = findViewById(R.id.tv_view);
btn_bindService = findViewById(R.id.btn_bindService);
btn_searchAge = findViewById(R.btn_searchAge);
btn_bindService.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
bindRemoteService();
}
});
btn_searchAge.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
Log.i("qqqq-client","开始查询");
getRemoteAge("zhangsan");
}
});
private void getRemoteAge(String name)
{
Parcel data = Parcel.obtain();
Parcel reply = Parce.obtain();//注意下,Parcel对象也是通过.obtain()获得
data.wtiteString(name);
try
{
if(binder == null)
{
return;
}
binder.transact(REQUEST_CODE,data,reply,0);
int age = reply.readInt();
tv.setText("年龄查询结果:"+age);
}catch(Exception ee)
{
ee.printStackTrace();
tv.setText(ee.toString());
}
}

}
}