无痛的使用BindService,从进程内通信改成允许进程间通信

1 题目要求

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

原创作品,转载请声明

2 实现思路

笔者上课的教材上面明确标注BindService只能进行进程内绑定,因此让笔者在实现题目需要的时候费了很多精力(辣鸡书,不看也罢 √)

回归正题,分析题目可知,需要通过服务去获取输入日期是星期几,所以一个简单的直觉就是使用BindService来进行通信,然而题目要求其他应用程序也要能使用该服务,所以这里引入一个新东西(反正书上没写)AIDL接口。

3 AIDL 接口

AIDL是Android Interface Definition Language的缩写,即Android接口定义语言。它是Android的进程间通信比较常用的一种方式。

通过使用AIDL接口可以轻松实现跨进程通信(IPC - Inter Process Communication),也就是说可以用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。

4 如何使用

4.1 新建AIDL文件

  1. 在包中,new—>AIDL—>AIDL file。

无痛的使用BindService,从进程内通信改成允许进程间通信_第1张图片

  1. 声明想要远程调用的接口

无痛的使用BindService,从进程内通信改成允许进程间通信_第2张图片

3. 下一步是关键,点击 Build–>Rebuild Project,从而将接口文件自动生成为java文件

无痛的使用BindService,从进程内通信改成允许进程间通信_第3张图片

4.2 写Service文件(这一步与本地Service有点不同)

  1. 声明并实现一个IBinder对象(这里与一般的bindService不同),这里就是实例化你刚刚定义的接口

    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. 绑定你的接口

        @Override
        public IBinder onBind(Intent intent) {
           
    //        return new MyBinder();
            return mBinder;
        }
    
  3. 写具体的业务

    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.3 在Manifests中声明你的服务

<service
    android:name=".service.QueryWeekday"
    android:process=":remote"
    android:exported="true"
    android:enabled="true">
service>

4.4 新建一个App,用于验证

  1. 将AIDL接口文件放在新的App中,注意要先创建一个与原来AIDL接口所在的接口一样包名的包。

无痛的使用BindService,从进程内通信改成允许进程间通信_第4张图片

  1. 然后build—>rebuild project,生成对应的java文件

  2. 在Acitivity中调用服务,即new一个ServiceConnection对象(这里是new的是接口对象),然后在onStart中调用服务,注意这里需要setComponent,具体看代码和注释

    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) {
           
    
        }
    };
    
    @Override
    protected void onStart() {
           
        super.onStart();
        Intent serviceIntent = new Intent();
        //这里的包名是原来服务所在的包的包名,cls是你在manifests文件中定义的服务的name
        serviceIntent.setComponent(new ComponentName("com.young.project02","com.young.project02.service.QueryWeekday"));
        bindService(serviceIntent,conn, BIND_AUTO_CREATE);
        boolean result = bindService(serviceIntent,conn, Context.BIND_AUTO_CREATE);
        Log.i("result",result+"" );
    }
    

    然后就是你的业务逻辑了,这里因人而异了

    @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();
            String weekday = null;
            try {
           
                weekday = queryWeekday.remoteGetWeekday(date);
            } catch (RemoteException e) {
           
                e.printStackTrace();
            }
            Toast.makeText(this,weekday,Toast.LENGTH_LONG).show();
        });
    }
    

5 效果

从结果可以看到跨APP可以调用服务

无痛的使用BindService,从进程内通信改成允许进程间通信_第5张图片

6 源代码

https://github.com/GoatYoung/issue10A 给颗小星星⭐可否? 嘿嘿

你可能感兴趣的:(java,android)