美文网首页
Android多进程通信

Android多进程通信

作者: 主音King | 来源:发表于2018-11-29 16:28 被阅读1次

    Android多进程通信:Socket、ContentProvider、AIDL、Messenger
    Socket多用于消息之间传递(聊天)
    ContentProvider数据库提供共享数据(电话本)
    AIDL提供相互认可的编程接口
    Messenger是基于AIDL

    Socket

    多进程Socket.png

    通过Socket实现两个应用之间的通信,接收消息和发送消息。
    因为基于Socket所以需要网络权限

    <uses-permission android:name="android.permission.INTERNET" />
    

    service端代码:

    public class MyServerSocket implements Runnable {
        private static final String TAG = "MyServerSocket";
        ServerSocket server;
        Socket client;
        PrintWriter os;
        BufferedReader is;
        Handler handler;
    
        public MyServerSocket(Handler handler) {
            this.handler = handler;
        }
    
        /**
         * 需要在自线程中发送消息,这里可以在主线程里调用send
         * @param data
         */
        @WorkerThread
        public void send(final String data) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    if (os != null) {
                        os.println(data);
                        os.flush();
                    }
                }
            }).start();
    
        }
    
        @Override
        public void run() {
            try {
                server = new ServerSocket(8080);
                client = server.accept();
                InetAddress inetAddress = client.getInetAddress();
                String ip = inetAddress.getHostAddress();
                Log.d(TAG, "run-ip:" + ip);
                os = new PrintWriter(client.getOutputStream());
                is = new BufferedReader(new InputStreamReader(client.getInputStream()));
            } catch (Exception e) {
                e.printStackTrace();
            }
            String result = "";
            while (true) {
                try {
                    result = is.readLine();
                    Log.d(TAG, "run-result:" + result);
                    Message msg = handler.obtainMessage();
                    msg.obj = result;
                    msg.arg1 = 0x11;
                    handler.sendMessage(msg);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        public void close() {
            try {
                if (os != null) {
                    os.close();
                }
                if (is != null) {
                    is.close();
                }
                if (client != null) {
                    client.close();
                }
                if (server != null) {
                    server.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    service端连接、发送、关闭连接:

    private MyServerSocket server;
      private StringBuffer receiveData = new StringBuffer();
      private Handler handler = new Handler(new Handler.Callback() {
          @Override
          public boolean handleMessage(Message msg) {
              if (msg.arg1 == 0x11) {
                  receiveData.append(msg.obj);
                  receiveData.append("\r\n");
                  Log.d(TAG, "收到client端消息:handleMessage-receiveData:" + receiveData.toString());
              }
              return false;
          }
      });
    
      public void link(View view) {
          Log.d(TAG,"link");
          server = new MyServerSocket(handler);
          new Thread(server).start();
      }
      private int count = 0;
    
      public void send(View view) {
          ++count;
          Log.d(TAG,"send:"+count);
          server.send("message:" + count);
      }
      public void close(View view) {
          Log.d(TAG,"close");
          server.close();
      }
    

    client端代码:

    public class MyClientSocket implements Runnable {
        private int timeout = 30000;
        Socket client;
        PrintWriter os;
        BufferedReader is;
        Handler handler;
    
        public MyClientSocket(Handler handler) {
            this.handler = handler;
        }
    
        /**
         * 需要在自线程中发送消息,这里可以在主线程里调用send
         * @param data
         */
        @WorkerThread
        public void send(final String data) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    if (os != null) {
                        os.println(data);
                        try {
                            os.flush();
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
    
        }
    
        @Override
        public void run() {
            try {
                client = new Socket("localhost", 8080);
                client.setSoTimeout(timeout);
                os = new PrintWriter(client.getOutputStream());
                is = new BufferedReader(new InputStreamReader(client.getInputStream()));
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            String result = "";
            while (true) {
                try {
                    result = is.readLine();
                    Message msg = handler.obtainMessage();
                    msg.arg1 = 0x12;
                    msg.obj = result;
                    handler.sendMessage(msg);
                } catch (IOException e) {
                    e.printStackTrace();
                }
    
            }
        }
    
        public void close() {
            try {
                if (os != null) {
                    os.close();
                }
                if (is != null) {
                    is.close();
                }
                if (client != null) {
                    client.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    client端连接、发送、关闭操作:

    MyClientSocket client;
        StringBuffer receiveData = new StringBuffer();
        Handler handler = new Handler(new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                if (msg.arg1 == 0x12) {
                    receiveData.append(msg.obj);
                    Log.d(TAG, "收到service端消息receiveData:" + receiveData.toString());
                    receiveData.append("\r\n");
                }
                return false;
            }
        });
    
        public void link(View view) {
            Log.d(TAG, "start");
            client = new MyClientSocket(handler);
            new Thread(client).start();
        }
    
        public void close(View view) {
            Log.d(TAG, "close");
            client.close();
        }
    
        int count = 0;
    
        public void send(View view) {
            ++count;
            Log.d(TAG, "send:" + count);
            client.send("client send:" + count);
        }
    

    ContentProvider

    多进程ContentProvider.png

    不同应用程序之间共享数据,底层Binder实现,为存储和获取数据提供统一接口
    Service端代码共享数据库:

    public class DbOpenHelper extends SQLiteOpenHelper {
        private static final String TAG = "DbOpenHelper";
        private static final String DB_NAME = "provider.db";
        private static final int DB_VERSION = 1;
        public static final String TABLE_TEST = "my_provide";
        
        private String mCreateTable = "create table if not exists "+TABLE_TEST+"(id integer primary key,"+"name TEXT, "+"sex TEXT)";
        public DbOpenHelper(Context context) {
            super(context,DB_NAME,null,DB_VERSION);
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
            Log.d(TAG,"onCreate");
            db.execSQL(mCreateTable);
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }
    }
    
    public class TestProvider extends ContentProvider {
        private static final String TAG = "TestProvider-测试-app2";
        public static final String AUTHORITY = "com.example.george.TestProvider";// 提供凭证;用于两个app之间的通信
        private static final UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        private SQLiteDatabase mDb;
        private Context mContext;
        private String mTable;
    
        static {
            mUriMatcher.addURI(AUTHORITY, "student", 0);
        }
    
        @Override
        public boolean onCreate() {
            Log.d(TAG, "onCreate");
            mTable = DbOpenHelper.TABLE_TEST;
            mContext = getContext();//ContentProvider的onCreate执行在Application的onCreate之前
            initProvider();
            return false;
        }
    
        private void initProvider() {
            mDb = new DbOpenHelper(mContext).getWritableDatabase();
        }
    
        @Override
        public Bundle call(String method,
                           String arg,
                           Bundle extras) {
            Log.d(TAG, "call-method:");
            Bundle bundle = new Bundle();
            bundle.putString(method, "xiaowang");
            return bundle;
        }
    
    
        @Override
        public Cursor query(Uri uri,
                            String[] projection,
                            String selection,
                            String[] selectionArgs,
                            String sortOrder) {
            Log.d(TAG, "query-");
            String table = DbOpenHelper.TABLE_TEST;
            Cursor mCursor = mDb.query(table, projection, selection, selectionArgs, null, sortOrder, null);
            return mCursor;
        }
    
    
        @Override
        public String getType(Uri uri) {
            return null;
        }
    
    
        @Override
        public Uri insert(Uri uri,
                          ContentValues values) {
            Log.d(TAG, "insert");
            mDb.insert(mTable, null, values);
            return null;
        }
    
        @Override
        public int delete(Uri uri,
                          String selection,
                          String[] selectionArgs) {
            return 0;
        }
    
        @Override
        public int update(Uri uri,
                          ContentValues values,
                          String selection,
                          String[] selectionArgs) {
            return 0;
        }
    }
    

    在AndroidManifest.xml中注册

    <provider
                android:authorities="com.example.george.TestProvider"
                android:name=".TestProvider"
                android:process=":provider"
                android:exported="true"
                />
    

    Client端获取ContentProvider提供的数据

            Uri uri = Uri.parse(AUTHORITY);
            ContentValues mContentValues = new ContentValues();
            mContentValues.put(ID, 34);
            mContentValues.put(NAME, "小王");
            mContentValues.put(SEX, "男");
            getContentResolver().insert(uri, mContentValues);// 根据 凭证 插入到数据库
    
            Cursor cursor = getContentResolver().query(uri, new String[]{NAME, SEX}, null, null, null);// 根据 凭证 获取数据库
            while (cursor.moveToNext()) {
                Student student = new Student(cursor.getString(0), cursor.getString(1));
                Log.d(TAG, "name:" + student.mName + " sex:" + student.mSex);
            }
            Bundle bundle = getContentResolver().call(uri, METHOD, null, null);
            Log.d(TAG, "method:" + bundle.getString(METHOD));
    

    AIDL

    多进程AIDL.png

    两个不同app之间通信
    在AndroidStudio中新建Person.aidl。会在main/aidl/xxx.Person.aidl。然后make project生成中间代码。
    Service 端代码:

    interface Person {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
        void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
                double aDouble, String aString);
    
        String getName();
    }
    

    在AndroidManifest.xml中注册,由于是两个app通信,则 enabled="true" 可用,android:exported="true"允许外部app访问。

    <service android:name="com.example.george.androidutils.MyService"
                android:enabled="true"
                android:exported="true">
                <intent-filter>
                    <action android:name="com.example.george.action.MyService" />
                    <category android:name="android.intent.category.DEFAULT"/>
                </intent-filter>
            </service>
    

    MyService.java代码如下:

    public class MyService extends Service {
        private static final String TAG = "MyService-测试-app1";
        public MyService() {
            Log.d(TAG,"MyService");
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            Log.d(TAG,"IBinder");
            return new MyBinder();
        }
    
        class MyBinder extends Person.Stub{
    
            @Override
            public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
    
            }
    
            @Override
            public String getName() throws RemoteException {
                Log.d(TAG,"getName");
                return "456";
            }
        }
    }
    

    另一个app客户端代码,在api21之后严格要求必须写入类名,否则无法启动另外一个app的service。
    Client代码:

    intent.setClassName("com.example.george.androidutils","com.example.george.androidutils.MyService");
    

    或者

    intent.setComponent(new ComponentName("com.example.george.androidutils", "com.example.george.androidutils.MyService"));
    

    这里采用第二种。

    public void connnect(View view) {
            Intent intent = new Intent();
    //        intent.setPackage("com.example.george.androidutils");
    //        intent.setAction("com.example.george.action.MyService");
    //        intent.setClassName("com.example.george.androidutils","com.example.george.androidutils.MyService");
            intent.setComponent(new ComponentName("com.example.george.androidutils", "com.example.george.androidutils.MyService"));
            bindService(intent, new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                    Person person = Person.Stub.asInterface(service);
                    Log.d(TAG, "onServiceConnected-componentName:" + name);
                    try {
                        Log.d(TAG, "onServiceConnected-person:" + (person == null ? "null" : person.getName()));
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
    
                @Override
                public void onServiceDisconnected(ComponentName name) {
                    Log.d(TAG, "onServiceDisconnected-componentName:" + name);
                }
            }, BIND_AUTO_CREATE);
        }
    

    Messenger

    是基于AIDL实现的,服务端(被动)Service处理客户端(主动),用Handler来创建Messenger,在onBinder返回Messenger的binder。双方用Messenger发送数据,用handler(串行)处理数据。多个message排队依次处理。


    多进程Messenger.png

    在AndroidManifest.xml中注册

    <service android:name=".MessengerService"
                android:process=":remote"/>
    

    服务端代码:

    public class MessengerService extends Service {
        private static final String TAG = "MessengerService-测试";
    
        Messenger mMessenger = new Messenger(new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 1:
                        Log.d(TAG, "handleMessage-接收客户端消息");
                        try {
                            Thread.sleep(3000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
    
                        Messenger messenger = msg.replyTo;
                        try {
                            Log.d(TAG, "handleMessage-向客户端发送消息");
                            messenger.send(Message.obtain(null, 1, 0, 0));
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                }
            }
        });
    
        @Override
        public IBinder onBind(Intent intent) {
            return mMessenger.getBinder();
        }
    }
    

    客户端代码:

    public class MainActivity extends AppCompatActivity {
        private static final String TAG = "MainActivity-测试";
        private boolean mMessengerIsConnect;
        private Messenger mMessenger = new Messenger(new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 1:
                        Log.d(TAG, "handleMessage-客户端收到消息");
                        break;
                }
            }
        });
        private ServiceConnection mConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.d(TAG, "onServiceConnected-建立连接");
                mMessengerIsConnect = true;
                Messenger messenger = new Messenger(service);
                Message message = Message.obtain(null, 1, 0, 0);
                message.replyTo = mMessenger;
                try {
                    Log.d(TAG, "onServiceConnected-向服务端发送消息");
                    messenger.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {// 连接正常关闭不会被调用。何时调用:系统资源不足,要关闭一些service
                mMessengerIsConnect = false;
                Log.d(TAG, "onServiceConnected-断开连接");
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
    
        public void link(View view) {
            if (!mMessengerIsConnect)
                bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE);
        }
    
        public void unLink(View view) {
            if (mMessengerIsConnect){
                mMessengerIsConnect = false;
                unbindService(mConnection);
            }
        }
    
    }
    

    相关文章

      网友评论

          本文标题:Android多进程通信

          本文链接:https://www.haomeiwen.com/subject/ciufcqtx.html