美文网首页
Android四大组件之Activity(2)组件间通信

Android四大组件之Activity(2)组件间通信

作者: 狼性代码人 | 来源:发表于2020-04-18 21:05 被阅读0次

    一、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设置需要传递给MainActivityBundle数据,在MainActivityonActivityResult函数中就可以得到相关的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()
        }
    }
    

      通过FragmentsetArguments(bundle)实现ActivityFragment传值。

    (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
    

      ServiceonBind方法需要返回一个Binder对象,而这个对象在ServiceConnection.onServiceConnected中可以获取,从而实现ServiceActivity之间的通信。

    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,我们可以在ServiceonStartCommand方法中得到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)等。

    相关文章

      网友评论

          本文标题:Android四大组件之Activity(2)组件间通信

          本文链接:https://www.haomeiwen.com/subject/ybegmhtx.html