概述

  在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开发笔记之 Activity四种加载模式
  2. 通过广播Intent控制Android系统自带的音
  3. android 如何彻底关闭应用
  4. Android 数据库SQLite的使用简单Demo
  5. Android桌面小部件AppWidget(1)
  6. Android培训班(3)
  7. Android的启动过程分析(从进程和Framewor
  8. Android 中自定义属性(attr.xml,TypedArr
  9. Android中LocationManager的简单使用,获
  10. android looper介绍