Activity与Service数据交互的几种方式

2018-01-11  本文已影响0人  AndrLin

扩展Binder

在绑定服务后,会回调onBind方法,此方法会返回IBinder。我们可以通过扩展自己的Binder来达到自己的目的。下面直接上代码:

class BinderService : Service() {
    companion object {
        val TAG = "BinderService"
    }

    private val mBinder: IBinder = TestBinder()

    override fun onCreate() {
        Log.d(TAG, "onCreate")
        super.onCreate()
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.d(TAG, "onStartCommand")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onBind(intent: Intent?): IBinder? {
        Log.d(TAG, "onBind")
        return mBinder
    }

    override fun onUnbind(intent: Intent?): Boolean {
        Log.d(TAG, "onUnbind")
        return true
    }

    override fun onRebind(intent: Intent?) {
        Log.d(TAG, "onRebind")
        super.onRebind(intent)
    }

    override fun onDestroy() {
        Log.d(TAG, "onDestroy")
        super.onDestroy()
    }

    fun toDoAnything() {
        Log.d(TAG, "toDoAnyThing")
    }

    inner class TestBinder : Binder() {
        fun getService() : BinderService {
            return this@BinderService
        }
    }
}

我们在TestService内部创建一个TestBinder,并在其中提供一个获取TestService实例的方法。然后在TestService中定义一个toDoAnything()方法。再来看下Activity的使用:

class BinderActivity : AppCompatActivity() {

    private var serviceIntent: Intent? = null

    private var isBindService = false

    private var mBinder: BinderService.TestBinder? = null
    private var mService: BinderService? = null

    private val serviceConnection: ServiceConnection = object : ServiceConnection {
        override fun onServiceDisconnected(name: ComponentName?) {
            isBindService = false
            mBinder = null
            mService = null
        }

        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            isBindService = true
            mBinder = service as BinderService.TestBinder?
            mService = mBinder?.getService()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_service)

        serviceIntent = Intent(this, BinderService::class.java)

        btnBind.setOnClickListener {
            bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE)
        }

        btnUnBind.setOnClickListener {
            unbindService(serviceConnection)
        }

        btn.setOnClickListener {
            if (isBindService) {
                mService?.toDoAnything()
            }
        }
    }

    override fun onDestroy() {
        if (isBindService)
            unbindService(serviceConnection)
        super.onDestroy()

    }
}

代码很简单,主要是利用bindService时,传递的ServiceConnection。在其onServiceConnected()方法中获取Binder,在通过Binder获取到TestService实例,然后就可以调用TestService中相应的方法了。

我们在清单文件中将TestService设置为在单独的进程中运行:

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

再次运行程序,并进行相应的操作,你会发现应用程序会挂掉。没错,扩展Binder的方式,只适用于本应用程序内适用,即组件和Service在同一个进程中。

那么有没有方法可以进行进程间的交互呢?别着急,下面的方式就可以了。


使用Messenger

如需让服务与远程进程通信,则可使用 Messenger 为您的服务提供接口。

以下是 Messenger 的使用方法摘要:

这样,客户端并没有调用服务的“方法”。而客户端传递的“消息”(Message 对象)是服务在其 Handler 中接收的。

下面来看下具体的使用:

class MessengerService : Service() {

    companion object {
        private val TAG = "MessengerService"
        val MSG_SAY_HELLO = 1
        val MSG_TO_CLIENT = 2
        val EXTRA_REPLY_STR_TO_CLIENT = "extra_reply_str_to_client"
        val EXTRA_SEND_STR_TO_SERVICE = "extra_send_str_to_service"

        private class ServiceHandler(messengerService: MessengerService) : Handler() {

            private var mReference: WeakReference<MessengerService> = WeakReference(messengerService)

            override fun handleMessage(msg: Message) {
                val service: MessengerService? = mReference.get()
                service?.let {
                    when (msg.what) {
                        MSG_SAY_HELLO -> {
                            Log.d(TAG, "process id is ${Process.myPid()}, Hello!")
                            Toast.makeText(service.applicationContext, "hello!", Toast.LENGTH_SHORT).show()

                            val messenger: Messenger = msg.replyTo // 获取用于回复的Messenger
                            val serviceMessage: Message = Message.obtain(null, MSG_TO_CLIENT)

                            val bundle = Bundle()
                            bundle.putString(EXTRA_REPLY_STR_TO_CLIENT, "I have received your message")
                            serviceMessage.data = bundle

                            messenger.send(serviceMessage)
                        }
                        else -> super.handleMessage(msg)
                    }
                }
            }
        }
    }

    private val mMessenger: Messenger = Messenger(ServiceHandler(this))

    override fun onBind(intent: Intent?): IBinder? {
        Log.d(TAG, "onBind")
        return mMessenger.binder
    }

}
class MessengerActivity : AppCompatActivity() {

    companion object {
        // 此handler用于接收Service的回复信息
        private class ClientHandler(messengerActivity: MessengerActivity) : Handler() {

            private val mReference: WeakReference<MessengerActivity> = WeakReference(messengerActivity)

            override fun handleMessage(msg: Message) {
                val activity = mReference.get()
                activity?.let {
                    when(msg.what) {
                        MessengerService.MSG_TO_CLIENT -> {
                            Log.d(activity.localClassName, "${msg.data[MessengerService.EXTRA_REPLY_STR_TO_CLIENT]}, process id is ${Process.myPid()}")
                        }
                        else -> super.handleMessage(msg)
                    }
                }
            }
        }
    }

    private var serviceIntent: Intent? = null
    private var isBindService = false
    private var mServiceMessenger: Messenger? = null
    private var mClientMessenger: Messenger = Messenger(ClientHandler(this))

    private val serviceConnection: ServiceConnection = object : ServiceConnection {
        override fun onServiceDisconnected(name: ComponentName?) {
            isBindService = false
            mServiceMessenger = null
        }

        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            isBindService = true
            mServiceMessenger = Messenger(service) // 获取Service的Messenger
            Log.d(localClassName, "ServiceConnection onServiceConnected()")
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_service)

        serviceIntent = Intent(this, MessengerService::class.java)
        btnStart.setOnClickListener {
            startService(serviceIntent)
        }

        btnStop.setOnClickListener {
            stopService(serviceIntent)
        }

        btnBind.setOnClickListener {
            bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE)
        }

        btnUnBind.setOnClickListener {
            unbindService(serviceConnection)
        }

        btn.setOnClickListener {
            Log.d("MessengerActivity", "process id is ${Process.myPid()}")
            if (isBindService)
                sayHello()
        }
    }

    private fun sayHello() {
        val message: Message = Message.obtain(null, MessengerService.MSG_SAY_HELLO)
        val bundle = Bundle()
        bundle.putString(MessengerService.EXTRA_SEND_STR_TO_SERVICE, "hello, this is client.")
        message.data = bundle

        message.replyTo = mClientMessenger // 设置用于回复消息的Messenger
        
        mServiceMessenger?.send(message)
    }

    override fun onDestroy() {
        if (isBindService)
            unbindService(serviceConnection)
        super.onDestroy()

    }

}

在向服务端发送信息时,通过Message.replyTo将客户端的Messenger传递给服务端。服务端接收到消息后,通过Message.replyTo获取客户端的Messenger,然后用此向客户端发送消息。


使用AIDL

AIDL:Android Interface Definition Language,即Android接口定义语言;用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。

使用流程

支持的数据类型

需要注意的事项

// Friend.aidl
package com.demo.service.aidl.bean;

parcelable Friend;

in:代表数据为输入型(客户端提供数据,服务端获取。服务端改变数据,不会影响客户端测数据)

out:代表数据为输出型(数据由服务端提供输出给客户端。客户端给的初始值,服务端并不会获取到;服务端改变数据,客户端所拥有的数据也会随之改变)

inout:代表数据为输入输出型(结合了inout的特性,客户端提供的数据,服务端可以获取到;服务端改变数据,客户端数据也会随之改变)

具体实例

下面用一个简单的小例子来演示如何使用AIDL:演示一个朋友群,添加了新朋友后,通知其他人有新的朋友被添加了。

package com.demo.service.aidl.bean

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

class Friend(var name: String, var isNew: Boolean) : Parcelable {
    constructor(source: Parcel) : this(
            source.readString(),
            1 == source.readInt()
    )

    override fun describeContents() = 0

    override fun writeToParcel(dest: Parcel, flags: Int) = with(dest) {
        writeString(name)
        writeInt((if (isNew) 1 else 0))
    }

    companion object {
        @JvmField
        val CREATOR: Parcelable.Creator<Friend> = object : Parcelable.Creator<Friend> {
            override fun createFromParcel(source: Parcel): Friend = Friend(source)
            override fun newArray(size: Int): Array<Friend?> = arrayOfNulls(size)
        }
    }
}
// Friend.aidl
package com.demo.service.aidl.bean;

parcelable Friend;
// IOnNewFriendAddListener.aidl
package com.demo.service.aidl;

import com.demo.service.aidl.bean.Friend;

interface IOnNewFriendAddedListener {
    void onNewFriendAdded(in Friend newFriend);
}
// IFriendService.aidl
package com.demo.service.aidl;

import com.demo.service.aidl.bean.Friend;
import com.demo.service.aidl.IOnNewFriendAddedListener;

interface IFriendService {

    void addFriend(in Friend friend);

    void registerListener(in IOnNewFriendAddedListener listener);

    void unRegisterListener(in IOnNewFriendAddedListener listener);
}

class FriendGroupService : Service() {
    companion object {
        val TAG = "FriendGroupService"
    }

    private val friendList: CopyOnWriteArrayList<Friend> by lazy {
        CopyOnWriteArrayList<Friend>()
    }
    private val callbackList: RemoteCallbackList<IOnNewFriendAddedListener> by lazy {
        RemoteCallbackList<IOnNewFriendAddedListener>()
    }

    private val mBind = object : IFriendService.Stub() {
        override fun addFriend(friend: Friend?) {
            friend?.let {
                Log.d(TAG, "Friend is added")
                friendList.add(friend)
                if (friend.isNew) {
                    val num = callbackList.beginBroadcast()

                    for (i in 0 until num) {
                        val callback = callbackList.getBroadcastItem(i)
                        callback?.let { callback.onNewFriendAdded(friend) }
                    }

                    callbackList.finishBroadcast()
                }
            }
        }

        override fun registerListener(listener: IOnNewFriendAddedListener?) {
            listener?.let { callbackList.register(listener) }
        }

        override fun unRegisterListener(listener: IOnNewFriendAddedListener?) {
            listener?.let { callbackList.unregister(listener) }
        }

    }

    override fun onBind(intent: Intent?): IBinder? {
        return mBind
    }
}
class ClientActivity : AppCompatActivity() {

    private var mService: IFriendService? = null
    private var isBindService = false
    private var serviceIntent: Intent? = null
    private var num: Int = 0

    private val callback = object : IOnNewFriendAddedListener.Stub() {
        override fun onNewFriendAdded(newFriend: Friend?) {
            newFriend?.let { Log.d(localClassName, "Friend is added, Friend's name is ${newFriend.name}") }
        }

    }

    private val serviceConnection: ServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            mService = IFriendService.Stub.asInterface(service)
            mService?.let {
                mService!!.registerListener(callback)
            }
            isBindService = true
        }

        override fun onServiceDisconnected(name: ComponentName?) {
            isBindService = false
            mService = null
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_service)

        serviceIntent = Intent(this, FriendGroupService::class.java)
        btnStart.setOnClickListener {
            startService(serviceIntent)
        }

        btnStop.setOnClickListener {
            stopService(serviceIntent)
        }

        btnBind.setOnClickListener {
            bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE)
        }

        btnUnBind.setOnClickListener {
            unbindService(serviceConnection)
        }
        
        btn.setOnClickListener {
            addFriend()
        }
    }

    private fun addFriend() {
        if (isBindService) {
            mService?.let {
                num++
                val friend = Friend("Friend$num", true)
                mService!!.addFriend(friend)
            }
        }
    }
    
    override fun onDestroy() {
        mService?.let {
            if (mService!!.asBinder().isBinderAlive) {
                try {
                    mService!!.unRegisterListener(callback)
                } catch (e: RemoteException) {
                    
                }
            }
        }
        if (isBindService)
            unbindService(serviceConnection)
        super.onDestroy()
    }
}

Log输出结果:

com.demo.service:remote D/FriendGroupService: Friend is added
com.demo.service D/aidl.ClientActivity: Friend is added, Friend's name is Friend1
com.demo.service:remote D/FriendGroupService: Friend is added
com.demo.service D/aidl.ClientActivity: Friend is added, Friend's name is Friend2
com.demo.service:remote D/FriendGroupService: Friend is added
com.demo.service D/aidl.ClientActivity: Friend is added, Friend's name is Friend3
com.demo.service:remote D/FriendGroupService: Friend is added
com.demo.service D/aidl.ClientActivity: Friend is added, Friend's name is Friend4


前往Github查看完整代码


上一篇 下一篇

猜你喜欢

热点阅读