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

2020-04-18  本文已影响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

接口回调方法

// 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已执行.

四、总结

除了上面说的常用方法外,还有很多其他方法,比如广播机制,事件总汇(eventbus)等。

上一篇下一篇

猜你喜欢

热点阅读