概述

  在Android学习之Service(上)中学习了Service的基本使用方式,接下来需要研究一下使用Service实现跨进程通信的功能。

配置远程Service

  要实现Service的跨进程通信就需要提到远程Service。远程Service和普通的Service注册方式是一样的,只不过是在注册时,设定android:process属性为:remote,这个“:remote”并不是固定这样写的可以随意写,例如,包名是com.servicedemo那么,不设定”:remote”的时候,默认的进程名称为com.servicedemo,当设置该属性后,就变成了com.servicedemo:remote
  除此之外,还需要添加一个action属性,记得在Android学习之Service(上) 中我的启动服务是这样写的final Intent intent = new Intent(this, StartService.class);其中StartService就是我的自定义服务类,那么,如果是其他应用程序的话,其他程序中是不可能存在StartService这个类的,所以就要使用action属性,用Intent的隐式调用,具体代码如下:

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.servicedemo">    <application>    .............        <service android:name=".service.StartService"                        android:process=":remote" >            <intent-filter>                <action android:name="com.servicedemo.CalculateService"/>            intent-filter>        service>    application>manifest>

编写AIDL

  解决了配置文件后,又看到一个新的东西,AIDL(Android接口定义语言),它实现了让Activity与一个远程Service建立关联,这里需要定一个.aidl文件由于我用的是Android Studio开发工具,作为新手着实费了一番周折,下面做一个记录。

  首先,.aidl文件是单独放在aidl文件夹下,当新建一个.aidl的文件的时候就会自动生成这样一个文件夹,既然是自动的就直在app上新建一个AIDL就好了方法是,选中app->右键->New->AIDL->AIDL File 然后输入名字即可这里是ADLIService.aidl,如下图:
  
         

  这里基本没什么问题,.aidl文件的内容如下:

// ADLIService.aidlpackage com.servicedemo;interface ADLIService {     int addCalculate(int a, int b);     int factorialCalculate(int num);}

  这就是一个接口,里边添加了两个需要子类去实现的方法,分别用来在服务启动的时候进行加法计算和阶乘运算。这一步完成后使用Eclipse就会直接生成一个与.aidl名字一样的.java文件,但是,使用Android Studio就是自动的,我起初以为是目录结构不一样,生成以后我又不知道,然后强行使用,发现没有这个类,次法行不通。百度后发现Android Studio需要Build->ReBuild Project一下就好了,但是,并不是直接可见的,需要改变一下目录结构,如下:

                 

使用AIDL

  维护好这些后就可以在自定义的Service中使用这个接口了,这里还是用上一篇代码中的例子工程,代码如下:

package com.servicedemo.service;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import com.servicedemo.ADLIService;public class StartService extends Service {    ADLIService.Stub mBinder = new ADLIService.Stub() {        @Override        public int addCalculate(int a, int b) throws RemoteException {            return a + b;        }        @Override        public int factorialCalculate(int num) throws RemoteException {            int result = 1;            do {                result *= num;            } while (num-- > 1);            return result;        }    };    @Override    public IBinder onBind(Intent intent) {        return mBinder;    }}

  将上个例子中没有用的代码去掉,留下有用的部分,首先是创建一个提供给obBind()返回的对象,这个对象就是刚刚定义的AIDL接口,这个对象是通过new ADLIService.Stub()得到的,而Stub是IBinder的子类。在创建对象的同时就可以像上边的代码中一样,实现那两个接口中的方法。

使用AIDL

  现在要实现的是跨进程通信,所以,首先是要有两个程序不是。这里先不急,先看看这个服务运行起来是什么样的,代码基本和之前的代码基本一样,就修改了ServiceConnection对象是重写的方法,如下所示:

    package com.servicedemo.activity;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.IBinder;import android.os.RemoteException;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import com.servicedemo.ADLIService;import com.servicedemo.R;import com.servicedemo.service.StartService;public class MainActivity extends AppCompatActivity {    private Button mStart, mStop, mBind, mUnBind;    // 改变一:自定义的AIDL接口对象    private ADLIService mADLIService;    private ServiceConnection connection = new ServiceConnection() {        /**         * 与Service断开连接后调用         */        @Override        public void onServiceDisconnected(ComponentName name) {        }        /**         * 与Service连接后调用         */        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            // 改变二:// 得到自定义的AIDL接口对象            mADLIService = ADLIService.Stub.asInterface(service);            try {                // 使用服务的方法                int result = mADLIService.addCalculate(10, 10);                Log.d("Service_remote", "add = " + result);                result = mADLIService.factorialCalculate(5);                Log.d("Service_remote", "factorial = " + result);            } catch (RemoteException e) {                e.printStackTrace();            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initUI();    }    private void initUI() {        mBind = (Button) findViewById(R.id.btn_bind_service);        final Intent intent = new Intent(this, StartService.class);        mBind.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                bindService(intent, connection, BIND_AUTO_CREATE);            }        });    }}

与之前的代码比去掉了一些用不到的按钮事件只看绑定Service事件。当点击”绑定Service”的时候就会将计算结果传回来,计算过程就是在之前Service中实现的,效果如下:

             

  知道了Service的正常使用和运行效果,再看看跨进程的效果,首先,在创建一个工程ServiceClient,然后,将先前工程中的aidl文件夹整个拷贝到ServiceClient工程下与java文件夹同级即可(可以直接到目录里复制和粘贴),如下所示:
       

  然后,到ServiceClient工程,ReBuild一下。至此已完成多半,剩下的就是给界面添加按钮,然后,设置点击事件,代码如下:

package com.serviceclient;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.IBinder;import android.os.RemoteException;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import com.servicedemo.ADLIService;public class MainActivity extends AppCompatActivity {    private Button mBind;    private ADLIService mADLIService;    // 与之前一样创建ServiceConnection对象,并称写两个监听方法    private ServiceConnection connection = new ServiceConnection() {        /**         * 与Service断开连接后调用         */        @Override        public void onServiceDisconnected(ComponentName name) {        }        /**         * 与Service连接后调用         */        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            mADLIService = ADLIService.Stub.asInterface(service);            try {                int result = mADLIService.addCalculate(30, 10);                Log.d("Service_remote", "add = " + result);                result = mADLIService.factorialCalculate(10);                Log.d("Service_remote", "factorial = " + result);            } catch (RemoteException e) {                e.printStackTrace();            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initUI();    }    private void initUI() {        mBind = (Button) findViewById(R.id.btn_bind_service);        // 注意,要与启动的Service的action属性一致        final Intent intent = new Intent("com.servicedemo.CalculateService");        mBind.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                bindService(intent, connection, BIND_AUTO_CREATE);            }        });    }}

  与之前项目中MainActivity.java是一模一样的代码,所不同是Intent在创建的时候传递的是action属性的值,这种方式属于隐性调用,其他的代码没有区别。实验效果,就是通过点击新创建app的按钮,去启动之前项目中的服务,将参数拿到远端Service去计算,得到一个计算结果,然后打印。
  注意final Intent intent = new Intent("com.servicedemo.CalculateService");这种写法只是用于5.0以前,5.0以后就不能这样隐性调用了,要改成如下代码:

private void initUI() {        mBind = (Button) findViewById(R.id.btn_bind_service);        final Intent intent = new Intent();        // 还是设定action        intent.setAction("com.servicedemo.CalculateService");        // 这里要明确设定要启动的服务的包名(程序名)        intent.setPackage("com.servicedemo");        mBind.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                bindService(intent, connection, BIND_AUTO_CREATE);            }        });    }

这样就可以实现远程启动服务了,至此,Service的学习就结束了,最终效果如下:

   
  
  上面的代码传递就是Java的基础类型,例如,传个整型做加减乘除什么的,远程服务所传递的参数基本也就是这些还有Map和List什么的,如果想传递一些自定义类型,这就必须要让这个类去实现Parcelable接口,并且要给这个类也定义一个同名的AIDL文件,我的理解就是将自动生成的那个.java文件改成手写的,这个类实现Parcelable接口接口以了,我大概创建了一下,还是挺复杂的(功力不足),回头用的时候再说吧!
           以上是关于Service学习和理解!

更多相关文章

  1. Android(安卓)自定义View - 启航 一般View定义
  2. Android(安卓)更新UI的两种方法——handler和runOnUiThread() -
  3. Android(安卓)APP之间共享SharedPreference
  4. Android(安卓)SDK更新后 ADT R17 E/AndroidRuntime : java.lang.
  5. Android(安卓)JNI 实例
  6. 下载android sdk更新包离线安装解决方案
  7. Android使用Aidl实现跨进程通信
  8. Android性能测试工具(一)之Emmagee
  9. Android(安卓)Native层开发Camera应用的方法

随机推荐

  1. android相机调试
  2. Gradle-jar-aar
  3. android中ColorStateList及StateListDraw
  4. Android进阶之代码应用技巧
  5. Android(安卓)GPS架构分析
  6. 4种必须知道的Android屏幕自适应解决方案
  7. Android(安卓)TextView字体颜色等样式详
  8. Android(安卓)Sqlite Failed to open dat
  9. 做android 开发遇到的问题及解决办法记录
  10. Android(安卓)主动获取电量的方法