跨app调用Service

一、项目要求

1、在Model app中创建一个服务 QueryWeekdayService,该服务提供一个公共方法 QueryWeekday,输入参数日期(年、月、日),返回该日期是星期几。要求本应用程序和其它应用程序都能够绑定到该服务,并调用公共方法。

2、在Model app2中创建一个应用程序app2,验证1中创建的服务。

二、项目步骤

1、在Model app中创建service:

1)新建AIDL文件

(1)修改build.gradle文件,在Android中添加属性:

buildFeatures{aidl true},如果不添加的话将无法创建AIDL文件

(2)创建AIDL文件

在包中,new--->AIDL--->AIDL file

创建结果:

(3)声明想要远程调用的接口
(4)点击 Build-->Rebuild Project,从而将接口文件自动生成为java文件

创建结果:

2)写Service文件(这一步和写本地Service有点不同)

(1)声明并实现一个IBinder对象(这里与一般的bindService不同),这里就是实例化你刚刚定义的接口
java 复制代码
private final IBinder mBinder = new IMyAidlInterface.Stub(){
    @Override
    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {}
    @Override
    public String remoteGetWeekday(String date) throws RemoteException {
        return getWeekday(date); //调用具体的业务
    }
};
(2)绑定你的接口
java 复制代码
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
(3)写具体的业务
java 复制代码
public String getWeekday(String date){
    String[] dates = date.split("-");
    String[] weekdays = {"星期日","星期一","星期二","星期三","星期四","星期五","星期六",};
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.YEAR,Integer.parseInt(dates[0]));
    cal.set(Calendar.MONTH,Integer.parseInt(dates[1])-1);
    cal.set(Calendar.DATE,Integer.parseInt(dates[2]));
    int weekday = cal.get(Calendar.DAY_OF_WEEK)-1;
    return date+"的那天是"+weekdays[weekday];
}
(4)在Model app中创建一个activity MainActivity,用于检测功能

下面附上各个模块的功能以及代码:

onCreate():程序启动时会调用此方法,进行相关的初始化设置,如加载界面布局文件,获取查询按钮和日期输入框的实例,以及设置查询按钮的点击事件。

onStart():当Activity启动或重新可见时,会调用此方法,这里主要是绑定远程服务,使用bindService()方法,将创建的Intent和ServiceConnection对象传入,通过后台自动创建服务的方式进行绑定。

onStop():当Activity停止时,会调用此方法,这里主要是解绑远程服务,防止Activity销毁后,服务还持有Activity的引用,导致内存泄露。

java 复制代码
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button queryBtn = (Button)findViewById(R.id.queryBtn); // 获取查询按钮
        EditText dateText = (EditText)findViewById(R.id.dateEditView); // 获取日期输入框
        queryBtn.setOnClickListener(v -> {
            String date = dateText.getText().toString().trim(); // 获取输入的日期
            String weekday = null;
            try {
                weekday = queryWeekday.remoteGetWeekday(date); // 调用远程服务的方法获取星期
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            Toast.makeText(this,weekday,Toast.LENGTH_LONG).show(); // 显示结果
        });
    }
    @Override
    protected void onStart() {
        super.onStart();
        Intent intent = new Intent(this,QueryWeekday.class); // 创建一个Intent对象,用于指定要绑定的服务
        Boolean result = bindService(intent,conn,BIND_AUTO_CREATE); // 绑定服务,并返回绑定结果
        Log.i("result",result+"");
    }
    @Override
    protected void onStop() {
        super.onStop();
        unbindService(conn); // 解绑服务
    }

ServiceConnection conn:这是一个服务连接对象,当服务连接成功时,会回调其onServiceConnected()方法,然后通过IMyAidlInterface.Stub.asInterface(service)获取远程服务的接口实例,以便进行后续的通信。当服务断开连接时,会回调其onServiceDisconnected()方法。

java 复制代码
    private final ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            queryWeekday = IMyAidlInterface.Stub.asInterface(service); // 获取远程服务的接口实例
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

3)检查Service功能是否正常

2、在ModelB中调用ModelA中的service

1)创建AIDL文件

在同一个项目下新建一个Model app2,然后参照上面的步骤创建一个AIDL文件。需要注意的是,必须保证包名一致。

2)在Model app2中添加依赖

(1)修改Model app2的build.grade
(2)修改Model app的builder.grade

重构项目:

(3)编写Activity

Model app2的activity的代码和Model app的activity代码差不多,就不再赘述了

3、运行Model app2的Activity

三、项目源代码

Programming-Learning-Process/Android学习 at main · cx1768762017/Programming-Learning-Process (github.com)

四、编写项目过程中的报错(主要是修改build.grade)

1、Model app2添加Model app的依赖后rebuild的时候报错,但是sync的时候没有报错

这个问题可以通过修改Model app的build.grade中的plugins属性解决,将其从

bash 复制代码
plugins {
    id 'com.android.application'
}

改成:

bash 复制代码
plugins {
    id 'com.android.library'
}

2、完成上述修改后,sync的时候报错:

rebuild的时候报错:

这个问题可以通过修改Model app的build.grade中的defaultConfig的applicationId属性解决,将其从:

arduino 复制代码
defaultConfig {
    applicationId "com.example.week_11_experiment_2"
    minSdk 24
    targetSdk 33
    versionCode 1
    versionName "1.0"

    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

改成:

perl 复制代码
defaultConfig {
    // applicationId "com.example.week_11_experiment_2"
    minSdk 24
    targetSdk 33
    versionCode 1
    versionName "1.0"

    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
相关推荐
CYRUS STUDIO8 分钟前
ARM64汇编寻址、汇编指令、指令编码方式
android·汇编·arm开发·arm·arm64
weixin_449310841 小时前
高效集成:聚水潭采购数据同步到MySQL
android·数据库·mysql
Zender Han1 小时前
Flutter自定义矩形进度条实现详解
android·flutter·ios
白乐天_n3 小时前
adb:Android调试桥
android·adb
姑苏风7 小时前
《Kotlin实战》-附录
android·开发语言·kotlin
数据猎手小k10 小时前
AndroidLab:一个系统化的Android代理框架,包含操作环境和可复现的基准测试,支持大型语言模型和多模态模型。
android·人工智能·机器学习·语言模型
你的小1011 小时前
JavaWeb项目-----博客系统
android
风和先行11 小时前
adb 命令查看设备存储占用情况
android·adb
AaVictory.12 小时前
Android 开发 Java中 list实现 按照时间格式 yyyy-MM-dd HH:mm 顺序
android·java·list
似霰13 小时前
安卓智能指针sp、wp、RefBase浅析
android·c++·binder