跨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"
}
相关推荐
阿巴斯甜9 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker10 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952711 小时前
Andorid Google 登录接入文档
android
黄林晴12 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android