Android-远程Service

http://blog.csdn.net/guolin_blog/article/details/9797169java

http://www.jianshu.com/p/eeb2bd59853fandroid

 

将一个普通的Service转换成远程Service其实很是简单,只须要在注册Service的时候将它的android:process属性指定成:remote就能够了,代码以下所示:app

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

远程service可让service在另外一个进程运行,因此能够执行阻塞进程的操做ide

 

远程Service这么好用,干脆之后咱们把全部的Service都转换成远程Service吧,还免得再开启线程了。其实否则,远程Service非但很差用,甚至能够称得上是较为难用。通常状况下若是能够不使用远程Service,就尽可能不要使用它。ui

 

下面就来看一下它的弊端吧,首先将MyService的onCreate()方法中让线程睡眠的代码去除掉,而后从新运行程序,并点击一下Bind Service按钮,你会发现程序崩溃了!为何点击Start Service按钮程序就不会崩溃,而点击Bind Service按钮就会崩溃呢?这是因为在Bind Service按钮的点击事件里面咱们会让MainActivity和MyService创建关联,可是目前MyService已是一个远程Service了,Activity和Service运行在两个不一样的进程当中,这时就不能再使用传统的创建关联的方式,程序也就崩溃了。this

 

那么如何才能让Activity与一个远程Service创建关联呢?这就要使用AIDL来进行跨进程通讯了(IPC)。spa

 

调用者和Service若是不在一个进程内, 就须要使用android中的远程Service调用机制.
android使用AIDL定义进程间的通讯接口. AIDL的语法与java接口相似, 须要注意如下几点:.net

    1. AIDL文件必须以.aidl做为后缀名.
    2. AIDL接口中用到的数据类型, 除了基本类型, String, List, Map, CharSequence以外, 其余类型都须要导包, 即便两种在同一个包内. List和Map中的元素类型必须是AIDL支持的类型.
    3. 接口名须要和文件名相同.
    4. 方法的参数或返回值是自定义类型时, 该自定义的类型必须实现了Parcelable接口.
    5. 全部非java基本类型参数都须要加上in, out, inout标记, 以代表参数是输入参数, 输出参数, 仍是输入输出参数.
    6. 接口和方法前不能使用访问修饰符和static, final等修饰.

AIDL实现
1.首先我创建2个app工程,经过aidl实现一个app调用另外一个app的service
目录结构以下:
service提供端app线程

利用aidl调用service的appcode

2.在两个app中都创建一个文件 IPerson.aidl注意 包名 要相同
IPerson.aidl只是一个接口文件,用来aidl交互的,创建好以后在Studio中点Build-->Rebuild会自动建立须要的java文件。

IPerson.aidl代码

package mangues.com.aidl;
interface IPerson {
  String greet(String someone);
}

3.在aidl_service 中创建AIDLService
这个IPerson.Stub 就是经过IPerson.aidl 自动生成的binder 文件,你实现下,而后在onBind()中 return出去就行了,就和Android Service实现和activity交互同样。
代码:

public class AIDLService extends Service {
  private static final String TAG = "AIDLService";

  IPerson.Stub stub = new IPerson.Stub() {
      @Override
      public String greet(String someone) throws RemoteException {
          Log.i(TAG, "greet() called");
          return "hello, " + someone;
      }
  };

  @Override
  public void onCreate() {
      super.onCreate();
      Log.i(TAG, "onCreate() called");
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      Log.i(TAG, "onBind() onStartCommand");
      return super.onStartCommand(intent, flags, startId);

  }

  @Override
  public IBinder onBind(Intent intent) {
      Log.i(TAG, "onBind() called");
      return stub;
  }

  @Override
  public boolean onUnbind(Intent intent) {
      Log.i(TAG, "onUnbind() called");
      return true;
  }

  @Override
  public void onDestroy() {
      super.onDestroy();
      Log.i(TAG, "onDestroy() called");
  }
}

这里为何能够这样写呢?由于Stub其实就是Binder的子类,因此在onBind()方法中能够直接返回Stub的实现。

4.aidl_service MainActivity 中启动这个service
简单点就不写关闭什么的了;

@Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      Intent startIntent = new Intent(this, AIDLService.class);
      startService(startIntent);
  }

在AndroidManifest.xml注册

<service android:name=".AIDLService"
               android:process=":remote">
          <intent-filter>
              <action android:name="android.intent.action.AIDLService" />
              <category android:name="android.intent.category.DEFAULT" />
          </intent-filter>
      </service>

做用就是把这个service暴露出去,让别的APP能够利用
android.intent.action.AIDLService 字段隐形绑定这个service,获取数据。

5.aidl_client 中绑定aidl_service service 获取数据
代码:

public class MainActivity extends AppCompatActivity {
    private IPerson person;
    private ServiceConnection conn = new ServiceConnection() {
       @Override
      public void onServiceConnected(ComponentName name, IBinder service) {
          Log.i("ServiceConnection", "onServiceConnected() called");
          person = IPerson.Stub.asInterface(service);
          String retVal = null;
          try {
              retVal = person.greet("scott");
          } catch (RemoteException e) {
              e.printStackTrace();
          }
          Toast.makeText(MainActivity.this, retVal, Toast.LENGTH_SHORT).show();
      }

      @Override
      public void onServiceDisconnected(ComponentName name) {
          //This is called when the connection with the service has been unexpectedly disconnected,
          //that is, its process crashed. Because it is running in our same process, we should never see this happen.
          Log.i("ServiceConnection", "onServiceDisconnected() called");
      }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      Intent mIntent = new Intent();
      mIntent.setAction("android.intent.action.AIDLService");
      Intent eintent = new Intent(getExplicitIntent(this,mIntent));
      bindService(eintent, conn, Context.BIND_AUTO_CREATE);
  }
  public static Intent getExplicitIntent(Context context, Intent implicitIntent) {
      // Retrieve all services that can match the given intent
      PackageManager pm = context.getPackageManager();
      List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
      // Make sure only one match was found
      if (resolveInfo == null || resolveInfo.size() != 1) {
          return null;
      }
      // Get component info and create ComponentName
      ResolveInfo serviceInfo = resolveInfo.get(0);
      String packageName = serviceInfo.serviceInfo.packageName;
      String className = serviceInfo.serviceInfo.name;
      ComponentName component = new ComponentName(packageName, className);
      // Create a new intent. Use the old one for extras and such reuse
      Intent explicitIntent = new Intent(implicitIntent);
      // Set the component to be explicit
      explicitIntent.setComponent(component);
      return explicitIntent;
  }
}

 

在上一篇文章中咱们已经知道,若是想要让Activity与Service之间创建关联,须要调用bindService()方法,并将Intent做为参数传递进去,在Intent里指定好要绑定的Service,示例代码以下:

Intent bindIntent = new Intent(this, MyService.class);  
bindService(bindIntent, connection, BIND_AUTO_CREATE);

这里在构建Intent的时候是使用MyService.class来指定要绑定哪个Service的,可是在另外一个应用程序中去绑定Service的时候并无MyService这个类,这时就必须使用到隐式Intent了

 <intent-filter>  
            <action android:name="com.example.servicetest.MyAIDLService"/>  
        </intent-filter>

这就说明,MyService能够响应带有com.example.servicetest.MyAIDLService这个action的Intent。

相关文章
相关标签/搜索