跨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"
}
相关推荐
le1616161 分钟前
Android 依赖种类及区别:远程仓库依赖、打包依赖、模块依赖、本地仓库依赖
android
lxysbly1 分钟前
psp模拟器安卓版带金手指
android
云上凯歌1 小时前
02 Spring Boot企业级配置详解
android·spring boot·后端
hqiangtai1 小时前
Android 高级专家技术能力图谱
android·职场和发展
aqi001 小时前
FFmpeg开发笔记(九十七)国产的开源视频剪辑工具AndroidVideoEditor
android·ffmpeg·音视频·直播·流媒体
stevenzqzq1 小时前
Android Koin 注入入门教程
android·kotlin
炼金术2 小时前
SkyPlayer v1.1.0 - 在线视频播放功能更新
android·ffmpeg
用户276038157812 小时前
鲲鹏+昇腾:开启 AI for Science 新范式——基于PINN的流体仿真加速实践
android
此去正年少2 小时前
编写adb脚本工具对Android设备上的闪退问题进行监控分析
android·adb·logcat·ndk·日志监控
落羽凉笙3 小时前
Python基础(4)| 玩转循环结构:for、while与嵌套循环全解析(附源码)
android·开发语言·python