Android 跨进程通讯的方式

15 篇文章 0 订阅

我已知Android 的跨进程通信方式有6种,分别为:访问他应用的Activity、接收其他应用的广播、访问其它应用的

开放数据、AIDL、Messenger和socket的跨进程通信。

(1)访问他应用的Activity

举一个简单的例子:

这个就是调用系统打电话的代码。这就是一个简单的Activity的跨进程通信。

private void test_1(){
      Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:123654789"));  
      startActivity(callIntent);  
   }

那么Activity跨进程是怎么实现的呢?

服务端:(注:服务端和客户端是不同应用)

<activity
     android:name="xyzefg.xxx.yyyy.cccc.ServiceActivity" >
            <intent-filter>
                <action android:name="com.service.activity" />

                <category android:name="android.intent.category.DEFAULT" />

                <data android:scheme="service" />
            </intent-filter>
 </activity>
public class ServiceActivity extends Activity{
   TextView tv ;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.service);
      
      if (getIntent().getData() != null) {
         String host = getIntent().getData().getHost();
         Bundle bundle = getIntent().getExtras();
         String value = bundle .getString("value");
         tv = (TextView) findViewById(R.id.tv);
         tv.setText(host+":"+value);
      }
   }
}
客户端:
private void test_2(){  
     Intent callIntent = new Intent("com.service.activity", Uri    
        .parse("service://跨进程请求Activity" ));  
     Bundle extras = new Bundle();  
     extras.putString("value", "我可是跨进程的");  
     callIntent.putExtras(extras);  
     startActivity(callIntent);    
  }  
服务端主要实现分为三步:

1,设置启动的action <action/>

2,定义一个访问协议 <data/>

3,设置默认分类 <category/>

客户端:只要按照对应的action和协议就能请求到服务端的Activity

(2)接收其他应用的广播

举个简单的例子:

动态注册监听系统没分钟变化的广播。

   private void registerTimeReceiver(){
      IntentFilter intentFilter = new IntentFilter();
      intentFilter.addAction(Intent.ACTION_TIME_CHANGED);
      intentFilter.addAction(Intent.ACTION_TIME_TICK);
      registerReceiver(myReceive, intentFilter);
   }
   
   BroadcastReceiver myReceive = new BroadcastReceiver(){

      @Override
      public void onReceive(Context arg0, Intent arg1) {
         Log.d("TAG","触发了");
      }
      
   };

那么广播的跨进程是怎么实现的呢?

发送者:(注:发送者和接受者是不同的应用)

   private void test_3(){
      Intent intent = new Intent("com.my.receiver");
      intent.putExtra("value", "我可是跨进程的");
      sendBroadcast(intent);
   }
接收者:
public class MyReceiver extends BroadcastReceiver{
   public final static String ACTION = "com.my.receiver";
   @Override
   public void onReceive(Context arg0, Intent arg1) {
      if (arg1.getAction() == ACTION) {
         Log.d("TAG", arg1.getStringExtra("value"));
      }
   }
}
注册广播:

①动态注册:

   private void registerTimeReceiver(){
      IntentFilter intentFilter = new IntentFilter();
      intentFilter.addAction(MyReceiver.ACTION);
      registerReceiver(myReceiver, intentFilter);
   }
静态 注册:
<receiver android:name="xyzefg.xxx.yyyy.cccc.MyReceiver" >
     <intent-filter>
         <action android:name="com.my.receiver" />
     </intent-filter>
</receiver>

定义一个广播接收需要继承BroadcastReceiver 并从写里面的onReceiver 方法,并且不要忘记注册广播,并且指定广

播接收的Action。发送广播只需要定义一个意图对象的action指向接收的Receiver,然后调用sendBroadcast(Intent)。

(3)访问其它应用的开放数据

举一个简单的例子:

查询手机联系人。

private void test_4(){
      ContentResolver contentResolver = getContentResolver();
      Cursor cursor = contentResolver.query(android.provider.Contacts.Phones.CONTENT_URI, null, null, null, null);
      while (cursor.moveToNext()) {
         String name = cursor.getString(cursor.getColumnIndex(android.provider.Contacts.Phones.NAME));
         String num = cursor.getString(cursor.getColumnIndex(android.provider.Contacts.Phones.NUMBER));
         Log.d("TAG", "name:"+name+"\nPhoneNum:"+num);
      }
   }

相比上面2个ContentProvider相对来说是麻烦多了。

服务端:(注:服务端和客户端不是同一个应用)

Andriod:

package com.example.hellojni;

import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;

@DatabaseTable(tableName = "android")
public class Android {
   @DatabaseField(columnName="_id",generatedId = true)
   private Integer id;
   
   @DatabaseField(columnName = "name")
   private String name;
   
   @DatabaseField(columnName = "version")
   private String version;
   
   public Android() {
   }

   public Android(String name,String version){
      this.name = name;
      this.version = version;
   }

   public Integer getId() {
      return id;
   }

   public void setId(Integer id) {
      this.id = id;
   }



   public String getName() {
      return name;
   }

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

   public String getVersion() {
      return version;
   }

   public void setVersion(String version) {
      this.version = version;
   } 
   
}
DataBaseHelper:
package com.example.hellojni;

import java.sql.SQLException;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;

import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;

public class DataBaseHelper extends OrmLiteSqliteOpenHelper{
   
   private final static String TABLENAME = "android";
   
   private static DataBaseHelper instance;
   
   private static Dao<Android, Integer> androidDao;
   
   private DataBaseHelper(Context context) {
      super(context, TABLENAME, null, 1);
   }
   
   public static synchronized DataBaseHelper getHelper(Context context)  
   {  
       if (instance == null)  
       {  
           synchronized (DataBaseHelper.class)  
           {  
               if (instance == null)  
                   instance = new DataBaseHelper(context.getApplicationContext());  
           }  
       }  
       return instance;  
   }  

   @Override
   public void onCreate(SQLiteDatabase arg0, ConnectionSource arg1) {
      
      try {
         TableUtils.createTable(arg1, Android.class);
      } catch (SQLException e) {
         e.printStackTrace();
      }
      
   }

   @Override
   public void onUpgrade(SQLiteDatabase arg0, ConnectionSource arg1, int arg2, int arg3) {
      try {
         TableUtils.dropTable(arg1, Android.class, true);
         onCreate(arg0, arg1);
      } catch (SQLException e) {
         e.printStackTrace();
      }
   }
   
   public Dao<Android, Integer> getAndroidDao(){
      if (androidDao == null) {
         try {
            androidDao = super.getDao(Android.class);
            
         } catch (SQLException e) {
            e.printStackTrace();
         }
      }
      return androidDao;
   }
   
   @Override
   public void close() {
      super.close();
      if (androidDao !=null) {
         androidDao = null;
      }
   }

}
ContentProvider:
package com.example.hellojni;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;

public class MyContentProvider extends ContentProvider{

   private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
   
   private static final int CODE_NOPARAM = 1;
   
   private static final int CODE_PARAM = 2;
   
   private static final String AUTHORITIES = "cn.siy.provider.database";
   
   private static final String PATH_1 = "android";
   
   private static final String PATH_2 = "android/#";
   
   //集合类型,返回值前面一般是固定的,后面的值是自己添加的,也可以加上包路径 
   private static final String TYPE_ANDROIDS = "vnd.android.cursor.dir/" + "android";  
   
   //非集合类型数据,返回值前面一般是固定的,后面的值是自己添加的,也可以加上包路径 
   private static final String TYPE_ANDROID = "vnd.android.cursor.item/" + "android";  
   
   
   /**
    * content://cn.siy.provider.database/android/1/name
    * 
    * 其中content://是scheme Android规定必须是content
    * cn.siy.provider.database 是Authority ContentProvider的唯一标示
    *  /android/1/name 是path 指定对什么数据进行操作(对android表的id为1的name字段操作)
    */
   
   DataBaseHelper helper;
   
   static{
      matcher.addURI(AUTHORITIES, PATH_1, CODE_NOPARAM);
      matcher.addURI(AUTHORITIES, PATH_2, CODE_PARAM);
   }
   
   

   @Override
   public boolean onCreate() {
      helper = DataBaseHelper.getHelper(getContext());
      return true;
   }
   
   @Override
   public int delete(Uri uri, String selection, String[] selectionArgs) {
         SQLiteDatabase sqLiteDatabase = helper.getWritableDatabase();
         int count =-1;
         switch (matcher.match(uri)) {
         case CODE_NOPARAM:
            count = sqLiteDatabase.delete(PATH_1, selection, selectionArgs);
            break;
         case CODE_PARAM:
            long id = ContentUris.parseId(uri);
            String where = "_id = " + id;
            if (null != selection && !"".equals(selection.trim()))
            {
                where += " and " + selection;
            }
            count =  sqLiteDatabase.delete(PATH_1, where, selectionArgs);
            break;
         default:
            break;
         }
         
         getContext().getContentResolver().notifyChange(uri, null);
        return count;
   }

   @Override
   public String getType(Uri arg0) {
      switch (matcher.match(arg0)) {
      case CODE_NOPARAM:
         return TYPE_ANDROIDS;
      case CODE_PARAM:
         return TYPE_ANDROID;
      default:
         break;
      }
      return null;
   }

   @Override
   public Uri insert(Uri url, ContentValues values) {
      SQLiteDatabase db = helper.getWritableDatabase();
      long id = -1;
      switch (matcher.match(url))
      {
          case CODE_NOPARAM:
              // 若主键值是自增长的id值则返回值为主键值,否则为行号,但行号并不是RecNo列
              id = db.insert(PATH_1, "name", values); 
              break;
          default:
              break;
      }
      
      if (id>0) {
         Uri insertUri = ContentUris.withAppendedId(url, id); 
         getContext().getContentResolver().notifyChange(insertUri, null);
         return insertUri;
      }
      return null;
   }

   @Override
   public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
      SQLiteDatabase sqLiteDatabase = helper.getReadableDatabase();
      Cursor cursor = null;
      switch (matcher.match(uri)) {
      case CODE_NOPARAM:
         cursor =  sqLiteDatabase.query(PATH_1, projection, selection, selectionArgs, null, null, sortOrder);
         break;
      case CODE_PARAM:
         long id = ContentUris.parseId(uri); // 取得跟在URI后面的数字
         String where = "_id = " + id;
         if (null != selection && !"".equals(selection.trim()))
         {
             where += " and " + selection;
         }
         cursor = sqLiteDatabase.query(PATH_1, projection, where, selectionArgs, null, null, sortOrder);
         break;
      default:
         break;
      }
      
      cursor.setNotificationUri(getContext().getContentResolver(), uri);
      return cursor;
   }

   @Override
   public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
      SQLiteDatabase sqLiteDatabase = helper.getWritableDatabase();
      int count = 0;
      switch (matcher.match(uri)) {
      case CODE_NOPARAM:
         count = sqLiteDatabase.update(PATH_1, values, selection, selectionArgs);
         break;
      case CODE_PARAM:
         long id = ContentUris.parseId(uri);
         String where = "_id = " + id;
         if (null != selection && !"".equals(selection.trim()))
         {
             where += " and " + selection;
         }
         count = sqLiteDatabase.update(PATH_1, values, where, selectionArgs);
      default:
         break;
      }
      getContext().getContentResolver().notifyChange(uri, null);
      return count;
   }

}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testndk"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />
    
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.CALL_PHONE"/>
    <uses-permission android:name="android.permission.READ_CONTACTS" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.hellojni.SiyActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
        <provider 
            android:exported="true"
            android:name="com.example.hellojni.MyContentProvider"
            android:authorities="cn.siy.provider.database">
        </provider>
    </application>

</manifest>
数据库的操作使用了ormlite框架。

首先我对ContentProvider中增删改查几个方法的参数解释一下吧,因为一开始我自己也是糊涂,这里记录一下防止下

次自己又忘记了。

1)delete(Uri uri, String selection, String[] selectionArgs);

第一个参数 uri:uri怎么解释呢?恩!就是每个内容提供者的唯一标示,用指定你访问的是哪一个内容提供者。

第二个参数 selecttion:他可以单独使用也可以和selectionArgs配合使用。先解释它怎么单独使用例如:

contentResolver.delete(Uri.parse("content://cn.siy.provider.database/android"), "_id in (14,13,12)", null);

上面语句的意思就是删除_id是12,13,14的记录,执行之后的结果

单独使用的时候他就相当于条件语句,放在where 之后。也可以传null表示删除所有。再看看它怎么和selectionArgs配合使用:

contentResolver.delete(Uri.parse("content://cn.siy.provider.database/android"), "_id in(?,?,?)", new String[]{"14","13","12"});

执行结果和上面的结果一样。selecttion你面有多少个“?”,selectionArgs里面就要有多少个数据进行相应的替换,特别注意顺序额!

第三个参数selectionArgs:他就是配合selecttion的,如果selecttion是空的,它也可以传null。

2)insert(Uri uri, ContentValues values)

第一个参数uri:同上不做解释。

第二个参数 values:他是一个类似map的数据结构,可以put进键值对,key是表结构的列名,value是列名对应的值,具体用法如:

ContentValues contentValues = new ContentValues();
contentValues.put("name", "Android-N");
contentValues.put("version", "7.0");
contentResolver.insert(Uri.parse("content://cn.siy.provider.database/android"), contentValues);
3)query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

第一个参数uri:同上不做解释。

第二个参数projection:它表示查询后要显示的列名,可以传null表示查询显示所有,类似如sql语句的“*”。

第三个参数selection:同上不解释。

第四个参数selectionArgs:同上不解释。

第五参数sortOrder:它是指按照什么顺序排序,相当于sql的order by。具体用法如:

Cursor cursor = contentResolver.query(Uri.parse("content://cn.siy.provider.database/android"), null, null, null, "_id desc");

4)update(Uri uri, ContentValues values, String selection, String[] selectionArgs)

参数的意思都能在上面找到我就不说了。

要编写ContentProvider:

1,要继承要写一个类继承ContentProvider然后重写里面的方法,一般会有onCreate(),getType(),delete(),insert(),query(),update()。

2,指定一个唯一标示当前provider的uri。provider的uri的规则content://+Authority+path。content://是Android规定的不允许更改的,Authority自己指定作为provider的唯一标示,最好两级以上,何为两级以上呢?自己领悟!path是标示

操作对象一般表名什么。

举个例子吧:

content://cn.siy.provider.database/android/1/name

其中content://是scheme Android规定必须是content
cn.siy.provider.database 是Authority ContentProvider的唯一标示
 /android/1/name 是path 指定对什么数据进行操作(对android表的id为1的name字段操作)

3,既然uri里面包含这么多信息,那么provider怎么知道呢?Android为我们提供UriMatcher这个类,它允许我们将定

义好的uri添加到其中。

private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);

static{
      matcher.addURI(AUTHORITIES, PATH_1, CODE_NOPARAM);
      matcher.addURI(AUTHORITIES, PATH_2, CODE_PARAM);
   }
UriMatcher.NO_MATCH是匹配失败返回的值为-1。CODE_NOPARAM表示匹配path_1返回的值,CODE_PARAM表

示path_2返回的值。其中“匹配”动作可以通过matcher.match(uri)方法实现,这样就可以通过不同的返回值来进行不同的操作了。

4,既然provider是的四大组件之一(Activity,receiver,service,provider),那么它也是要在AndroidManifest.xml注册的。

<provider 
   android:exported="true"
   android:name="com.example.hellojni.MyContentProvider"
   android:authorities="cn.siy.provider.database">
</provider>
authorities就是上面说的uri中的authorities,name就是ContentProvider的全类名,exported为true表示它对其他应用可

见。

要使用provider:

1,首先你得有ContentResolver,这个你一调用Activity的getContentResolver()得到。

2, 然后通过ContentResolver的增删改查方法就可以调用provider的增删改查方法了,参数名的意思上面有说。

3,Uri.parse("content://cn.siy.provider.database/android")把字符串编程uri

到此provider的简单实用就解释完了,不说了。

(4)AIDL

例子不知道怎么举了,那就直接上代码吧!

服务端:(注:服务端和客户端不是同一个应用)

IService.aidl

package com.example.mytest.zoomInImanage;

import com.example.mytest.zoomInImanage.Android;

interface IService{
	/** 八种基本类型  shot 会报错额**/
	String input1(byte arg1,/**shot arg2,**/int arg3,char arg4,boolean arg5,float arg6,double arg7,long arg8);
	
	String input2(String arg1,CharSequence arg2);
	
	/** 需要使用in、out或inout修饰。其中in表示这个值被客户端设置;out表示这个值被服务端设置;inout表示这个值既被客户端设置,又被服务端设置。 **/
	Android input3(in List<String> arg1,in Map arg2);
	
	/** 必须要导包  **/
	String input4(in Android arg1);
}
Android.java(其实就是上面的Android类实现了Parcelable,哈哈...)
package com.example.mytest.zoomInImanage;

import android.os.Parcel;
import android.os.Parcelable;

import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;

@DatabaseTable(tableName = "android")
public class Android implements Parcelable {
   @DatabaseField(columnName = "_id", generatedId = true)
   private Integer id;

   @DatabaseField(columnName = "name")
   private String name;

   @DatabaseField(columnName = "version")
   private String version;

   public Android() {
   }

   public Android(String name, String version) {
      this.name = name;
      this.version = version;
   }
   
   public Android(Integer id,String name, String version) {
      this.id = id;
      this.name = name;
      this.version = version;
   }

   public Integer getId() {
      return id;
   }

   public void setId(Integer id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

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

   public String getVersion() {
      return version;
   }

   public void setVersion(String version) {
      this.version = version;
   }

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

   @Override
   public void writeToParcel(Parcel arg0, int arg1) {
      // 注:Parcel中的数据是按顺序写入和读取的,即先被写入的就会先被读取出来 
      arg0.writeInt(id);
      arg0.writeString(name);
      arg0.writeString(version);
   }
   
   //该静态域是必须要有的,而且名字必须是CREATOR,否则会出错  
   public static final Parcelable.Creator<Android> CREATOR = new Creator<Android>() {
      
      @Override
      public Android[] newArray(int arg0) {
         return new Android[arg0];
      }
      
      @Override
      public Android createFromParcel(Parcel arg0) {
       //从Parcel读取通过writeToParcel方法写入的Person的相关成员信息  
         return new Android(arg0.readInt(), arg0.readString(), arg0.readString());
      }
   };

}
Android.aidl(aidl传输的Parcelable对象,必须顶一个相应的aidl文件)
parcelable Android;
Myservice.java
package com.example.mytest.zoomInImanage;

import java.util.List;
import java.util.Map;

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

public class MyService extends Service{

   class MyBinder extends IService.Stub{

      @Override
      public String input1(byte arg1, int arg3, char arg4, boolean arg5, float arg6, double arg7, long arg8)
         throws RemoteException {
         return arg1+"-"+arg3+"-"+arg4+"-"+arg5+"-"+arg6+"-"+arg7+"-"+arg8+"-over";
      }

      @Override
      public String input2(String arg1, CharSequence arg2) throws RemoteException {
         return arg1+"-"+arg2+"-over";
      }

      @Override
      public Android input3(List<String> arg1, Map arg2) throws RemoteException {
         if (arg2.containsKey(1)) {
            if (arg2.get(1) instanceof Android) {
               return (Android)arg2.get(1);
            }
         }
         return null;
      }

      @Override
      public String input4(Android arg1) throws RemoteException {
         return arg1.getName();
      }
   }
   
   private MyBinder mybinder;
   
   @Override
   public void onCreate() {
      super.onCreate();
      Log.d("TAG", "onCreate");
      mybinder = new MyBinder();
   }
   
   @Override
   public IBinder onBind(Intent arg0) {
      Log.d("TAG", "onBind");
      return mybinder;
   }

}
AndroidManifest.xml
<service android:name="com.example.mytest.zoomInImanage.MyService"
   android:exported="true">
    <intent-filter>
       <!--  指定调用AIDL服务的ID  -->  
        <action android:name="com.siy.servicer" />
    </intent-filter>
 </service>
客户端:
Intent intent = new Intent("com.siy.servicer");
IService iservice;
bindService(intent, conn, Context.BIND_AUTO_CREATE);
   ServiceConnection conn = new ServiceConnection() {
      
      @Override
      public void onServiceDisconnected(ComponentName arg0) {
         
      }
      
      @Override
      public void onServiceConnected(ComponentName arg0, IBinder arg1) {
         Log.d("TAG", arg0+"");
         iservice = IService.Stub.asInterface(arg1);
      }
   };
使用AIDL:

1,首先呢得写一个服务的aidl文件,里面定义一些需要实现的方法。

2,关于方法的参数:

①支持除了shot类型以为的基本类型(byte,char,int,boolean,float,long,double)

②支持String,CharSequence类型

③支持实现Parcelable序列化的类型

④支持List,Map,但是里面传输的类型必须是以上4种

3,如果传输Parcelable序列化的对象,必须定义相应的aidl文件,并且不要忘记在服务的aidl文件中导包

4,实现的服务类,必须在onBind返回服务的aidl的实现类的桩对象(也有人说是句柄对象,随便你叫什么),就是那个

继承.Stub的对象。

5,在AndroidManifest.xml中注册

6,在客户端绑定服务,用iservice = IService.Stub.asInterface(arg1)获取远程服务对象。注意哈,你的服务端的

.aidl文件都要拷一份给

客户端并且包名不能变。

(5)Messenger

例子不举了吧!

我还是看代码吧!我觉得代码最能让人理解。

MessageService:

public class MessageService extends Service{
   
   public static final int FROMCLIENT = 123;
   
   private Messenger service = new Messenger(new Handler(){
      @Override
      public void handleMessage(Message msg) {
         Message serviceMessage = Message.obtain();
         switch (msg.what) {
         case FROMCLIENT:
            serviceMessage.what = FROMCLIENT;
            Android an = (Android)(msg.obj);
//            serviceMessage.obj = an.getName();
//            serviceMessage.arg1 = msg.arg1;
            
            Bundle bundle = msg.getData();
            Android andriod_1 = (Android) bundle.getSerializable("android_1");
            Android android_2 = (Android) bundle.getSerializable("android_2");
            
            Android android = new Android(andriod_1.getId() + android_2.getId(), andriod_1.getName() +
               android_2.getName(), andriod_1.getVersion() + android_2.getVersion());
            
            Bundle bundle_1 = new Bundle();
            bundle_1.putSerializable("android", android);
            serviceMessage.setData(bundle_1);
            try {
               msg.replyTo.send(serviceMessage);
            } catch (RemoteException e) {
               e.printStackTrace();
            }
            break;

         default:
            break;
         }
         super.handleMessage(msg);
      };
   });
   
   
   @Override
   public IBinder onBind(Intent arg0) {
      return service.getBinder();
   }

   
}
AndroidManifest.xml
<service android:name="com.example.mytest.photowall.MessageService"
           android:exported="true">
    <intent-filter >
        <action android:name="com.siy.messageservice"/>
    </intent-filter>
</service>
client:
  private static final int FROMCLIENT = 123;
   
   private Messenger mServiceMessage;
   private ServiceConnection messageConn = new ServiceConnection() {
      
      @Override
      public void onServiceDisconnected(ComponentName name) {
         mServiceMessage = null;
      }
      
      @Override
      public void onServiceConnected(ComponentName name, IBinder service) {
         mServiceMessage = new Messenger(service);
         Log.d("TAG", "连上了");
      }
   };
   
   private Messenger client = new Messenger(new Handler(){
      @Override
      public void handleMessage(Message msg) {
         switch (msg.what) {
         case FROMCLIENT:
            Bundle bundle = msg.getData();
            Android android = (Android) bundle.getSerializable("android");
            Log.d("TAG", "messenger:"+android);
            break;

         default:
            break;
         }
         super.handleMessage(msg);
      }
   });
   
   private void test_7(){
      Message clientMessage = Message.obtain();
      clientMessage.what = FROMCLIENT;
//      clientMessage.obj = new Android(1, "andorid-n", "7.0");
//      clientMessage.arg1 = 1;
      Bundle bundle = new Bundle();
      bundle.putSerializable("android_1", new Android(1,"andriod-1", "1.0"));
      bundle.putSerializable("android_2", new Android(2,"android-2", "2.0"));
      clientMessage.setData(bundle);
      
      clientMessage.replyTo = client;
      try {
         mServiceMessage.send(clientMessage);
      } catch (RemoteException e) {
         e.printStackTrace();
      }
   }
使用messenger:

1,在服务器定一个Messenger 并以Handler为参数实例化它。

2,在AndroidManifest.xml注册它

3,在客户端也是用一个Messenger并以Handler参数实例化它进行通信的。

其实messenger的使用非常简单。但是他们通信所传递的对象如果是int型直接用户message.arg1 和message.arg2

行了,如果是自定义对象不能用message.obj,而要使用message.setData(),而且我发现不能使用Parcelable对象

要使用Serializable,不知道是不是我的使用方式不对,反正我使用Parcelable老是报错的。

(6)Socket:

例子不举了吧!

我还是看代码吧!我觉得代码最能让人理解。

SocketServicer:
public class SocketServicer extends Service{
    private boolean mIsServideDestoryed = false;

    private String[] mDefinedMessages = new String[]{
            "你好啊,哈哈",
            "请问你叫什么名字?",
            "今天深圳的天气不太好诶",
            "你知道吗,我是可以同时和很多人聊天额",
            "给你讲一个笑话吧,一二三,笑话"
    };


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        new Thread(new TcpService()).start();
        System.out.println("servicer启动了");
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        mIsServideDestoryed=true;
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    private  class TcpService implements Runnable{

        @Override
        public void run() {
            ServerSocket serverSocket = null;

            //监听本地8688端口
            try {
                serverSocket = new ServerSocket(8688);
            }catch (IOException e){
                e.printStackTrace();
                return;
            }
            while(!mIsServideDestoryed){
                try {
                    //接受客户端的请求
                     final Socket client = serverSocket.accept();
                    System.out.println("客户端已经连上了");
                    System.out.println("client_1"+client);
                    new Thread(){
                        @Override
                        public void run() {
                            try{
                                System.out.println("client_2"+client);
                                responseClinet(client);
                            }catch (IOException e){
                                e.printStackTrace();
                            }
                        }
                    }.start();

                }catch (IOException e){
                }

            }
        }
    }

    private void responseClinet(Socket client) throws IOException{
        //用于接受客户端的消息
        BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));

       //用于向客户端发送消息
        PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())),true);

        out.println("欢迎大家了来到聊天室");


        while(!mIsServideDestoryed){

            String str = in.readLine();

            System.out.println("msg form client:"+str);

            if(str == null){
                //客户端断开
                break;
            }
            int i = new Random().nextInt(mDefinedMessages.length);
            String msg = mDefinedMessages[i];
            out.println(msg);
        }
        if(in != null){
            in.close();
        }

        if(out!=null){
            out.close();
        }

        if(client!=null){
            client.close();
        }
        System.out.println("client活着4");
    }
}
SocketClientTest:
public class SocketClientTest extends Activity {
    private Socket mclientSocket;
    private BufferedReader mBufferedReader;
    private PrintWriter mPrintWriter;

    private static final int MESAGE_RECEIVE_NEW_MSG = 1;
    private static final int MESAGE_SOCKET_CONNECTED = 2;

    private EditText client_1;

    private TextView service_1;
    private TextView service_2;
    private TextView service_3;

    private Button sendbut;


    private Handler mhandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MESAGE_SOCKET_CONNECTED:
                    break;
                case MESAGE_RECEIVE_NEW_MSG:
                    if (TextUtils.isEmpty(service_1.getText())){
                        service_1.setText((String)msg.obj);
                        return;
                    }
                    if (TextUtils.isEmpty(service_2.getText())){
                        service_2.setText((String)msg.obj);
                        return;
                    }

                    if (TextUtils.isEmpty(service_3.getText())){
                        service_3.setText((String)msg.obj);
                    }
                    break;
            }

        }
    };

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

        client_1 = (EditText) findViewById(R.id.clinet_1);

        service_1 = (TextView) findViewById(R.id.servicer_1);
        service_2 = (TextView) findViewById(R.id.servicer_2);
        service_3 = (TextView) findViewById(R.id.servicer_3);

        sendbut = (Button) findViewById(R.id.send);

        sendbut.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(!TextUtils.isEmpty(client_1.getText()) && mPrintWriter !=null){
                    mPrintWriter.println(client_1.getText());
                    client_1.setText("");
                }
            }
        });


        new Thread() {
            @Override
            public void run() {
                connectSocketServier();
            }
        }.start();
    }

    @Override
    protected void onDestroy() {
        try{
        if(mclientSocket !=null){
            mclientSocket.shutdownInput();
            mclientSocket.close();;
        }
        }catch (IOException e){
            e.printStackTrace();
        }
        super.onDestroy();
    }

    private void connectSocketServier() {
        Socket client = null;

        while (client == null) {
            try {
                client = new Socket("localhost", 8688);
                mclientSocket = client;

                System.out.println("connect service success");
            } catch (IOException e) {
                SystemClock.sleep(1000);
                System.out.println("connect service failed,retry...");
            }
        }

        try {
            mBufferedReader = new BufferedReader(new InputStreamReader(mclientSocket.getInputStream()));
            mPrintWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(mclientSocket.getOutputStream())),true);
            mhandler.sendEmptyMessage(MESAGE_SOCKET_CONNECTED);
            while (!SocketClientTest.this.isFinishing()) {
                String msg = mBufferedReader.readLine();
                System.out.println("service:" + msg);
                if (msg != null) {
                    mhandler.obtainMessage(MESAGE_RECEIVE_NEW_MSG, msg).sendToTarget();
                }
            }

            if (mBufferedReader != null) {
                mBufferedReader.close();
            }

            if (mPrintWriter != null) {
                mPrintWriter.close();
            }

            if (mclientSocket != null) {
                mclientSocket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

}
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
以上就socket的跨进程通讯的全部代码,其实socket不仅可跨进程通讯,也可以进行网络的通讯,只要ip彼此可见。
以上6种方式都可以跨进程通讯各有什么优缺点适应什么场景呢?
名称优点缺点使用场景
Bundle简单易用名只能传输Bundle支持的类型的数据四大组件间的进程间的通讯
AIDL功能强大使用稍微有点复杂,需要处理好线程同步一对多通信且有RPC(远程方法调用)需求
Messenger功能一般,支持一对多串行通信, 支持实时通信不能很好的处理高并发的情形,不支持RPC,数据通过
Message进行传输,因此只能传输Bundle支持的数据
类型
低并发的一对多即时通讯,无RPC需求,或则无须
返回结果的RPC通讯
ContenProvider在数据源访问方面功能强大, 支持一对多并发数
据共享,可通过Call方法扩展其他操作
可以理解为受约束的AIDL,主要提供数据源的CRUD
操作
一对多的进程间的数据共享
Socket功能强大,可以通过网络传输字节流,支持一对
多的实时通讯
实现细节稍微有点繁琐,不支持RPC网络数据交换

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值