Service—AIDL跨进程通信

1 介绍

我们都知道在Android系统中,进程之间一般无法直接进行数据交换,因为他们的内存并不是共享的。那么我们在开发一个应用程序时往往需要调用某个其它进程中的service,这时候就需要跨进程间通信。Android提供了一种叫作AIDL(Android Interface Definition Language)的接口语言来解决这种通信问题。这位爷看着唬人,其实很简单,其语法与Java基本一样。但它的特殊之处有:

AIDL定义的接口必须以.aidl结尾
AIDL文件中,除了基本数据类型、String、List、Map、CharSequence外,都需要导入包才能使用。

2 AIDL创建

定义一个AIDL接口,形式如下。可以看到,与Java定义接口简直一毛一样,很是简单。

interface IDog {
    String getColor();
    float getWeight();
}

定义好接口后,ADT工具会自动生成一个IDog.java接口,在该接口里会创建一个Stub内部类,该内部类同时实现了IBinder、ICat两个接口。

3 服务端 Server

我们易银一个这样的场景,有个服务端运行在进程1中,有个客户端运行在进程2中,客户端想访问一下服务端并取点数据出来现实显示。这时就用到我们这个AIDL了。我们说定义好AIDL文件后,会自动生产一个IDog.java类,不用去尝试去看这个类的代码,你会大失所望,没必要看。然后我们指导,这个类有个内部Stub类,在服务端我们需要继承这个类,并实现其内部方法,实现的这个类将会作为远程调用Service的回调类,注意它同时实现了IBinder接口,因此可作为Service的onBind()方法的返回值。
废话少说,来看一下如何实现。

public class MyService extends Service {
    IDog.Stub binder;
    String[] color = new String[] {"赤","橙","红","绿","青"};
    float[] weight = new float[] {12.1f,12.2f,12.3f,12.4f,12.5f};
    Timer timer;
    int rand;
    public class DogBinder extends IDog.Stub {
        @Override
        public String getColor() {
            return color[rand];
        }
        @Override
        public float getWeight()  {
            return weight[rand];
        }
    }
    public MyService() {
    }
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        binder = new DogBinder();
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                rand = (int)(Math.random()*5);
                Log.i("MyService","rand="+rand);
            }
        },0,100);
    }
}

这里用到了Timer,怎么使用我在附录中说明一下。

4 客户端Customer

客户端要想调用到上面的service,需要先将上面所创建的AIDL文件连同它所在目录com/example/server/IDog.aidl一块复制到客户端代码中来。与server端类似,ADT工具会自动生成IDog.java类。那么在客户端又是如何跨进程调用到server的,上代码。

public class MainActivity extends AppCompatActivity {
    Button get;
    TextView show;
    IDog dogBinder;
    //与普通调用service基本相同,也要创建ServiceConnection对象
    ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //重点:需要使用asInterface方法,该方法会新创建一个Binder代理对象
            dogBinder = IDog.Stub.asInterface(service);
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
                dogBinder = null;
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        show = findViewById(R.id.show);
        //还是创建一个Intent
        Intent intent = new Intent();
        intent.setPackage("com.example.server");
        intent.setAction("com.example.server.MY_SERVICE");
        //套路相同,使用bindService方法绑定service
        bindService(intent,conn, Service.BIND_AUTO_CREATE);
        //这里,通过一个按钮点击来控制客户端访问server端
        get = findViewById(R.id.get);
        get.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    //终于要访问server端了,内心有一丝骚动
                    show.setText(dogBinder.getColor()+"  "+dogBinder.getWeight());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

附录

Timer
Timer是一种定时器工具,用来在一个后台线程计划执行指定任务。它可以计划执行一个任务一次或反复多次。
TimerTask一个抽象类,它的实现类代表一个可以被Timer计划的任务。
timer.schedule(new TimerTask(){//我懒了}, 0, 1000);
第一个参数:TimerTask对象,使用者要继承TimerTask类,并实现 public void run() 方法,因为 TimerTask 类实现了 Runnable 接口。
第二个参数:delay,延迟时间,表示调用 schedule() 方法后还需要等待多长时间去执行 run() 方法。
第三个参数:period,周期,表示每隔多长时间调用一次 run() 方法

asInterface()方法
asInterface()方法的作用总结
(1)在客户进程中调用asInterface(),会新创建一个Binder代理对象,代理对象中包含了引用对象。
(2)在服务进程中调用asInterface(),直接返回参数的指针。因为在服务进程中可以直接调用服务类,无须再创建代理对象了。

实例代码
已经调通,运行没有问题,仅供学习使用,勿喷bug
server端

~~~~~~~~~~~~~AndroidManifest.xml~~~~~~~~~~~~~~



    
        
            
                
            
        

        
            
                

                
            
        
    



~~~~~~~~~~~~~MyService.java~~~~~~~~~~~~~~
package com.example.server;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

import java.util.Timer;
import java.util.TimerTask;

public class MyService extends Service {
    IDog.Stub binder;
    String[] color = new String[] {"赤","橙","红","绿","青"};
    float[] weight = new float[] {12.1f,12.2f,12.3f,12.4f,12.5f};
    Timer timer;
    int rand;
    public class DogBinder extends IDog.Stub {
        @Override
        public String getColor() {
            return color[rand];
        }
        @Override
        public float getWeight()  {
            return weight[rand];
        }
    }
    public MyService() {
    }
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        binder = new DogBinder();
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                rand = (int)(Math.random()*5);
                Log.i("MyService","rand="+rand);
            }
        },0,100);
    }
}

~~~~~~~~~~~~~IDog.aidl~~~~~~~~~~~~~~
package com.example.server;

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

interface IDog {
    String getColor();
    float getWeight();
}

~~~~~~~~~~~~~MainActivity.java~~~~~~~~~~~~~~
package com.example.server;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

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

实例代码
customer端

~~~~~~~~~~~~~AndroidManifest.xml~~~~~~~~~~~~~~



    
        
            
                

                
            
        
    




~~~~~~~~~~~~~MainActivity.java~~~~~~~~~~~~~~

package com.example.customer;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Service;
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.Button;
import android.widget.TextView;
import com.example.server.IDog;

public class MainActivity extends AppCompatActivity {
    Button get;
    TextView show;
    IDog dogBinder;
    ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            dogBinder = IDog.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        show = findViewById(R.id.show);
        Intent intent = new Intent();
        intent.setPackage("com.example.server");
        intent.setAction("com.example.server.MY_SERVICE");
        bindService(intent,conn, Service.BIND_AUTO_CREATE);
        get = findViewById(R.id.get);
        get.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    show.setText(dogBinder.getColor()+"  "+dogBinder.getWeight());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });


    }
}

~~~~~~~~~~~~~IDog.aidl~~~~~~~~~~~~~~

// IDog.aidl
package com.example.server;

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

interface IDog {
    String getColor();
    float getWeight();
}

你可能感兴趣的:(Service—AIDL跨进程通信)