上篇文章中我们谈到了,Service的远程沟通,既当Activity和Service不在一个进程中,它们之间是怎么相互通信的,不过只是停留在原理层面,今天傻蛋写了一个测试程序来进一步说明远程沟通机制。
Android框架的IPC沟通其实是依赖单一的IBinder接口,当Activity端呼叫IBinder接口的transact()函数时,就会透过IPC机制来呼叫远端的onTransact()函数。当调用transact函数之后,Android框架会根据线程的同步机制,等待远端的onTransact()函数执行完毕 并且返回,才继续向下面继续执行。傻蛋画了副图来进一步说明这个过程。
1. JavaBBinder是Android系统底层提供的类,其实它是个代理(代理模式),同时实现了IBinder接口,这样它onTransact()函数就能够调用myBinder的onTransact()函数
2. 当RemoteServiceTransactActivity需要夸进程来执行JavaBBinder的对象时,Android框架从RemoteServiceTransact所在的进程中启动一个线程Thread X来配合Thread A的执行,这样就变成进程内的通信了。
3. 通过这种远程代理的方式,使用者就会感觉到好像是在本地线程中执行程序一样了。
运行结果如下:
从结果我们可以看出Activity运行的线程名是main,Service运行的线程名也是main,不过和前面Activity的那个main不是一个,为了证明这一点我把它改名为main-changed,Binder所运行的线程名为Binder Thread #2 ,用来配合Activity主线程的远程调用。
测试代码如下:
- /**
- * RemoteMusicService.java
- * com.androidtest.service.mediaplayer
- *
- * Function: TODO
- *
- * ver date author
- * ──────────────────────────────────
- * 2011-5-19 Leon
- *
- * Copyright (c) 2011, TNT All Rights Reserved.
- */
- package com.androidtest.service;
- import com.androidtest.R;
- import com.androidtest.parcelable.ParcelableObject;
- import android.app.Service;
- import android.content.Intent;
- import android.media.MediaPlayer;
- import android.os.Binder;
- import android.os.IBinder;
- import android.os.Parcel;
- import android.os.Parcelable;
- import android.os.RemoteException;
- import android.util.Log;
- /**
- * ClassName:RemoteMusicService
- * Function: TODO ADD FUNCTION
- * Reason: TODO ADD REASON
- *
- * @author Leon
- * @version
- * @since Ver 1.1
- * @Date 2011-5-19
- */
- public class RemoteServiceTransact extends Service {
- private IBinder mBinder = null ;
- private String replyString;
- @Override
- public void onCreate() {
- // TODO Auto-generated method stub
- super.onCreate();
- mBinder = new myBinder();
- Thread.currentThread().setName("Service Thread Name : " +
- Thread.currentThread().getName()+"-chenaged");
- }
- @Override
- public IBinder onBind(Intent intent) {
- // TODO Auto-generated method stub
- replyString = Thread.currentThread().getName();
- return mBinder;
- }
- public class myBinder extends Binder{
- @Override
- protected boolean onTransact(int code, Parcel data, Parcel reply,
- int flags) throws RemoteException {
- // TODO Auto-generated method stub
- reply.writeString(replyString + " Binder Thread is :" + Thread.currentThread().getName());
- return true;
- }
- }
- }
- /**
- * RemoteServiceTransactActivity.java
- * com.androidtest.service
- *
- * Function: TODO
- *
- * ver date author
- * ──────────────────────────────────
- * 2011-6-21 Leon
- *
- * Copyright (c) 2011, TNT All Rights Reserved.
- */
- package com.androidtest.service;
- import com.androidtest.service.mediaplayer.IMusicService;
- import android.app.Activity;
- import android.content.ComponentName;
- import android.content.Context;
- import android.content.Intent;
- import android.content.ServiceConnection;
- import android.os.Bundle;
- import android.os.IBinder;
- import android.os.Parcel;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
- import android.widget.LinearLayout;
- import android.widget.TextView;
- /**
- * ClassName:RemoteServiceTransactActivity
- * Function: TODO ADD FUNCTION
- * Reason: TODO ADD REASON
- *
- * @author Leon
- * @version
- * @since Ver 1.1
- * @Date 2011-6-21
- */
- public class RemoteServiceTransactActivity extends Activity {
- private static final String TAG= RemoteServiceTransactActivity.class.getSimpleName();
- private final int WC=LinearLayout.LayoutParams.WRAP_CONTENT;
- private final int WP=LinearLayout.LayoutParams.FILL_PARENT;
- private Button buttonRunService ;
- private TextView textView ;
- private IBinder iBinder;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onCreate(savedInstanceState);
- LinearLayout layout=new LinearLayout(this);
- layout.setOrientation(LinearLayout.VERTICAL);
- this.setTitle("Test Run Service..");
- //定义Button
- buttonRunService=new Button(this);
- buttonRunService.setId(1);
- buttonRunService.setText("Run Service");
- buttonRunService.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- Parcel sendParcel = Parcel.obtain();
- Parcel replyParcel =Parcel.obtain();
- try{
- iBinder.transact(2, sendParcel, replyParcel, 0);
- //先打印出Activity的主线程名 然后Service的主线程名更名然后返回,说明Service运行在不同
- //的进程中
- textView.setText("Activity Thread Name is :" +Thread.currentThread().getName()
- +" and "+replyParcel.readString());
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- });
- //定义TextView
- textView = new TextView(this);
- textView.setText("Ready....");
- //加入到Layout中
- layout.addView(buttonRunService);
- layout.addView(textView);
- this.setContentView(layout);
- this.bindService(new Intent("com.androidtest.service.RemoteServiceTransact")
- , myServiceConnection, Context.BIND_AUTO_CREATE);
- }
- private ServiceConnection myServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder binder) {
- iBinder=binder;
- Log.d(TAG, " onServiceConnected");
- }
- @Override
- public void onServiceDisconnected(ComponentName name) {
- Log.d(TAG, " onServiceDisconnected");
- }
- };
- }
同时在Android Manifest中需要这样来定义这个Service,以便它能够在不同的进程中运行。
- <service android:enabled="true" android:process=":remote"
- android:name=".service.RemoteServiceTransact">
- <intent-filter>
- <action android:name="com.androidtest.service.RemoteServiceTransact" />
- </intent-filter>
- </service>
本文转自 最牛傻蛋 51CTO博客,原文链接:http://blog.51cto.com/zuiniuwang/718292,如需转载请自行联系原作者