Android四大组件之Activity(2)组件间通信
一、Activity与Activity之间通信
- Intent\Bundle传值
- 成员变量传值
- 类静态变量传值
1、Intent\Bundle传值
- 示例代码:
// MainActivity.kt
const val INTENT_FIELD = "intent\\bundle传值"
const val INTENT_FIELD_RESULT = "intent\\bundle传值result"
const val INTENT_TAG = "Activity与Activity之间传值"
const val REQUEST_CODE = 0x100
const val RESULT_CODE = 0x101
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
hello.setOnClickListener {
// 向MainActivity2发送数据
startActivityForResult(Intent(this@MainActivity, MainActivity2::class.java).apply {
putExtras(Bundle().apply {
putString(INTENT_FIELD, "the value from MainActivity")
})
}, REQUEST_CODE)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when {
requestCode == REQUEST_CODE && resultCode == RESULT_CODE -> data?.run {
// 打印从MainActivity2返回的数据
extras?.getString(INTENT_FIELD_RESULT)?.let {
Log.e(INTENT_TAG, it)
}
}
else -> super.onActivityResult(requestCode, resultCode, data)
}
}
}
// MainActivity2.kt
class MainActivity2 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 打印 MainActivity传递过来的数据
intent?.extras?.getString(INTENT_FIELD)?.apply { Log.e(INTENT_TAG, this) }
hello.setOnClickListener {
setResult(RESULT_CODE, Intent().apply {
putExtras(Bundle().apply {
putString(INTENT_FIELD_RESULT, "the value from MainActivity2")
})
})
finish()
}
}
}
MainActivity
通过startActivityForResult
启动MainActivity2
,同时传递一个Bundle
对象给MainActivity2
,在MainActivity2
中通过getIntent
获取到传递过来的Bundle
,进而得到MainActivity
传递过来的String 数据并打印。
在MainActivity2
中通过setResult
设置需要传递给MainActivity
的Bundle
数据,在MainActivity
的onActivityResult
函数中就可以得到相关的Bundle
数据。
- 运行结果:
2020-04-14 10:32:04.707 6146-6146 E/Activity与Activity之间传值: 类静态变量
2020-04-14 10:32:13.897 6146-6146 E/Activity与Activity之间传值: 修改后的类静态变量
2、全局变量
- 代码示例:
// 定义一个自己的Application,并在AndroidManifest中注册。
class DoItApplication : Application() {
var globalField: String = "全局变量"
}
// MainActivity中onCreate代码:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
(application as DoItApplication).globalField.let {
Log.e(INTENT_TAG, "application.field=$it")
}
hello.setOnClickListener {
(application as DoItApplication).globalField = "修改后的全局变量"
(application as DoItApplication).globalField.let {
Log.e(INTENT_TAG, "application.field=$it")
}
}
}
每一个Android应用都有一个Application
对象,这个Application
会贯穿整个Android应用,在其中定义的变量,它的生命周期也是和整个应用的生命周期一样。
- 运行结果:
2020-04-14 10:16:06.493 5465-5465 E/Activity与Activity之间传值: application.field=全局变量
2020-04-14 10:16:18.617 5465-5465 E/Activity与Activity之间传值: application.field=修改后的全局变量
3、类静态变量
- 示例代码
// MainActivity.kt
const val INTENT_TAG = "Activity与Activity之间传值"
class MainActivity : AppCompatActivity() {
companion object {
var staticField: String = "类静态变量"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
startActivity(Intent(this, MainActivity2::class.java))
hello.setOnClickListener {
// 打印MainActivity2修改后的staticField信息
Log.e(INTENT_TAG, staticField)
}
}
}
// MainActivity2.kt
class MainActivity2 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 打印MainActivity的静态成员变量
Log.e(INTENT_TAG, staticField)
hello.setOnClickListener {
// 修改MainActivity的静态成员变量
staticField = "修改后的类静态变量"
finish()
}
}
}
在MainActivity
中定义了一个伴生变量,它相当于Java中的静态变量,而在MainActivity2
中可以获取此静态变量,并对其进行修改。
- 运行结果:
2020-04-14 10:32:04.707 6146-6146 E/Activity与Activity之间传值: 类静态变量
2020-04-14 10:32:13.897 6146-6146 E/Activity与Activity之间传值: 修改后的类静态变量
二、Activity与Fragment之间通信
1、Activity将数据传递给Fragment
- Bundle
- 直接在Activity中定义方法
(a). Bundle 方法
- 实例代码
// MyFragment .kt
const val NAME = "name"
const val AGE = "age"
class MyFragment : Fragment() {
companion object {
fun create(vararg pairs: Pair<String, *>) = MyFragment().apply { ofArguments(*pairs) }
}
private val name: String by lazy { arguments?.getString(NAME, "") ?: "" }
private val age: Int by lazy { arguments?.getInt(AGE, 18) ?: 18 }
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(R.layout.fragment_main, container, false)
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
hello.text = "name=$name, age=$age"
}
}
// Fragment 扩展函数
fun Fragment.ofArguments(vararg pairs: Pair<String, *>): Fragment = apply {
arguments = Bundle().apply {
pairs.forEach { (name, value) ->
when (value) {
is String -> putString(name, value)
is Int -> putInt(name, value)
is Double -> putDouble(name, value)
is Long -> putLong(name, value)
is Boolean -> putBoolean(name, value)
else -> throw IllegalArgumentException("咱不支持此类型。")
}
}
}
}
// MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
attachFragment()
}
private fun attachFragment() {
val fragment = MyFragment.create(NAME to "代码人", AGE to 20)
val transaction: FragmentTransaction = supportFragmentManager.beginTransaction()
transaction.add(R.id.rootView, fragment).commit()
}
}
通过Fragment
的setArguments(bundle)
实现Activity
想Fragment
传值。
(b). 直接在Activity中定义方法
- 示例代码(对上述代码进行修改)
// MainActivity.kt 增加下面代码
class MainActivity : AppCompatActivity() {
private var name = "小雪"
private var age = 23
fun arguments() = listOf(name, age)
........
}
// MyFragment .kt 修改如下
class MyFragment : Fragment() {
private var showString: String? = null
override fun onAttach(activity: Activity) {
super.onAttach(activity)
if (activity is MainActivity) {
val args = activity.arguments()
if (args.size == 2) {
showString = "name=${args[0]}, age=${args[1]}"
}
}
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
hello.text = "name=$name, age=$age"
hello.setOnClickListener { hello.text = showString }
}
......
}
通过onAttach(activity: Activity)
方法获得activity
实例,直接调用activity
中的方法获得数据。
2、Fragment将数据传递给Activity
接口回调方法
- 操作步骤:
在fragment中定义一个内部回调接口,让activity继承
fragment的onAttach()
中获取实现接口的activity实例
fragment的onDetach()
中activity实例对象释放掉 - 示例代码:
// MyFragment.kt
class MyFragment : Fragment() {
interface FragmentListener { fun process(info: String) }
private var listener: FragmentListener? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(R.layout.fragment_main, container, false)
override fun onAttach(activity: Activity) {
super.onAttach(activity)
if (activity is FragmentListener) { listener = activity }
}
override fun onDetach() {
super.onDetach()
listener = null
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
hello.setOnClickListener { listener?.process("It is ok.") }
}
}
// MainActivity.kt
class MainActivity : AppCompatActivity(), MyFragment.FragmentListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportFragmentManager.beginTransaction().add(R.id.rootView, MyFragment()).commit()
}
override fun process(info: String) {
Log.e("传值", "info=$info")
}
}
三、Activity与Service之间通信
- 绑定服务,利用ServiceConnection类
- 简单通信,利用Intent进行传值
- 定义一个callback接口来监听服务中的进程变化
1、绑定服务,利用ServiceConnection类
- 实例代码:
// MyService.kt
class MyService : Service() {
var data: String = ""
fun setAndPrint(str: String) {
data = str
Log.e("service通信", "data=$data")
}
override fun onBind(intent: Intent?) = MyBind()
inner class MyBind : Binder() {
val data = "无敌最俊朗"
fun info() = "男(名字:${data}),年龄:18"
fun setString(str: String) = setAndPrint(str)
}
}
// MainActivity.kt
class MainActivity : AppCompatActivity(), ServiceConnection {
var binder: MyService.MyBind? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
hello.setOnClickListener { binder?.setString("activity to service") }
}
override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
this.binder = if (binder is MyService.MyBind) binder else null
this.binder?.let {
Log.e("service通信", "service -> data=${it.data}")
Log.e("service通信", "service -> info=${it.info()}")
}
}
override fun onServiceDisconnected(p0: ComponentName?) = Unit
override fun onResume() {
super.onResume()
val intent = Intent(this, MyService::class.java)
bindService(intent, this, Context.BIND_AUTO_CREATE)
}
override fun onPause() {
super.onPause()
unbindService(this)
}
}
// AndrioidManifest.xml
<manifest>
<application>
<service android:name=".MyService" />
</application>
</manifest>
- 运行结果
2020-04-18 E/service通信: service -> data=无敌最俊朗
2020-04-18 E/service通信: service -> info=男(名字:无敌最俊朗),年龄:18
2020-04-18 E/service通信: data=activity to service
Service
的onBind
方法需要返回一个Binder
对象,而这个对象在ServiceConnection.onServiceConnected
中可以获取,从而实现Service
和Activity
之间的通信。
2、简单通信,利用Intent进行传值
- 示例代码
// MyService.kt
const val NAME = "name"
class MyService : Service() {
var data = ""
override fun onBind(intent: Intent?) = Binder()
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
data = intent?.getStringExtra(NAME) ?: ""
printData()
return super.onStartCommand(intent, flags, startId)
}
fun printData() = Log.e("service通信", "data -> $data")
}
// MainActivity.kt
class MainActivity : AppCompatActivity() {
private val serviceIntent by lazy { Intent(this, MyService::class.java) }
private var startService = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
hello.setOnClickListener {
startService = true
serviceIntent.putExtra(NAME, "启动Service.")
startService(serviceIntent)
}
}
override fun onDestroy() {
super.onDestroy()
if (startService) stopService(serviceIntent)
}
}
- 运行结果:
2020-04-18 E/service通信: data -> 启动Service.
startService
时,传入参数intent
可以携带部分参数给Service
,我们可以在Service
的onStartCommand
方法中得到startService
传递过来的intent
数据。
3、定义一个callback接口来监听服务中的进程变化
- 实例代码:
// MyService.kt
class MyService : Service() {
inner class MyBinder : Binder() {
fun getService(): MyService = this@MyService
}
var callback: Callback? = null
private val thread by lazy {
thread(false) {
Thread.sleep(5 * 1000)
callback?.onDataChanged("service.thread已执行.")
}
}
override fun onBind(intent: Intent?): IBinder? = MyBinder().apply {
thread.start() }
}
interface Callback { fun onDataChanged(data: String) }
// MainActivity.kt
class MainActivity : AppCompatActivity(), ServiceConnection {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onResume() {
super.onResume()
bindService(
Intent(this, MyService::class.java),
this, Context.BIND_AUTO_CREATE
)
}
override fun onPause() {
super.onPause()
unbindService(this)
}
private val handler = Handler() {
it.data?.getString("data")?.let {
Log.e("service传值", "service.data -> $it")
}
true
}
private val callback = object : Callback {
override fun onDataChanged(data: String) {
handler.sendMessage(handler.obtainMessage().apply {
setData(Bundle().apply { putString("data", data) })
})
}
}
private var service: MyService? = null
override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
if (binder is MyService.MyBinder) {
service = binder.getService()
service?.callback = callback
}
}
override fun onServiceDisconnected(name: ComponentName?) = Unit
}
在service中持有callback
接口,并在binder中定义方法得到service的实例。activity中实现ServiceConnection
,通过绑定启动service,这样会回调ServiceConnection
接口的onServiceConnected
方法,从而得到service实例,对service中的callback
进行赋值,在service中可进行耗时操作并见数据通过callback接口,传递给activity进行其他操作。
- 运行结果:
2020-04-18 E/service传值: service.data -> service.thread已执行.
四、总结
- activity与activity之间通信:
Intent\Bundle传值
成员变量传值
类静态变量传值 - activity与fragment之间通信
Bundle传值/直接在Activity中定义方法
接口回调方法 - Activity与Service之间通信
绑定服务,利用ServiceConnection类
简单通信,利用Intent进行传值
定义一个callback接口来监听服务中的进程变化
除了上面说的常用方法外,还有很多其他方法,比如广播机制,事件总汇(eventbus)等。