Activity与Service数据交互的几种方式
2018-01-11 19:31
573 查看
扩展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 的使用方法摘要:
服务实现一个 Handler,由其接收来自客户端的每个调用的回调
Handler 用于创建 Messenger 对象(对 Handler 的引用)
Messenger 创建一个 IBinder,服务通过 onBind() 使其返回客户端
客户端使用 IBinder 将 Messenger(引用服务的 Handler)实例化,然后使用后者将 Message 对象发送给服务
服务在其 Handler 中(具体地讲,是在 handleMessage() 方法中)接收每个 Message。
这样,客户端并没有调用服务的“方法”。而客户端传递的“消息”(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的功能。使用流程
创建.aidl文件Android SDK 基于创建的.aidl文件,会生成一个java的接口。此接口有一个Stub的内部抽象类,用于扩展Binder类实现AIDL接口中的方法
实现Service类,并在onBind方法中返回Stub的具体实现
客户端绑定Service,并在onServiceConnected中获取AIDL的具体实现,从而操作AIDL的方法
支持的数据类型
基本数据类型( byte、short、int、long、float、double、boolean、char)String和CharSequence
List:只支持ArrayList,且里面的每个元素都必须是AIDL所支持的数据类型
Map:只支持HashMap,且里面每个元素都必须是AIDL所支持的,包括key和value
Parcelable:实现了Parcelable接口的对象
AIDL:所有的AIDL接口本身也可以在AIDL文件中使用
需要注意的事项
使用实现了Parcelable接口的对象,需要创建相应的AIDL文件。例如Friend.java实现了Parcelable,那么就需要向下面一样,创建Friend.aidl进行声明。它们两的包名需要一致:
// Friend.aidl package com.demo.service.aidl.bean; parcelable Friend;
AIDL中使用Parcelable的对象和AIDL接口,需要使用
import显示导入。
AIDL中除了基本数据类型,其他类型的参数必须标上方向:
in、
out或
inout。
in:代表数据为输入型(客户端提供数据,服务端获取。服务端改变数据,不会影响客户端测数据)
out:代表数据为输出型(数据由服务端提供输出给客户端。客户端给的初始值,服务端并不会获取到;服务端改变数据,客户端所拥有的数据也会随之改变)
inout:代表数据为输入输出型(结合了
in和
out的特性,客户端提供的数据,服务端可以获取到;服务端改变数据,客户端数据也会随之改变)
具体实例
下面用一个简单的小例子来演示如何使用AIDL:演示一个朋友群,添加了新朋友后,通知其他人有新的朋友被添加了。创建
Friend类,并且实现
Parcelable
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文件,注意此文件包名需和
Friend类包名一致
// Friend.aidl package com.demo.service.aidl.bean; parcelable Friend;
创建
aidl的回调接口文件
// IOnNewFriendAddListener.aidl package com.demo.service.aidl; import com.demo.service.aidl.bean.Friend; interface IOnNewFriendAddedListener { void onNewFriendAdded(in Friend newFriend); }
创建
Service需要实现的
aidl文件,在其中编写相应的方法
// 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); }
接下来就是编写
Service,并在
onBind方法中返回
IFriendService.Stub的具体实现
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 } }
在接下来就是在相应组件中实现对
service的绑定,
onServiceConnected中获取
IFriendService,从而使用它进行回调注册,相应方法的使用。
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) { a871 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查看完整代码
相关文章推荐
- Android Service与Activity之间通信的几种方式
- Android Service与Activity之间通信的几种方式
- Android Service与Activity之间通信的几种方式(1)-----通过Binder对象
- 【Android 开发】 : Activity之间传递数据的几种方式
- Android Service与Activity之间通信的几种方式
- Android Service与Activity之间通信的几种方式
- Activity与Service数据交互:Binder、bindService的用法
- Android Service与Activity之间通信的几种方式
- Android Service与Activity之间通信的几种方式
- android 中Service 和activity之间的数据传递的几种方法
- Activity传递数据的几种方式及返回结果
- Service与Activity之间通信的几种方式
- Android Service与Activity之间通信的几种方式
- Android Service与Activity之间通信的几种方式
- 详解Android Service与Activity之间通信的几种方式
- 你一定要知道的几种项目间数据交互方式
- 【学习】Service与Activity之间通信的几种方式
- Android Service与Activity之间通信的几种方式
- Activity传递数据的几种方式及返回结果
- Android Service与Activity之间通信的几种方式