乐趣区

关于android:Android中的IPC进程通信方式第二篇

本文系转载文章,浏览原文可获取源码,文章开端有原文链接

ps:本文讲的是 应用 Messenger 进行过程间通信,demo 是用 kotlin 语言写的

1、应用 Messenger

Messenger 能够了解为信使,它能够在不同过程中传递 Message 对象,个别它是在客户端过程和服务器端过程通信,当咱们在客户端发送一个 Message 给服务端时,在服务端的 Handler 中会接管到客户端的音讯,而后进行对应的解决,解决实现后,再将后果等数据封装成 Message,发送给客户端,客户端的 Handler 中会接管到解决的后果。

咱们在写 Messenger 过程间通信的时候不须要写 AIDL 文件,因为 Messenger 封装了 AIDL,咱们这边先不剖析源码,先写 demo 演示,而后再剖析源码。

上面咱们举个例子:

(1)新建一个 kotlin 类 MyService 并继承于 Service,它的包名是 com.xe.demo.ipcdemo2.ipcserver:

class MyService: Service() {

var mHandler: MessengerServiceHandler? = null;
var TAG: String  = "MyService";
var num: Int = 0
var mServiceMesstenger: Messenger? = null;
override fun onBind(intent: Intent?): IBinder {return mServiceMesstenger!!.binder}

override fun onCreate() {super.onCreate()
    mHandler = MessengerServiceHandler()
    mServiceMesstenger = Messenger(mHandler)
}

inner class MessengerServiceHandler: Handler() {override fun handleMessage(msg: Message?) {super.handleMessage(msg)
        if (msg!!.what == 1) {
            num++
            var content: String = msg!!.data.getString("msg")
            Log.d(TAG,content)
            var clientMessenger: Messenger = msg.replyTo
            var message: Message  = Message.obtain(null,2)
            var replyContent: String = "发送给客户端" + num + "条音讯"
            var bundle: Bundle = Bundle()
            bundle.putString("replyContent",replyContent)
            message.setData(bundle);
            try {clientMessenger.send(message);
            } catch (e: RemoteException) {e.printStackTrace()
            }
        }
    }

}

override fun onDestroy() {super.onDestroy()
    if (mHandler != null) {mHandler!!.removeCallbacksAndMessages(null)
    }
}

}

(2)在 AndroidManifest.xml 文件配置一下,开一下多过程:

<service android:name=”com.xe.demo.ipcdemo2.ipcserver.MyService”

        android:process=":remote">

</service>

(3)新建一个 kotlin 类 MainActivity 并继承于 AppCompatActivity,它包名为:com.xe.demo.ipcdemo2.ipcdemo2

class MainActivity: AppCompatActivity() {

var mTv: TextView? = null
var mMyServiceConnection: MyServiceConnection? = null
var mMessengerClientHandler: MessengerClientHandler? = null
var mClientMesstenger: Messenger? = null
var mMessenger: Messenger? = null
var num: Int = 0
inner class MyServiceConnection: ServiceConnection {override fun onServiceDisconnected(name: ComponentName?) { }

    override fun onServiceConnected(name: ComponentName?, service: IBinder?) {mMessenger = Messenger(service)
    }

}
inner class MessengerClientHandler: Handler() {override fun handleMessage(msg: Message?) {super.handleMessage(msg)
        if (msg!!.what == 2) {var fromServiceContent: String = msg.data.getString("replyContent");
            mTv!!.setText(fromServiceContent)
        }
    }
}
override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    mTv = findViewById(R.id.tv);
    mMyServiceConnection = MyServiceConnection()
    mMessengerClientHandler = MessengerClientHandler()
    mClientMesstenger = Messenger(mMessengerClientHandler)
    bindService()}
fun bindService() {var intent: Intent = Intent(this, MyService::class.java)
    bindService(intent,mMyServiceConnection, Context.BIND_AUTO_CREATE);
}

fun onClick(v: View) {sendMessage()
}

fun sendMessage() {
    num++
    var message: Message = Message.obtain(null,1)
    var bundle: Bundle = Bundle()
    bundle.putCharSequence("msg","这是客户端发送给服务器端的第" + num + "条音讯")
    message.data = bundle
    message.replyTo = mClientMesstenger;
    try {mMessenger!!.send(message);
    } catch (e: RemoteException) {e.printStackTrace();
    }
}

}

(4)新建一个 xml 文件 activity_main:

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.xe.demo.ipcdemo2.ipcdemo2.MainActivity">
<Button
    android:layout_width="match_parent"
    android:text="发送音讯给客户端"
    android:onClick="onClick"
    android:layout_height="wrap_content" />

<TextView
    android:id="@+id/tv"
    android:layout_width="match_parent"
    android:gravity="center"
    android:layout_height="wrap_content" />

</LinearLayout>

程序一开始运行时,显示如下界面:

图片

点击“发送音讯给客户端”按钮后,界面变动如下所示:

图片

随后日志打印如下所示:

图片

到这里,咱们总结一下,这里开启多过程是胜利了的,至于如何查看多过程的过程名,能够看 Android 中的 IPC 过程通信形式第一篇这篇文章;首先客户端这边的 MainActivity 类调用 bindService(intent,mMyServiceConnection, Context.BIND_AUTO_CREATE) 办法来启动服务,intent 蕴含了指标服务 MyService,mMyServiceConnection 则是 ServiceConnection 类型的对象;连贯胜利后 MyService 的 onBind 办法就会返回 Messenger 的 Binder 对象,客户端的 ServiceConnection 实现类从 onServiceConnected 办法中拿到回调的 IBinder 类型的对象 service,而后通过 service 作为参数去结构一个 Messenger 类型的对象 mMessenger,这个时候的 mMessenger 是服务 MyService 的 mMessenger;咱们再创立一个 Messenger 类型的对象 mClientMesstenger,这个 mClientMesstenger 是属于客户端的,当咱们客户端用 mMessenger 发送数据给服务的时候,顺便把 mClientMesstenger 传送过来,这样服务就能用 mClientMesstenger 发送数据给客户端了。

2、源码剖析

咱们来看服务 MyService 的 onBind 办法

override fun onBind(intent: Intent?): IBinder {

    return mServiceMesstenger!!.binder

}

再点 mServiceMesstenger!!.binder 进去看看,其实它是调用了 Messenger 的 getBinder 办法

public IBinder getBinder() {

    return mTarget.asBinder();

}

mTarget 是 IMessenger 接口,是通过后面咱们写的 MyService 中的 onCreate 办法结构进去的,如下所示

override fun onCreate() {

    super.onCreate()
    mHandler = MessengerServiceHandler()
    mServiceMesstenger = Messenger(mHandler)

}

点击 Handler 为参数的 Messenger 结构器,发现是 Handler 对象的 getIMessenger 办法返回

public Messenger(Handler target) {

    mTarget = target.getIMessenger();

}

咱们查看 Handler 的 getIMessenger 办法

final IMessenger getIMessenger() {

    synchronized (mQueue) {if (mMessenger != null) {return mMessenger;}
        mMessenger = new MessengerImpl();
        return mMessenger;
    }

}

点击 MessengerImpl 类代码往下看

private final class MessengerImpl extends IMessenger.Stub {

    public void send(Message msg) {msg.sendingUid = Binder.getCallingUid();
        Handler.this.sendMessage(msg);
    }

}

从 IMessenger.Stub 这里能够看出应用 AIDL,所以 Messenter 封装了 AIDL。

咱们看一下客户端中 ServiceConnection 的实现类中 onServiceConnected 办法是怎么拿到 Messenter 对象的

override fun onServiceConnected(name: ComponentName?, service: IBinder?) {

        mMessenger = Messenger(service)

}

点击进去 Messenter 的结构器看看

public Messenger(IBinder target) {

    mTarget = IMessenger.Stub.asInterface(target);

}

从客户端这里能够看出,创立一个 Messenter 应用 IMessenger.Stub.asInterface(target) 拿到接口实例进行调用,这里它结构 Messenter 对象用 IBinder 作为参数,它的底层也是用 AIDL 来实现的,这里客户端 mMessenter 和服务端的 mServiceMesstenger 并非是同一个对象,它们可能通信,是因为它们能拿到同一个对象 Binder。

退出移动版