AIDL使用1 – 简单通信

AIDL使用1 – 简单通信

终于又有活儿干了。
监控网速。可以提供给其他app。涉及到IPC,bound service不再适用。这里就用上了AIDL。
AIDL简介详见官方文档:http://developer.android.com/intl/zh-cn/guide/components/aidl.html
这里主要简单介绍一下基本用法(复杂的用法留到下篇再讲):


服务端创建AIDL:

package com.meizu.flyme.tv.bandwithmonitor;

// Declare any non-default types here with import statements

// 有参数的情况会略有不同,这个下篇再讲
interface IMonitorService {
    long getBandwidth();   // 返回带宽。单位KB/s。下同
    long getRealTimeSpeed();  // 返回实时网速
}

可以看到,AS为我们自动生成了一些类:
自动生成的类

生成的类中,最重要的是IMonitorService.Stub。在服务端,我们要重载这个类,需要重载的方法和对应aidl文件中声明的方法一样,如下:

private IMonitorService.Stub mStub = new IMonitorService.Stub() {
        @Override
        public long getBandwidth() throws RemoteException {
            return 0;
        }

        @Override
        public long getRealTimeSpeed() throws RemoteException {
            return 0;
        }
    };

都对应Stub中重载的方法完全和aidl中声明的一样。这样,我们便能控制返回给客户端的结果。


下面看看客户端需要做些什么:
1.将服务端中的aidl文件拷贝到客户端的工程中。对于这个例子,则是把PROJECT_PATH/app/src/main/aidl/com/robert/bandwidthmonitor中的com/robert/bandwidthmonitor/IMonitorService.aidl拷贝了到CLIENT_ROOT_PATH/app/src/main/aidl下。
2.和通常的绑定服务一样,不过在SerivceConnection.onServiceConnected中调用IMonitorService.Stub.asInterface(Binder)得到Service。如下:

    private IMonitorService mService;
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            KLog.e();
            mService =  IMonitorService.Stub.asInterface(iBinder);

            setupTimer();
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
        }
    };

下面是具体代码:

服务端

下面看一下服务端(接受请求的一端)是怎么实现逻辑的(忽略监听网络的逻辑):

package com.robert.bandwidthmonitor.service;

public class MonitorService extends Service {
    private static final int SAMPLE_PERIOD_TIME = 1000;
    private static final int DOWNLOAD_TEST_TIME = 15000; // 15s

    private long mBandwidth = 0;
    private long mCurrentSpeed = 0;

    private Timer mTimer;
    private long mLastRecv = 0;

    // 最重要的是这个Stub
    private IMonitorService.Stub mStub = new IMonitorService.Stub() {
        @Override
        public long getBandwidth() throws RemoteException {
            return mBandwidth;
        }

        @Override
        public long getRealTimeSpeed() throws RemoteException {
            return mCurrentSpeed;
        }
    };

    public static Intent newIntent(Context context) {
        return new Intent(context, MonitorService.class);
    }

    @Override
    public IBinder onBind(Intent intent) {
        KLog.e();
        return mStub;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        KLog.e();

        mTimer = new Timer("MonitorTimer");
        mTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                calculateRealTimeSpeed();
            }
        }, 1000, SAMPLE_PERIOD_TIME);     // sample frequency: 1s

        initBandwidth();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        KLog.d();
        if (mTimer != null) {
            mTimer.cancel();
        }
    }

    private void initBandwidth() {
        startTestTask();
    }



    private void startTestTask() {
        KLog.e();
        new StatCollectTask().execute("https://qd.myapp.com/myapp/qqteam/AndroidQQ/mobileqq_android.apk");  // 下载qq apk
    }

    private void calculateRealTimeSpeed() {
        long cur = TrafficStats.getTotalRxBytes();
        mCurrentSpeed = (cur - mLastRecv) / SAMPLE_PERIOD_TIME;
        mLastRecv = cur;
    }


    private class StatCollectTask extends AsyncTask<String, Void, Long> {
        private String urlString;

        @Override
        protected Long doInBackground(String... strings) {
            urlString = strings[0];

            Timer timer = new Timer("FinishTaskTimer");
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    StatCollectTask.this.cancel(true);
                }
            }, DOWNLOAD_TEST_TIME);

            try {
                URL url = new URL(urlString);
                long start = System.currentTimeMillis();
                int tot = 0;
                while (isCancelled() == false) {
                    tot += readBytes(url);
                }
                long end = System.currentTimeMillis();
                KLog.d("read bytes: " + tot / 1024);
                return tot / ((end - start) / 1000);
            } catch (MalformedURLException e) {
                KLog.e();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                timer.cancel();
            }
            return null;
        }

        @Override
        protected void onCancelled(Long aLong) {
            processResult(aLong);
        }

        @Override
        protected void onPostExecute(Long aLong) {
            processResult(aLong);
        }

        // on ui thread
        private void processResult(Long aLong) {
            if (aLong != null) {
                mBandwidth = aLong / 1024;
                KLog.e("finish download test. result: " + mBandwidth + " KB/s");
            }
        }

        private int readBytes(URL url) throws IOException {
            KLog.e("execute downloading: " + url);
            URLConnection conn = url.openConnection();
            conn.setUseCaches(false);
            InputStream in = conn.getInputStream();
            int cnt = 0;
            try {
                int bytesRead = 0;
                byte[] buffer = new byte[1024 * 1024];     // 1MB
                while ((bytesRead = in.read(buffer)) != -1) {
                    cnt += bytesRead;
                    if (isCancelled()) {
                        break;
                    }
                }
            } finally {
                in.close();
            }
            return cnt;
        }
    }
}

AndroidManifest.xml

<manifest package="com.robert.bandwidthmonitor"
          xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">



        <service
            android:name=".service.MonitorService"
            android:enabled="true"
            android:exported="true"
            android:process=":remote">
            <intent-filter>
                <action android:name="com.robert.bandwidthmonitor.service.IMonitorService"/>
            </intent-filter>
        </service>

    </application>

</manifest>

注意service的android:process属性。(:remote为BandwidthMonitor创建了一个私有进程,如果没有冒号,则代表创建一个全局的进程,名字就是remote。名字应该避免冲突。)


客户端代码:

public class AIDLActivity extends AppCompatActivity {
    private TextView mBandwidth;
    private TextView mSpeed;
    private Timer mTimer;
    private IMonitorService mService;
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            KLog.e();
            mService =  IMonitorService.Stub.asInterface(iBinder);

            setupTimer();
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
        }
    };

    private void setupTimer() {
        mTimer = new Timer("speed");
        mTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    final long speed = mService.getRealTimeSpeed();
                    final long max = mService.getBandwidth();
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            mSpeed.setText("speed: " + speed + "KB/s");
                            mBandwidth.setText("bandwidth: " + max + "KB/s");
                        }
                    });
                } catch (DeadObjectException e) {
                  e.printStackTrace();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }, 1000, 1000);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_aidl);

        KLog.e();

        mBandwidth = (TextView) findViewById(R.id.bandwidth);
        mSpeed = (TextView) findViewById(R.id.speed);


//        Intent intent = new Intent(this, MonitorService.class);
        Intent intent = new Intent("com.meizu.flyme.tv.bandwidth.service.IMonitorService");
        intent.setPackage("com.robert.bandwithmonitor");  // 必须设置
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        KLog.e();

        if (mTimer != null) {
            mTimer.cancel();
        }
        unbindService(mConnection);
    }
}

intent必须设置package,intent必须为显示的(explicit),否则会报错。(在官方看到过,不过找不到了。)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AIDLAndroid Interface Definition Language)是一种用于 Android 平台的接口定义语言,它可以帮助不同进程之间的组件进行通信。下面是使用 AIDL 进行进程间通信的步骤: 1.定义 AIDL 接口 首先,在服务端和客户端之间定义一个 AIDL 接口。在 AIDL 文件中,定义需要向客户端公开的方法和参数。 2.实现 AIDL 接口 在服务端中,实现定义的 AIDL 接口,并在 onCreate() 方法中将其注册到系统中。 3.绑定服务端 在客户端中,使用 bindService() 方法绑定服务端。 4.获取 AIDL 接口实例 在客户端中,实现 ServiceConnection 接口,当服务端连接成功时,会回调 onServiceConnected() 方法。在此方法中,可以获取到 AIDL 接口实例。 5.调用 AIDL 接口方法 在客户端中,通过获取到的 AIDL 接口实例,即可调用服务端暴露的方法。 下面是一个简单的示例代码: 服务端: ``` //定义 AIDL 接口 interface IMyAidlInterface { int add(int a, int b); } //实现 AIDL 接口 class MyAidlInterfaceImpl extends IMyAidlInterface.Stub { @Override public int add(int a, int b) throws RemoteException { return a + b; } } //在 onCreate() 方法中注册 AIDL 接口 @Override public void onCreate() { super.onCreate(); Intent intent = new Intent(this, MyAidlInterfaceService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); Log.i(TAG, "MyAidlInterfaceService is created."); } //定义 ServiceConnection 对象,以便在客户端连接时获取 AIDL 接口实例 private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mIMyAidlInterface = IMyAidlInterface.Stub.asInterface(service); Log.i(TAG, "MyAidlInterfaceService is connected."); } @Override public void onServiceDisconnected(ComponentName name) { mIMyAidlInterface = null; Log.i(TAG, "MyAidlInterfaceService is disconnected."); } }; ``` 客户端: ``` //定义 ServiceConnection 对象 private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //获取 AIDL 接口实例 mIMyAidlInterface = IMyAidlInterface.Stub.asInterface(service); Log.i(TAG, "MyAidlInterfaceService is connected."); } @Override public void onServiceDisconnected(ComponentName name) { mIMyAidlInterface = null; Log.i(TAG, "MyAidlInterfaceService is disconnected."); } }; //使用 bindService() 方法绑定服务端 Intent intent = new Intent(); intent.setComponent(new ComponentName("com.example.myaidlservice", "com.example.myaidlservice.MyAidlInterfaceService")); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); //调用服务端暴露的方法 int result = mIMyAidlInterface.add(1, 2); ``` 希望这个简单的示例可以帮助你了解如何使用 AIDL 进行进程间通信

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值