Intent:Android 组件间的“快递包裹”
首先,我们需要明确一个概念:Android 应用程序是由多个组件组成的,例如:
Activity: 负责用户交互的界面。Service: 在后台运行的任务,例如下载文件、播放音乐。Broadcast Receiver: 接收系统或应用程序发出的广播消息。Content Provider: 提供数据访问接口,允许其他应用程序访问你的数据。
这些组件就像一个个独立的模块,它们之间需要进行通信和协作才能完成复杂的任务。 而 Intent,就是负责在这些组件之间传递消息和数据的“快递包裹”。
Intent 的核心作用:
启动组件(“我要寄包裹!”)
Intent 可以用来启动一个 Activity、Service 或 Broadcast Receiver。这就像你告诉快递员:“我要寄一个包裹!”,快递员会根据你的指示,找到相应的收件人并送达。例如,你可以使用 Intent 启动一个新的 Activity 来显示用户个人资料,或者启动一个 Service 在后台下载文件。
传递数据(“包裹里有什么?”)
Intent 可以携带数据在组件之间传递。这就像你在快递包裹里放了一些东西(例如文件、照片、商品),收件人收到包裹后可以取出这些东西。例如,你可以使用 Intent 将用户名、密码等信息从一个 Activity 传递给另一个 Activity。
Intent 的两种类型:
显式 Intent(“指定收件人!”)
显式 Intent 明确指定了要启动的组件的类名(就像快递单上写明了收件人的姓名和地址)。
Android 系统会直接找到该组件并启动它。
使用场景: 通常用于启动应用程序内部的组件,例如启动同一个应用程序中的另一个 Activity。
示例:
val intent = Intent(this, MyActivity::class.java) // 明确指定要启动 MyActivity
startActivity(intent)
隐式 Intent(“告诉快递员需求!”)
隐式 Intent 没有明确指定要启动的组件的类名,而是指定了一组 action、category 和 data 等信息(就像你告诉快递员:“我要寄一个能打开网页的包裹!”)。
Android 系统会根据这些信息找到能够处理该 Intent 的组件(例如浏览器),并启动该组件。
使用场景: 通常用于启动其他应用程序的组件,例如打开网页、发送邮件、拨打电话等。
示例:
val intent = Intent(Intent.ACTION_VIEW) // 指定 action 为查看
intent.data = Uri.parse("http://www.example.com") // 指定要查看的数据是 URL
startActivity(intent) // 系统会找到能够打开网页的应用程序(例如浏览器)
Intent 的属性:
action(“包裹要做什么?”)
action 描述了 Intent 要执行的动作。例如:Intent.ACTION_VIEW(查看)、Intent.ACTION_SEND(发送)、Intent.ACTION_DIAL(拨打电话)等。
data(“包裹里的数据是什么?”)
data 指定了 Intent 要操作的数据。通常是一个 Uri 对象,表示数据的地址。例如:Uri.parse("http://www.example.com")(网页地址)、Uri.parse("tel:1234567890")(电话号码)等。
category(“包裹的分类?”)
category 提供了关于 Intent 的额外信息。例如:Intent.CATEGORY_LAUNCHER(表示该 Activity 可以在应用程序启动器中显示)。
extra(“包裹里的额外信息?”)
extra 用于携带额外的数据。可以使用 putExtra() 方法添加 extra 数据,使用 getStringExtra()、getIntExtra() 等方法获取 extra 数据。
使用 Intent 的步骤:
创建 Intent 对象(“准备快递包裹!”)
使用 Intent 的构造函数创建一个 Intent 对象。
设置 Intent 的属性(“填写快递单!”)
根据需要,设置 Intent 的 action、data、category 和 extra 等属性。
启动组件(“寄出快递包裹!”)
使用 startActivity()、startService() 或 sendBroadcast() 等方法启动相应的组件。
总结:
Intent 是 Android 组件之间进行通信和协作的关键机制。 它可以用来启动组件、传递数据,就像一个“快递包裹”一样,将消息和数据从一个地方送到另一个地方。
对于一个115的理论理解:
在WeatherActivity中:
weatherViewModel.locationLng = intent.getStringExtra("location_lng") ?: ""
val weatherViewModel by lazy { ViewModelProvider(this).get(WeatherShowViewModel::class.java) } 那这个是intent的一个构造函数吗?
不,val weatherViewModel by lazy { ViewModelProvider(this).get(WeatherShowViewModel::class.java) } 不是 Intent 的构造函数。 它是 Kotlin 中使用 ViewModelProvider 获取 ViewModel 实例的一种方式,并且使用了 lazy 委托来实现延迟初始化。
weatherViewModel.locationLng = intent.getStringExtra("location_lng") ?: "" 那使用intent不是先要构造intent吗,那为什么那个没有构造?
使用 intent.getStringExtra() 前提是已经有了一个 intent 对象。
在 weatherViewModel.locationLng = intent.getStringExtra("location_lng") ?: "" 这段代码中,我们没有看到显式地构造 Intent 对象。 这是因为这段代码通常出现在 Activity 的 onCreate() 方法或者 Fragment 的 onCreateView() 方法中,而启动该 Activity 或 Fragment 的 Intent 对象已经由 Android 系统创建并传递过来了。
从 PlaceSearchActivity 启动:
在 PlaceSearchActivity 中的 PlaceSearchAdapter 的 onCreateViewHolder 方法中,当用户点击一个地点时,会创建一个 Intent 对象,并将地点信息(经度、纬度、地点名称、地点地址)作为 extra 数据添加到 Intent 中,然后启动 WeatherActivity。
// PlaceSearchAdapter.kt
holder.itemView.setOnClickListener {
val position = holder.bindingAdapterPosition
val place = placeList[position]
val intent = Intent(placeSearchActivity,WeatherActivity::class.java).apply {
putExtra("location_lng", place.location.lng)
putExtra("location_lat", place.location.lat)
putExtra("place_name", place.name)
putExtra("place_address",place.address)
}
placeSearchActivity.viewModel.savePlace(place)
placeSearchActivity.startActivity(intent)
placeSearchActivity.finish()
}
在这个场景中,PlaceSearchActivity 是 Intent 对象的创建者和发送者,而 WeatherActivity 是 Intent 对象的接收者。
由系统启动(如果保存了地点信息):
在 PlaceSearchActivity 的 onCreate 方法中,会检查是否已经保存了地点信息(通过 viewModel.isPlaceSaved() 方法)。如果已经保存了地点信息,则会创建一个 Intent 对象,并将保存的地点信息作为 extra 数据添加到 Intent 中,然后启动 WeatherActivity。
// PlaceSearchActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_place_search)
val fromActivity = intent.getStringExtra("FROM_ACTIVITY")
if (fromActivity == null && viewModel.isPlaceSaved()) {
val place = viewModel.getSavedPlace()
val intent = Intent(this, WeatherActivity::class.java).apply {
putExtra("location_lng", place.location.lng)
putExtra("location_lat", place.location.lat)
putExtra("place_name", place.name)
putExtra("place_address",place.address)
}
startActivity(intent)
finish()
return
}
在这个场景中,PlaceSearchActivity 也是 Intent 对象的创建者和发送者,而 WeatherActivity 是 Intent 对象的接收者。这种情况通常发生在用户已经选择过地点,并且应用程序重新启动时。
从地点管理列表启动:
在 WeatherActivity 中的 PlaceManageAdapter 的 onCreateViewHolder 方法中,当用户点击一个地点管理列表中的地点时,会设置对应的经纬度等信息,然后调用refreshWeather()函数来更新天气,但没有直接创建新的intent,而是使用了已有的intent,并更新了相关信息。
holder.itemView.setOnClickListener {
val position = holder.bindingAdapterPosition
val placeManage = placeManageList[position]
weatherActivity.drawerLayout.closeDrawers()
weatherActivity.weatherViewModel.locationLng = placeManage.lng
weatherActivity.weatherViewModel.locationLat = placeManage.lat
weatherActivity.weatherViewModel.placeName = placeManage.name
weatherActivity.weatherViewModel.isUpdatePlaceManage = true
weatherActivity.refreshWeather()
val place = Place(placeManage.name, Location(placeManage.lng,placeManage.lat),placeManage.address)
weatherActivity.placeManageViewModel.savePlace(place)
}
总结:
WeatherActivity 可以被 PlaceSearchActivity 启动,或者由系统在应用程序重新启动时启动(如果保存了地点信息)。在这些场景中,Intent 对象由 PlaceSearchActivity 创建,并携带地点信息作为 extra 数据传递给 WeatherActivity。WeatherActivity 通过 getIntent() 方法获取 Intent 对象,并从中获取地点信息。