跨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"
}
相关推荐
吃着火锅x唱着歌12 分钟前
PHP7内核剖析 学习笔记 第四章 内存管理(1)
android·笔记·学习
_Shirley2 小时前
鸿蒙设置app更新跳转华为市场
android·华为·kotlin·harmonyos·鸿蒙
hedalei3 小时前
RK3576 Android14编译OTA包提示java.lang.UnsupportedClassVersionError问题
android·android14·rk3576
锋风Fengfeng3 小时前
安卓多渠道apk配置不同签名
android
枫_feng4 小时前
AOSP开发环境配置
android·安卓
叶羽西4 小时前
Android Studio打开一个外部的Android app程序
android·ide·android studio
qq_171538856 小时前
利用Spring Cloud Gateway Predicate优化微服务路由策略
android·javascript·微服务
Vincent(朱志强)7 小时前
设计模式详解(十二):单例模式——Singleton
android·单例模式·设计模式
mmsx7 小时前
android 登录界面编写
android·登录界面
姜毛毛-JYM7 小时前
【JetPack】Navigation知识点总结
android