• Android-bindService远程服务(Aidl)-初步


    之前上一篇讲解到本地服务,本地服务只能在自身APP中Activity访问Service,调用Service里面到方法等操作

    如果想A应用访问B应用里面的方法,属于跨进程调用,如果Android不特供这种跨进程间通讯等API,是不能实现的

    Google Android 为了解决 A应用--->B应用 跨进程访问通讯,提供了一种机制,就是IBInder,这种IBinder机制是Google工程师加入进去的,以前的Linux里是没有这个机制的

    bindService 会返回IBinder接口,IBinder就是Google工程师在为了解决这种跨应用跨进程通讯,IBinder还需要结合Aidl才能实现远程服务(跨进程跨应用通讯)

    注意:⚠️以前本地服务是通过显示意图去绑定,现在远程服务由于无法拿到另外应用的字节码,只能隐士意图去绑定

    Service2,作为服务端,需要把MyService暴露出去

        <!--
            android:process=":remote",代表在应用程序里,当需要该service时,会自动创建新的进程。
            而如果是android:process="remote",没有“:”分号的,则创建全局进程,不同的应用程序共享该进程。
            -->
            <service android:name=".service.MyService"
                     android:exported="true"
                     android:enabled="true"
                     android:process=":remote"> <!-- 允许对外输出 -->
    
                <!-- 想要其他应用程序可以访问我的访问,就必须要对外暴漏 -->
                <intent-filter>
    
                    <action android:name="liudeli.service2.service.MyService" />
    
                </intent-filter>
    
            </service>

    Service2,把逻辑都卸载MyService

    package liudeli.service2.service;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.Binder;
    import android.os.IBinder;
    import android.os.RemoteException;
    
    import liudeli.service2.IMusician;
    import liudeli.service2.service.inter.ISinger;
    
    public class MyService extends Service {
    
        @Override
        public IBinder onBind(Intent intent) {
            // return new MyBinder(); 以前这种方式只适合本地服务(自身APP)
            return new MyBinderAidl();
        }
    
        /**
         * 以前本地服务的方式
         */
        /*class MyBinder extends Binder implements ISinger {
    
            *//**
             * 通过ID查询歌手姓名
             *
             * @param id
             * @return
             *//*
            @Override
            public String querySingerNameByID(int id) {
                String result = null;
                switch (id) {
                    case 1:
                        result = "黄家驹";
                        break;
                    case 2:
                        result = "王杰";
                        break;
                    case 3:
                        result = "陈百强";
                        break;
                    default:
                        result = "张雨生";
                        break;
                }
                return result;
            }
        }*/
    
        /**
         * AIDL的方式,只有这种方式才能完成远程服务
         */
        class MyBinderAidl extends IMusician.Stub {
    
            @Override
            public String querySingerNameByID(int id) throws RemoteException {
                String result = null;
                int result2 = 0;
                switch (id) {
                    case 1:
                        result = "黄家驹";
                        result2 = 210000;
                        break;
                    case 2:
                        result = "王杰";
                        result2 = 180000;
                        break;
                    case 3:
                        result = "陈百强";
                        result2 = 200000;
                        break;
                    default:
                        result = "张雨生";
                        result2 = 200090;
                        break;
                }
                return result;
            }
        }
    }

    Service2,以前本地服务接口的定义:

    package liudeli.service2.service.inter;
    
    import java.lang.String;
    
    public interface ISinger {
    
        /**
         * 通过ID查询歌手姓名
         * @param id
         * @return
         */
        public String querySingerNameByID(int id);
    
    }

    Service2,现在远程服务的AIdl语言接口的定义:

    // IMusician.aidl
    package liudeli.service2;
    
    // Declare any non-default types here with import statements
    
    interface IMusician {
    
        /**
         * 通过ID查询歌手姓名
         * @param id
         * @return
         */
         String querySingerNameByID(int id);
    }

    ----------------------------- 分割线 下面代码是 Service1 访问者相关的了 

     Service1,⚠️要把Service2 aidl 带包一起copy到Service1,保持aidl相关一模一样

    Service1,绑定远程服务相关代码

    package liudeli.service1;
    
    import android.app.Activity;
    import android.content.ComponentName;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.view.View;
    import android.widget.Toast;
    
    import liudeli.service2.IMusician;
    
    public class RemoteActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_remote);
    
            bindServiceAction();
        }
    
        /**
         * Activity初始化的时候绑定服务
         */
        private void bindServiceAction() {
            Intent intent = new Intent();
            intent.setAction("liudeli.service2.service.MyService");
            // android 5.0以后直设置action不能启动相应的服务,需要设置packageName或者Component
            intent.setPackage("liudeli.service2");
            bindService(intent, connection, BIND_AUTO_CREATE);
        }
    
        private IMusician iMusician;
    
        /**
         * 定义服务连接对象,用于连接远程服务
         */
        private ServiceConnection connection = new ServiceConnection() {
            /**
             * 服务连接成功
             * @param name 可以获取到服务到完整信息
             * @param service 服务那边返回到IBinder接口
             */
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                // 这里和本地服务不同,本地服务是强制类型转换,远程服务直接使用代理完成
                iMusician = IMusician.Stub.asInterface(service);
            }
    
            /**
             * 服务断开连接
             * @param name
             */
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
    
        /**
         * 查询远程服务里面的数据
         * @param view
         */
        public void queryRemoteService(View view) {
            if (null == iMusician) {
                Toast.makeText(this, "绑定远程服务失败,无法查询", Toast.LENGTH_LONG).show();
                return;
            }
            try {
                String result = iMusician.querySingerNameByID(1);
                Toast.makeText(this, "查询成功:" + result, Toast.LENGTH_LONG).show();
            } catch (RemoteException e) {
                e.printStackTrace();
                Toast.makeText(this, "远程服务失败 远程异常", Toast.LENGTH_LONG).show();
            }
        }
    
        /**
         * Activity结束时,记得一定要解绑服务,否则会报连接资源异常
         */
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unbindService(connection);
        }
    }

    Layout相关代码:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="queryRemoteService"
            android:text="查询远程服务"
            />
    
    </LinearLayout>

    结果:

  • 相关阅读:
    关于form表单的相同name问题
    MySQL数据库视图
    Blazor
    查看Oracle正在执行的任务
    比较不错的几款开源的WPF Charts报表控件
    Raft算法
    EntityFramework 使用Linq处理内连接(inner join)、外链接(left/right outer join)、多表查询
    systemd、upstart和system V 枯木
    MRTG生成首页报错解决方法 枯木
    dd备份和恢复 枯木
  • 原文地址:https://www.cnblogs.com/android-deli/p/10089355.html
Copyright © 2020-2023  润新知