Android多进程通信

2018-11-29  本文已影响1人  主音King

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);
        }
    }

}
上一篇下一篇

猜你喜欢

热点阅读