java是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由Sun Microsystems公司于1995年5月推出的Java程序设计语言和Java平台(即JavaEE, JavaME, JavaSE)的总称。本站提供基于Java框架struts,spring,hibernate等的桌面应用、web交互及移动终端的开发技巧与资料

保持永久学习的心态,将成就一个优秀的你,来 继续搞起java知识。

第一部分:rxjava 的操作符

(1).just(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10);

将传入的参数一次发送出来。

(2).from(iterable);

将传入的数组或者iterable拆分成具体的对象之后,一次发出来 。

(3).flatMap(func)

将解释它之前,先看一段代码

private void test(){
      List<Student> list = new ArrayList<SiyActivity.Student>();
      list.add(new Student("张三丰", new String[]{"a","b","c","d","e"}));
      list.add(new Student("Tobby", new String[]{"1","2","3"}));
      list.add(new Student("Corey", new String[]{"哈哈","嘿嘿","呲呲","默默","讷讷","enene"}));
      
      Observable.from(list)
      .flatMap(new Func1<Student, Observable<String>>() {
         @Override
         public Observable<String> call(Student arg0) {
            // TODO Auto-generated method stub
            return Observable.from(arg0.curors);
         }
      })
      .subscribe(new Action1<String>() {
         @Override
         public void call(String arg0) {
            Log.d("TAG", "cursors:"+arg0);
         }
      });
   }

我们在通过from传入了一个学生的List,然后我们输出了每个学生所对应的课程,然而我们并没有使用for循环去遍历每

个学生的课程数组一个一个的输出,而是使用了flatMap使每一个学生的课程创建成了一个Observable然后交给Subsc

riber去处理。这就是flatMap的作用,不知道这样有没有很好的解释flatMap的用法。

(4).filter(predicate)

如果对于上面的代码,我们只想输出我们要求的课程名称(如a,b,1,3),这就会用到filter操作符了,filter()输出和输

入相同的元素,并且会过滤掉那些不满足检查条件的。

source.filter(new Func1<String, Boolean>() {
      @Override 
      public Boolean call(String arg0) { 
         return arg0.matches("[a13b]"); 
         }
    });

(5).take(count)上面的操作会输出4个结果,但是我现在只想输出满足我结果的3个名称,这样我就会使用take操作符,take(3)就行了

(6).doOnNext(onNext)

doOnNext()允许我们在每次输出一个元素之前做一些额外的事情。

(7).mergeWith(t1)

将两个或更多同类型的 Observable可以合并到一起去创建一个 Observable。

(8).zipWith(other, zipFunction)

将other与source进行合并返回,并且返回的个数由最小的那个指定

source .zipWith(Observable.range(10, 4), new Func2<String, Integer, String>() {
         @Override
         public String call(String arg0, Integer arg1) {
            Log.d("TAG", "zipwith:"+arg1);
            return arg0;
         }
      })
      .zipWith(list, new Func2<String, Student, String>() {
         @Override
         public String call(String arg0, Student arg1) {
            // TODO Auto-generated method stub
            return arg0+arg1.name;
         }
      })

(9).repeatWhen(notificationHandler)接收到.onCompleted()事件后触发Func1中的call方法,但是这样有什么用呢?关键是看Func1的输入参数和返回参

数,Func1, Observable>() 接收一个Observable 返回有一个Ob

servable,这样我们就能在事件发送完了之后重新再发送一次,这样我们就能简单的实现轮询数据。

source.repeatWhen(new Func1<Observable<? extends  Void>, Observable<?>>() {
         @Override
         public Observable<?> call(Observable<? extends Void> arg0) {
            Log.d("TAG", "repeatWhen");
            return arg0.delay(5, TimeUnit.SECONDS);
         }
      })

每隔5秒轮询一次。(10).retryWhen(notificationHandler)

接收到.onError()事件后触发Func1中的call方法,这个操作符其实同上面的操作符相似,只是触发的条件不一样,但是我们看retryWhen的Func1, Observable>()的参数,接收的是一个Observa

ble返回一个Observable,这样又能干什么呢?看下面的一段代码:

source.retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() {
         @Override
         public Observable<?> call(Observable<? extends Throwable> arg0) {
            return arg0.zipWith(Observable.range(1, 3), new Func2<Throwable, Integer, Object>() {
               @Override
               public Object call(Throwable arg0, Integer arg1) {
                  Log.d("TAG", "exception:"+arg0);
                  if (arg0 instanceof IOException) {
                     return arg1;
                  }else{
                     return Observable.error(arg0);
                  }
               }
            }).flatMap(new Func1<Object, Observable<? extends Object>>() {
               @Override
               public Observable<? extends Object> call(Object arg0) {
                  if (arg0 instanceof Integer) {
                     return Observable.timer((long)Math.pow(2, (Integer)arg0), TimeUnit.SECONDS);
                  }else{
                     return Observable.error((Throwable)arg0);
                  }
               }
            });
         }})

当发生IOException的时候,每隔2^arg0秒重新发送一次事件,一共重新发送3次,如果不是IOException则直接onError()。

第二部分:Android 跨进程通信

个人认为Android 的跨进程通信方式有5种,分别为:访问他应用的Activity、接收其他应用的广播、访问其它应用的

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

(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

2,定义一个访问协议

3,设置默认分类

客户端:只要按照对应的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老师报错的。

好了先写这里吧!

rxjava跨进程通信Android服务AIDL

因为水平有限,难免有疏忽或者不准确的地方,希望大家能够直接指出来,我会及时改正。一切为了知识的分享。

后续会有更多的精彩的内容分享给大家。