您的位置:首页 > 博客中心 > APP开发 >

Android进程间通信详细介绍

时间:2022-03-13 19:53

1、为什么需要多个进程?

默认情况下,一个Android应用中所有的组件都会运行在以包名为进程名的单个进程中,但是由于Android自身平台的一些限制或者多进程固有的一些好处,导致很多应用在实现的时候不得不选择多进程的实现方式:

1.1. Android系统对每一个应用进程的内存占用有限制,视具体设备的情况,我的测试机的单个应用的内存限制为128M,比较大了,早期的Android设备由于总的内存大小限制,对单个应用的内存限制的比较小24M或者更小。所以如果应用需要占用很大的内存,可以考虑将一些组件单独运行在独立的进程中,减小OOM和被系统kill的概率。

1.2. 由于每一个进程都是运行在独立的虚拟机中,所以子进程的崩溃不会影响到其它的进程

1.3. 主进程退出后,子进程仍然可以运行,对voip和推送服务类的应用,可以说是必备的

1.4. 还有一些另类的应用用多个进程之间相互监听,防止自己的服务被系统杀死,保证被杀死或者崩溃后能拉起服务

2、android多进程实现方式

说了多进程的那么多好处,在Android中如何实现呢?可通过两种设置process属性的方式实现多进程:

2.1. android:process=”:process_one”

实际的进程名是包名:process_one,这种形式表示该进程为当前应用的私有进程,其它应用的组件不可以和它跑在同一个进程中

2.2. android:process=”com.study.androidprocess.process_one”

其它应用可以通过设置相同SharedUID且签名完全一致,可以和它跑在同一个进程

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.study.androidprocess">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"
            android:process=":process_one">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity android:name=".ProcessOneActivity"
            android:process=":process_two">
        </activity>
    </application>

</manifest>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

Android 查看进程命令 adb shell —> 利用(ps|grep 条目名称)命令,过滤自己需要的进程,比如列出条目里含有tencent字符的进程(包名里面含有该字符),则输入ps|grep tencent

运行结果

root@generic_x86:/ # ps|grep com.study.androidprocess
u0_a74    11614 1290  1265280 27464 SyS_epoll_ b7344c35 S com.study.androidprocess
u0_a74    11690 1290  1274828 40500 SyS_epoll_ b7344c35 S com.study.androidprocess:process_one
u0_a74    11949 1290  1277692 40224 SyS_epoll_ b7344c35 S com.study.androidprocess:process_two
  • 1
  • 2
  • 3
  • 4
  • 5

2.3. Application也可以设置android:process属性,来修改所有组件运行进程的名称

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.study.androidprocess">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:process=":process_app">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity android:name=".ProcessOneActivity">
        </activity>
    </application>

</manifest>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

运行结果:用第一种方式指定的进程的进程名称依然是包名:process_app

root@generic_x86:/ # ps|grep com.study.androidprocess
u0_a74    18188 1290  1282900 41848 SyS_epoll_ b7344c35 S com.study.androidprocess:process_app
  • 1
  • 2
  • 3

3.进程间通信

3.1 Intent

Intent进行数据的传递是我们平时最常用的,他的原理其实是对于Binder的封装,但是他只能做到单向的数据传递,所以并不能很好的实现跨进程通信,我们这里就不展开来介绍了

3.2 Messager

Messager的底层也是基于Binder的,其实应该说他是在AIDL的基础上封装了一层。

基于消息的进程间通信方式:

在客户端发送一个Message给服务端,在服务端的handler中会接收到客户端的消息,然后进行对应的处理,处理完成后,再将结果等数据封装成Message,发送给客户端,客户端的handler中会接收到处理的结果

一般来说安卓中使用Binder主要是通过绑定服务(bindService),服务端(这里指的不是后台,是指其中一个进程)主要是运行Service,客户端通过bindService获取到相关的Binder,Binder就作为桥梁进行跨进程的通信.

这里我们先演示同一个应用内的多进程通信

3.2.1 服务器端

首先我们先创建一个Service,

public class MyService extends Service{

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

并在清单文件中配置他的进程

<service
            android:name=".messager.MyService"
            android:process=":process_one">

        </service>
  • 1
  • 2
  • 3
  • 4
  • 5

在Service里面创建一个Hander用来接受消息

private final static Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
       Log.d(TAG, "handleMessage: 服务端接到消息");

    }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在Service里面创建一个Messager,并把Handler放入其中

private final static Messenger mMessenger = new Messenger(mHandler);
  • 1

重写onbind方法,返回Messager里面的Binder

public IBinder onBind(Intent intent) {
    return mMessenger.getBinder();
}
  • 1
  • 2
  • 3

3.2.2 客户端

创建一个对象实现ServiceConnection

private ServiceConnection mMyServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            isConnected = true;
            mServiceMessenger = new Messenger(service);
            Toast.makeText(MainActivity.this, "isConnect", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            isConnected = false;
            Toast.makeText(MainActivity.this, "unConnect", Toast.LENGTH_SHORT).show();
        }
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

绑定服务

        Intent intent = new Intent(MainActivity.this, MyService.class);
        bindService(intent, mMyServiceConnection, BIND_AUTO_CREATE);
  • 1
  • 2

绑定服务后,会调用ServiceConnection的onServiceConnected方法,通过Messager发送消息,服务器端的Handler就能够收到消息了

Message msgFromClient = Message.obtain();
        msgFromClient.replyTo = mMessenger;
        if (isConnected) {
            //往服务端发送消息
            try {
                mServiceMessenger.send(msgFromClient);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

这样的话我们就能够通过bindService获取到一个包含Binder的Messager进行通信了,但是我们目前只实现了客户端对服务器端传递消息,那么服务器端如何对客户端传递消息呢?

我们先对服务器端的代码进行修改,首先修改Service的Handler

(关键代码是 Messenger messenger = msg.replyTo)

 private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {

            Log.d(TAG, "handleMessage: 服务端接到消息");
            //获取Messager
            Messenger messenger = msg.replyTo;
            //创建消息
            Message msg_reply = Message.obtain();
            try {

                Thread.sleep(2000);
                //发送
                messenger.send(msg_reply);

            } catch (RemoteException | InterruptedException e) {
                e.printStackTrace();
            }
        }

    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

接着我们在客户端也增加一个Handler和Messager来处理消息

private Messenger mMessenger = new Messenger(new Handler() {
        @Override
        public void handleMessage(Message msgFromServer) {
            super.handleMessage(msgFromServer);
            Log.d(TAG, "handleMessage: 客户端接到消息了");

        }
    });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这样一来,服务器端和客户端就能很好的实现跨进程通信了.

如果需要传送数据的话,可以通过Bundle设置数据,除了基本数据类型,还可以通过消息传送可序列化的对象

发送方:

    Message msg = Message.obtain();

    Bundle bundle = new Bundle();

    //传输序列化对象
    //bundle.putParcelable();

    //bundle.putSerializable();

    msg.setData(bundle);

接收方:

    Bundle data = msg.getData();

    //获取数据
    //data.getSerializable()

    //data.getParcelable()

注意:

Messenger中进行数据传递必须将数据放入Message中,而Messenger与Message都实现了Parcelable接口,因此可以跨进程传输。 
Message只能使用what,arg1,arg2,Bundle,replyto传递信息,Message中object字段仅支持系统提供的实现了Parcelable接口的对象传递信息,我们自己定义Parcelable对象不能进行传输。

举个例子,传递String类型:(其他类型类似,如:Book 实现Parcelable接口即可)

客户端代码:

/**
 * 发送String字符串
 *
 * @param view
 */
public void sendStringMessage(View view) {
    if (isConnected) {
        Message message = Message.obtain();
        message.what = 0x002;
        Bundle bundle = new Bundle();
        bundle.putString("client", "client 发送的消息");
        message.setData(bundle);
        message.replyTo = mClientMessenger;
        try {
            mServiceMessenger.send(message);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

服务端代码

                case 0x002:

                //获取Messager
                Messenger messenger2 = msg.replyTo;
                //创建消息
                Message msg_reply2 = Message.obtain();
                Bundle data = msg.getData();
                String client = data.getString("client");
                Log.d(TAG, "handleMessage: 服务端接到消息 --->0x002" + client);
                msg_reply2.what = 0x002;
                Bundle bundle = new Bundle();
                bundle.putString("server", "server 发送消息");
                msg_reply2.setData(bundle);
                try {
                    Thread.sleep(2000);
                    //发送
                    messenger2.send(msg_reply2);

                } catch (RemoteException | InterruptedException e) {
                    e.printStackTrace();
                }
                break;

打印log为:

服务端
04-07 10:16:38.642 4118-4118/com.wz.ipcdemo:process_messenger D/MessengerServer: handleMessage: 服务端接到消息 --->0x002client 发送的消息

客户端
04-07 10:16:40.642 3960-3960/com.wz.ipcdemo D/MessengerClient: handleMessage: 客户端接到消息了 ---> 0x002server 发送消息

注意: 
测试了下,及时Book实现序列化接口,也不行,有待研究!!!

3.2.3 弊端

上面我们已经实现了跨进程通信,但是这里面其实是有弊端的,服务端处理客户端的消息是串行的,必须一个一个来处理,所以如果是并发量比较大的时候,通过Messager来通信就不太适合了

3.3 AIDL

aidl是 Android Interface definition 
language的缩写,一看就明白,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口

ipc:interprocess communication :内部进程通信

3.3.1 支持传递的数据类型

  • 1.基本数据类型
  • 2.实现了Parcelable接口的对象
  • 3.List:只支持ArrayList,并且里面的元素需要时AIDL支持的
  • 4.Map:只支持HashMap,并且里面的key和value都需要是被AIDL支持的

注意:这里有一个定向tag的问题,下面会提及

AIDL中的定向 tag 表示了在跨进程通信中数据的流向,其中 in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。其中,数据流向是针对在客户端中的那个传入方法的对象而言的。in 为定向 tag 的话表现为服务端将会接收到一个那个对象的完整数据,但是客户端的那个对象不会因为服务端对传参的修改而发生变动;out 的话表现为服务端将会接收到那个对象的的空对象,但是在服务端对接收到的空对象有任何修改之后客户端将会同步变动;inout 为定向 tag 的情况下,服务端将会接收到客户端传来对象的完整信息,并且客户端将会同步服务端对该对象的任何变动。

第一种:一个App内跨进程通信

3.3.1 服务端

首先我们创建一个Service

public class AIDLService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

然后在清单文件里面设置Service的进程

        <service
            android:name=".AIDLService"
            android:process=":process_two">
        </service>
  • 1
  • 2
  • 3
  • 4
  • 5

然后右键选择新建AIDL文件,Android Studio就会帮你在你的aidl目录的同名文件夹下面创建一个AIDL文件

技术分享

创建一个接口

// IShop.aidl
package com.study.androidprocess;

// Declare any non-default types here with import statements
//导入所需要使用的非默认支持数据类型的包
import com.study.androidprocess.Book;

interface IShop {
   //所有的返回值前都不需要加任何东西,不管是什么数据类型
       List<Book> getBooks();

       //传参时除了Java基本类型以及String,CharSequence之外的类型
       //都需要在前面加上定向tag,具体加什么量需而定
       void addBook(in Book book);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

同时还有一个对应实体类的一个.aidl文件

// Book.aidl
//第一类AIDL文件的例子
//这个文件的作用是引入了一个序列化对象 Book 供其他的AIDL文件使用
//注意:Book.aidl与Book.java的包名应当是一样的
package com.study.androidprocess;

//注意parcelable是小写
parcelable Book;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

最好也把实体类放在aidl包下

public class Book implements Parcelable {
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    private String name;
    private int price;
    public Book(){}

    public Book(Parcel in) {
        name = in.readString();
        price = in.readInt();
    }

    public static final Creator<Book> CREATOR = new Creator<Book>() {
        @Override
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

        @Override
        public Book[] newArray(int size) {
            return new Book[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(price);
    }

    /**
     * 参数是一个Parcel,用它来存储与传输数据
     * @param dest
     */
    public void readFromParcel(Parcel dest) {
        //注意,此处的读值顺序应当是和writeToParcel()方法中一致的
        name = dest.readString();
        price = dest.readInt();
    }

    //方便打印数据
    @Override
    public String toString() {
        return "name : " + name + " , price : " + price;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

AndroidStudio中有自动生成Parcelable的插件

问题1:默认生成的模板类的对象只支持为 in 的定向 tag 。为什么呢?因为默认生成的类里面只有 writeToParcel() 方法,而如果要支持为 out 或者 inout 的定向 tag 的话,还需要实现 readFromParcel() 方法——而这个方法其实并没有在 Parcelable 接口里面,所以需要我们从头写

问题2 Android Studio 是默认使用 Gradle 来构建 Android 项目的,而 Gradle 在构建项目的时候会通过 sourceSets 来配置不同文件的访问路径,从而加快查找速度——问题就出在这里。Gradle 默认是将 java 代码的访问路径设置在 java 包下的,这样一来,如果 java 文件是放在 aidl 包下的话那么理所当然系统是找不到这个 java 文件的。

修改 build.gradle 文件:在 android{} 中间加上下面的内容:

sourceSets {
    main {
        java.srcDirs = [‘src/main/java‘, ‘src/main/aidl‘]
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5

给Service添加Action

<service
            android:name=".aidltest.AIDLService"
            android:process=":process_aidl">

            <intent-filter>
                <action android:name="action.hfs"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </service>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

完整服务端代码

public class AIDLService extends Service {
    public final String TAG = this.getClass().getSimpleName();

    //包含Book对象的list
    private List<Book> mBooks = new ArrayList<>();

    //由AIDL文件生成的BookManager
    private final IShop.Stub mIShop = new IShop.Stub() {
        @Override
        public List<Book> getBooks() throws RemoteException {
            synchronized (this) {
                Log.d(TAG, "invoking getBooks() method , now the list is : " + mBooks.toString());
                if (mBooks != null) {
                    return mBooks;
                }
                return new ArrayList<>();
            }
        }


        @Override
        public void addBook(Book book) throws RemoteException {
            synchronized (this) {
                if (mBooks == null) {
                    mBooks = new ArrayList<>();
                }
                if (book == null) {
                    Log.e(TAG, "Book is null in In");
                    book = new Book();
                }
                //尝试修改book的参数,主要是为了观察其到客户端的反馈
                book.setPrice(2333);
                if (!mBooks.contains(book)) {
                    mBooks.add(book);
                }
                //打印mBooks列表,观察客户端传过来的值
                Log.d(TAG, "invoking addBooks() method , now the list is : " + mBooks.toString());
            }
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        Book book = new Book();
        book.setName("Android");
        book.setPrice(10);
        mBooks.add(book);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mIShop;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

3.3.3 客户端代码

public class AIDLActivity extends AppCompatActivity {
    private static final String TAG = "AIDLActivity";

    //由AIDL文件生成的Java类
    private IShop mIShop = null;

    //标志当前与服务端连接状况的布尔值,false为未连接,true为连接中
    private boolean mIsConnected = false;

    //包含Book对象的list
    private List<Book> mBooks;

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

    /**
     * 按钮的点击事件,点击之后调用服务端的addBookIn方法
     *
     * @param view
     */
    public void addBook(View view) {
        //如果与服务端的连接处于未连接状态,则尝试连接
        if (!mIsConnected) {
            attemptToBindService();
            Toast.makeText(this, "当前与服务端处于未连接状态,正在尝试重连,请稍后再试", Toast.LENGTH_SHORT).show();
            return;
        }
        if (mIShop == null) return;

        Book book = new Book();
        book.setName("APP研发录In");
        book.setPrice(30);
        try {
            mIShop.addBook(book);
            Log.d(TAG, "addBook: " + book.toString());
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    /**
     * 尝试与服务端建立连接
     */
    private void attemptToBindService() {
        Intent intent = new Intent();
        intent.setAction("action.hfs");
        intent.setPackage("com.study.androidprocess");
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (!mIsConnected) {
            attemptToBindService();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mIsConnected) {
            unbindService(mServiceConnection);
            mIsConnected = false;
        }
    }

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(getLocalClassName(), "service connected");
            mIShop = IShop.Stub.asInterface(service);
            mIsConnected = true;

            if (mIShop != null) {
                try {
                    mBooks = mIShop.getBooks();
                    Log.d(TAG, "onServiceConnected: " + mBooks.toString());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(getLocalClassName(), "service disconnected");
            mIsConnected = false;
        }
    };
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94

3.3.4 运行结果

客户端

 D/AIDLActivity: onServiceConnected: [name : Android , price : 10]
 D/AIDLActivity: addBook: name : APP研发录In , price : 30
  • 1
  • 2

服务端

D/AIDLService: invoking getBooks() method , now the list is : [name : Android , price : 10]
D/AIDLService: invoking addBooks() method , now the list is : [name : Android , price : 10, name : APP研发录In , price : 2333]
  • 1
  • 2

第二种:两个App跨进程通信

服务端代码不用改

把之前写的整个aidl包拷贝到另一个项目中

注意:包名不要改变

技术分享

在build.gradle中添加代码

sourceSets {
        main {
            java.srcDirs = [‘src/main/java‘, ‘src/main/aidl‘]
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5

编写客户端代码,把之前的客户端代码拿过来用即可

这里为了区分,添加书的名字换了下,方便测试

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    //由AIDL文件生成的Java类
    private IShop mIShop = null;

    //标志当前与服务端连接状况的布尔值,false为未连接,true为连接中
    private boolean mIsConnected = false;

    //包含Book对象的list
    private List<Book> mBooks;

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

    /**
     * 按钮的点击事件,点击之后调用服务端的addBookIn方法
     *
     * @param view
     */
    public void addBook(View view) {
        //如果与服务端的连接处于未连接状态,则尝试连接
        if (!mIsConnected) {
            attemptToBindService();
            Toast.makeText(this, "当前与服务端处于未连接状态,正在尝试重连,请稍后再试", Toast.LENGTH_SHORT).show();
            return;
        }
        if (mIShop == null) return;

        Book book = new Book();
        book.setName("另外一个App");
        book.setPrice(666);
        try {
            mIShop.addBook(book);
            Log.d(TAG, "addBook: " + book.toString());
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    /**
     * 尝试与服务端建立连接
     */
    private void attemptToBindService() {
        Intent intent = new Intent();
        intent.setAction("action.hfs");
        intent.setPackage("com.study.androidprocess");
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (!mIsConnected) {
            attemptToBindService();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mIsConnected) {
            unbindService(mServiceConnection);
            mIsConnected = false;
        }
    }

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(getLocalClassName(), "service connected");
            mIShop = IShop.Stub.asInterface(service);
            mIsConnected = true;

            if (mIShop != null) {
                try {
                    mBooks = mIShop.getBooks();
                    Log.d(TAG, "onServiceConnected: " + mBooks.toString());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(getLocalClassName(), "service disconnected");
            mIsConnected = false;
        }
    };
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94

运行结果: 
客户端:


com.study.useaidldemo D/MainActivity: onServiceConnected: [name : Android , price : 10]
com.study.useaidldemo D/MainActivity: addBook: name : 另外一个App , price : 666
  • 1
  • 2
  • 3
  • 4

服务端:

03-30 03:22:49.532 3718-3752/com.study.androidprocess:process_aidl D/AIDLService: invoking getBooks() method , now the list is : [name : Android , price : 10]
03-30 03:22:59.193 3718-3733/com.study.androidprocess:process_aidl D/AIDLService: invoking addBooks() method , now the list is : [name : Android , price : 10, name : 另外一个App , price : 2333]
  • 1
  • 2
  • 3

 

相关推荐

电脑软件

本类排行

今日推荐

热门手游