Android进程通信的几种方式

原创 2018年04月16日 14:28:46

前言

做应用开发的时候关于Android中的多进程问题其实并不多见,不过面试当中还是会经常问到,这里就对常用的通信方式做一些基本的总结。

Bundle

Android四大组件可以通过Intent进行通信,Intent里的Bundle对象就是用来保存各种通信的数据,不过如果传递的是自定义类型的数据就需要支持序列化,可以是Serializable或者Parcelable两种类型。

// sender进程
Intent intent = new Intent("com.example.bundle.receiver");
intent.putExtra("message", "Bundle Hello world");
startActivity(intent);

// receiver进程
public class BundleReceiverActivity extends AppCompatActivity {
    private TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bundle_receiver);
        textView = findViewById(R.id.text);
        textView.setText(getIntent().getStringExtra("message"));
    }
}

<activity android:name=".BundleReceiverActivity">
    <intent-filter>
        <action android:name="com.example.bundle.receiver" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

当然发送进程的Activity和接收进程的Activity通过隐式跳转来实现通信,开发中使用最多的就是Activity之间的通信,其实这种方法很常见,其他的组件通信方式不再演示。

File

文件作为操作系统提供的功能,可以被多个进程同时访问,所以为了能够保证数据的一致性还需要在多进程访问的时候做加锁同步处理。Java中的FileLock文件锁对象能够保证多进程访问的同步效果,不过需要使用nio的FileChannel来获取FileLock。

// sender进程
File file = new File(Environment.getExternalStorageDirectory(), "readMe.txt");
FileChannel fileChannel = null;
FileLock fileLock = null;
try {
    if (!file.exists()) {
        file.createNewFile();
    }
    RandomAccessFile randomAccessFile = new RandomAccessFile(file.getAbsolutePath(), "rw");
    fileChannel = randomAccessFile.getChannel();
    fileLock = fileChannel.lock();
    ByteBuffer byteBuffer = ByteBuffer.wrap(("File Hello World" + (count += 111)).getBytes());
    fileChannel.write(byteBuffer);
    Toast.makeText(this, "写入" + new String(byteBuffer.array()), Toast.LENGTH_SHORT).show();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    IOUtils.close(fileChannel);
    if (fileLock != null) {
        try {
            fileLock.release();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

发送数据进程通过FileLock独占当前的文件并写入数据,而接收进程则需要获取独占锁之后才能够读取到文件内容。

File file = new File(Environment.getExternalStorageDirectory(), "readMe.txt");
FileChannel fileChannel = null;
FileLock fileLock = null;
if (file.exists()) {
    try {
        RandomAccessFile randomAccessFile = new RandomAccessFile(file.getAbsolutePath(), "rw");
        fileChannel = randomAccessFile.getChannel();
        fileLock = fileChannel.lock();
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        fileChannel.read(byteBuffer);
        Toast.makeText(this, new String(byteBuffer.array()), Toast.LENGTH_SHORT).show();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        IOUtils.close(fileChannel);
        if (fileLock != null) {
            try {
                fileLock.release();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

AIDL

AIDL也就是Android Interface Definition Language(Android 接口定义语言),是Android自身提供的一种进程键通信机制,可以使用bindService来获取另外一个进程里提供的Binder对象,通过这个远程Binder实现进程间的通信。
在Android Studio里添加aidl文件,aidl的语法和java很像但又不完全一样,下面的代码就是定义一个发送的接口。

// ICommunicate.aidl
package com.example.process;

interface ICommunicate {
    void send(String str);
}

Android Studio会自动为aidl文件生成Java代码,在接收者进程的Service中返回自定义的Stub对象。

public class AIDLService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new Hello();
    }

    private class Hello extends ICommunicate.Stub {
        @Override
        public void send(final String str) throws RemoteException {
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(), str, Toast.LENGTH_SHORT).show();
                }
            });
        }
    }
}

为了能够向接受者进程发送消息,发送者进程调用bindService方法获取这个自定义的Binder对象。

Intent intent = new Intent();
intent.setAction("com.example.aidl.receiver");
intent.setPackage("com.example.receiver");
bindService(intent, new AIDLCallback(), BIND_AUTO_CREATE);

private class AIDLCallback implements ServiceConnection {

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        communicate = ICommunicate.Stub.asInterface(service);
        sendAIDLMessage();
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
}

private void sendAIDLMessage() {
    try {
        communicate.send( "Hello world from AIDL" + (count += 111));
    } catch (RemoteException e) {
        e.printStackTrace();
    }
}

Messenger

Messenger是Android系统提供的对AIDL功能的简单封装,同样可以使用bindService来获取远程进程的Messenger内部Binder对象,这样两者就可以通过Messenger内部的Binder实现进程间通信。在接受者的Service里将Messenger内部的Binder返回。

// 接收者所在的服务
public class ReceiverService extends Service {
    private class MessageHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 1:
                    Bundle bundle = msg.getData();
                    Toast.makeText(getApplicationContext(), bundle.getString("message"), Toast.LENGTH_SHORT).show();
                    break;
                default:
                    break;
            }
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Messenger messenger = new Messenger(messageHandler);
        return messenger.getBinder();
    }

    private MessageHandler messageHandler = new MessageHandler();
}

发送者进程通过bindService获取这个Binder对象。

Intent intent = new Intent();
intent.setAction("com.example.messenger.receiver");
intent.setPackage("com.example.receiver");
bindService(intent, new ServiceCallback(), BIND_AUTO_CREATE);

private class ServiceCallback implements ServiceConnection {

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        sender = new Messenger(service);
        sendMessage();
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        sender = null;
    }
}

private void sendMessage() {
    Message message = Message.obtain();
    message.what = 1;
    String str = "Hello world from Messenger" + (count += 111);
    Bundle bundle = new Bundle();
    bundle.putString("message", str);
    message.setData(bundle);
    try {
        sender.send(message);
    } catch (RemoteException e) {
        e.printStackTrace();
    }
}

Socket

Socket是操作系统提供的网络连接对象,它不止能支持本地的进程间通信还支持不同网络主机键的进程通信,不过这种比较通用的通信手段导致它相对其他通信方式速度更慢。首先在接收者进程需要创建ServerSocket对象。

new Thread(new Runnable() {
    @Override
    public void run() {
        ServerSocket serverSocket = null;
        Socket socket = null;
        try {
            serverSocket = new ServerSocket(8888);
            socket = serverSocket.accept();
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            final StringBuilder stringBuilder = new StringBuilder();
            String str;
            while ((str = reader.readLine()) != null) {
                stringBuilder.append(str);
            }

            handler.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(context, stringBuilder.toString(), Toast.LENGTH_SHORT).show();
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}).start();

发送者进程连接ServerSocket会导致accept方法返回并且生成一个服务端的Socket,这样客户端和服务端两个Socket就能相互通信了。

new Thread(new Runnable() {
    @Override
    public void run() {
        Socket sock = null;
        try {
            sock = new Socket("127.0.0.1", 8888);
            PrintWriter printWriter = new PrintWriter(sock.getOutputStream());
            printWriter.write("Socket Hello World" + (count += 111));
            printWriter.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (sock != null) {
                try {
                    sock.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        socket.post(new Runnable() {
            @Override
            public void run() {
                socket.setEnabled(true);
            }
        });
    }
}).start();
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xingzhong128/article/details/79960210

Android 进阶13:几种进程通信方式的对比总结

不花时间打基础,你将会花更多时间解决那些不必要的问题。 读完本文你将了解: RPC 是什么 IDL 是什么 IPC 是什么 Android 几种进程通信方式 如何选择这几种通信方式 ThanksRPC...
  • u011240877
  • u011240877
  • 2017-06-05 01:16:48
  • 8300

进程通信的几种方式及其各自优缺点

linux上面的IPC大多都是从UNIX上面继承而来。  最初Unix IPC包括:管道、FIFO、信号。System V IPC包括:System V消息队列、System V信号灯、System...
  • fighting_kangle
  • fighting_kangle
  • 2016-12-01 22:34:21
  • 1269

常用的几种进程通信方式的比较

  • 2011年03月02日 14:25
  • 39KB
  • 下载

Android--进程间通信的几种实现方式

一、概述        由于应用程序之间不能共享内存。在不同应用程序之间交互数据(跨进程通讯),在Android SDK中提供了4种用于跨进程通讯的方式。这4种方式正好对应于android系统中...
  • chaoyu168
  • chaoyu168
  • 2017-02-22 08:52:35
  • 1629

Android 进程间通信的几种实现方式

一、概述        由于应用程序之间不能共享内存。在不同应用程序之间交互数据(跨进程通讯),在android SDK中提供了4种用于跨进程通讯的方式。这4种方式正好对应于android系统中4种...
  • zhuangyalei
  • zhuangyalei
  • 2016-01-14 09:53:41
  • 24874

android多进程的几种通信方式二

一.概述    接着上一篇我们继续讲解多进程的通信方式,这一篇我们介绍Messenger(信使),它是基于aidl之上封装了一层,类似thread和handler通信一样简单易使用,它与aidl不同之...
  • u010648159
  • u010648159
  • 2016-09-08 11:43:32
  • 597

Android跨进程通讯的几种方式

Android系统的每个应用都是运行在一个单独的虚拟机中(不同的进程)。因此不同的app间不能直接通讯,但是可以间接进行通讯。 今天我要介绍的四种跨进程通讯方式就是四种间接通讯方式。这四种跨进程通讯的...
  • wangsongbin893603021
  • wangsongbin893603021
  • 2016-03-30 19:03:03
  • 612

进程间8种通信方式详解

1 无名管道通信无名管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。2 高级管道通信高级管道(popen):...
  • violet_echo_0908
  • violet_echo_0908
  • 2016-04-20 15:34:57
  • 30208

【进程间通信】Android 进程间通信的几种实现方式

一、整体结构下面将逐一介绍4种通讯方式二、4种通讯方式1、ActivityAndroid内置了许多可供其他程序跨进程访问的Activity,比如跳至打电话页面(指定Action,uri跨进程访问) ...
  • Tomasyb
  • Tomasyb
  • 2017-06-06 14:32:09
  • 1482

用户进程间通信主要有哪几种方式?

(1)管道(Pipe):管道可用于具有亲缘关系进程间的通信,允许一个进程和另一个与它有共同祖先的进程之间进行通信。 (2)命名管道(named pipe):命名管道克服了管道没有名字的限制,因此,除...
  • zy512638348
  • zy512638348
  • 2017-10-12 09:16:36
  • 229
收藏助手
不良信息举报
您举报文章:Android进程通信的几种方式
举报原因:
原因补充:

(最多只允许输入30个字)