提示1:首先介绍作者编写本文时的水平和状态(避免浪费大佬时间),如果想要直接快速了解如何使用,直接看尝试使用那一章即可。
提示2:由于一开始想将原理各方面都讲的很全面,但是最后由于时间不太够了,所以原理方面我只列了几篇我在学习时看到的写的比较好的参考文章,有需要的朋友可以去阅读一下。
首先了解到安卓应用程序的四个常用组件,然后在这里见到了service这一关键词。
了解方式为 菜鸟教程
Service是android 系统中的四大组件之一(Activity、Service、BroadcastReceiver、ContentProvider),它跟Activity的级别差不多,但不能自己运行只能后台运行,并且可以和其他组件进行交互。service可以在很多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务总是藏在后台的。
在网上搜索之后,了解到的一般都是service的运行流程、方式之类的具体场景使用方法,在这里就先不详细研究,我就大致了解了基础的概念。
在了解学习aidl之前,需要先了解Binder机制。
机制:Binder是一种进程间通信的机制
驱动:Binder是一个虚拟物理设备驱动
应用层:Binder是一个能发起进程间通信的JAVA类
Binder就是Android中的血管,在Android中我们使用Activity,Service等组件都需要和AMS(system_server)进行通信,这种跨进程的通信都是通过Binder完成。
Activity,Service等组件和AMS不是同一个进程,其实也是多进程通信。
tips1:具体可以参考以下链接,讲解的十分详细且清晰,不仅是概念介绍,还包括了原理级别的讲解,想要读懂需要对操作系统这门计算机基础课程有一定的了解。
tips2:可以详细看一下传统的IPC方式和Binder中的IPC方式
参考链接:https://blog.csdn.net/ly0724ok/article/details/117566381/
AIDL(Android 接口定义语言),可以使用它定义客户端与服务端进程间通信(IPC)的编程接口,在 Android 中,进程之间无法共享内存(用户空间),不同进程之间的通信一般使用 AIDL 来处理。
序列化和反序列化:由于不同的进程有着不同的内存区域,并且它们只能访问自己的那一块内存区域,所以我们不能像平时那样,传一个句柄过去就完事了——句柄指向的是一个内存区域,现在目标进程根本不能访问源进程的内存,那把它传过去又有什么用呢?所以我们必须将要传输的数据转化为能够在内存之间流通的形式。这个转化的过程就叫做序列化与反序列化。
参考链接:aidl看这一篇就够了!
备注:该文章写的也很好
在了解了一些内容后,我想要去尝试一下对aidl进行一个简单的应用,通过一个demo来进行说明,然后这个demo主要就是实现了客户端调动服务端的service,完成一个加法操作。
在尝试使用的过程中出现了很多问题,我也耗费了很长时间才把这一个小小的,简单的demo给弄出来,显然是自己基础太差导致的问题,但是解决方案只要想找的话,肯定也是能够找到的。
以下是我在进行尝试使用时所参考的文章:
链接:
本次尝试分为服务端和客户端,服务端用于提供某一服务,然后客户端可以直接调用服务端创建的服务即可。
以下是使用步骤的目录,可以先大致了解下流程。
服务端:
客户端:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
>
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="加法器服务端"/>
<EditText
android:id="@+id/et_add_x"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/et_add_y"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btn_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="add"/>
<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="相加结果为:"
/>
<TextView
android:id="@+id/tv_result"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="wrap_content"
/>
LinearLayout>
LinearLayout>
// IAddAidlLnterface.aidl
package com.example.myapplication;
// Declare any non-default types here with import statements
interface IAddAidlLnterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
int add(in int x, in int y);
}
== 编写完此代码后,需要clean project或者rebuild项目==
package com.example.myapplication;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class AddService extends Service {
public AddService() {
}
IAddAidlLnterface.Stub mBinder = new IAddAidlLnterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public int add(int x, int y) throws RemoteException {
return x + y;
}
};
@Override
public IBinder onBind(Intent intent) {
// // TODO: Return the communication channel to the service.
// throw new UnsupportedOperationException("Not yet implemented");
Log.d("ning","调用了AddService.onBind");
return mBinder;
}
}
这里需要在AndroidManifest.xml中注册服务(AndroidManifest.xml)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.myapplication">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication"
tools:targetApi="31">
<service
android:name=".AddService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.add"/>
<category android:name="android.intent.category.DEFAULT"/>
intent-filter>
service>
<activity
android:name=".ActFinishActivity"
android:exported="false" />
<activity
android:name=".ActStartActivity"
android:exported="false" />
<activity
android:name=".CalculatorActivity"
android:exported="false" />
<activity android:name=".MainActivity2" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
intent-filter>
activity>
application>
manifest>
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
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.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private static final String Tag = "ning";
private IAddAidlLnterface mService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//app启动后首先显示的布局,R是系统自动生成的类
setContentView(R.layout.activity_main);
TextView tv = findViewById(R.id.tv);
tv.setText("服务端加法器");
// //添加点击时间,跳转到MainActivity2
// Button button = findViewById(R.id.button);
// button.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View view) {
// //意图对象
// Intent intent = new Intent();
// //编辑意图上下文
// intent.setClass(MainActivity.this, ActStartActivity.class);
// startActivity(intent);
// }
// });
//学习activity生命周期
//打印当前所处周期
Log.d(Tag, "MainActivity onCreate");
//实现aidl服务端
aboutService();
findViewById(R.id.btn_add).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int x = Integer.parseInt(((EditText) findViewById(R.id.et_add_x)).getText().toString());
int y = Integer.parseInt(((EditText) findViewById(R.id.et_add_y)).getText().toString());
try {
Log.d("ning", "服务端 相加结果:" + mService.add(x, y));
TextView tv = (TextView) findViewById(R.id.tv_result);
int num = mService.add(x, y);
tv.setText(num + "");
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
ServiceConnection mConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d("ning", "服务端:连接 Service 成功");
mService = IAddAidlLnterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private void aboutService() {
Intent intent = new Intent(this, AddService.class);
bindService(intent, mConn, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStart() {
super.onStart();
//打印当前所处周期
Log.d(Tag,"MainActivity onStart");
}
@Override
protected void onResume() {
super.onResume();
//打印当前所处周期
Log.d(Tag,"MainActivity onResume");
}
@Override
protected void onPause() {
super.onPause();
//打印当前所处周期
Log.d(Tag,"MainActivity onPause");
}
@Override
protected void onStop() {
super.onStop();
//打印当前所处周期
Log.d(Tag,"MainActivity onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
//打印当前所处周期
Log.d(Tag,"MainActivity onDestroy");
}
@Override
protected void onRestart() {
super.onRestart();
//打印当前所处周期
Log.d(Tag,"MainActivity onRestart");
}
}
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
>
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="加法器客户端"/>
<EditText>
android:id="@+id/et_add_x"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/et_add_y"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btn_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="add"/>
<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="相加结果为:"
/>
<TextView
android:id="@+id/tv_result"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="wrap_content"
/>
LinearLayout>
LinearLayout>
// IAddAidlLnterface.aidl
package com.example.myapplication;
// Declare any non-default types here with import statements
interface IAddAidlLnterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
int add(in int x, in int y);
}
注:编写完此代码后,需要clean project或者rebuild项目
3. 客户端代码(MainActivity.java)
package com.example.demoaidlservice;
import androidx.appcompat.app.AppCompatActivity;
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.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import com.example.myapplication.IAddAidlLnterface;
public class MainActivity extends AppCompatActivity {
private IAddAidlLnterface mService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
aboutService();
findViewById(R.id.btn_add).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int x = Integer.parseInt(((EditText) findViewById(R.id.et_add_x)).getText().toString());
int y = Integer.parseInt(((EditText) findViewById(R.id.et_add_y)).getText().toString());
try {
Log.d("ning", "调用服务--客户端 相加结果:" + mService.add(x, y));
TextView tv = (TextView) findViewById(R.id.tv_result);
int num = x + y;
tv.setText(num + "");
} catch (Exception e) {
e.printStackTrace();
Log.d("ning",e.toString());
}
}
});
}
private void aboutService() {
Intent intent = new Intent();
// intent.setAction()
intent.setClassName("com.example.myapplication","com.example.myapplication.AddService");
bindService(intent, mConn, Context.BIND_AUTO_CREATE);
Log.d("ning", "aboutService成功");
}
ServiceConnection mConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
mService = IAddAidlLnterface.Stub.asInterface(service);
Log.d("ning", "客户端:连接 Service 成功");
}catch (Exception e){
Log.d("ning", "客户端:连接 Service 失败");
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConn);
}
}
注:如果运行出现错误,可能是由于客户端代码中建立连接的部分写错了,我当初就是在这个位置出现了问题,我参考的别的博客中,不是使用这种方式来建立intent,导致我一直无法顺利调用服务端的service,如果读者出现类似问题了,可以往这里思考一下。