增加界面显示openweathermap返回的信息。
在activity_main.xml里增加输入框来输入城市,在输入款旁边增加搜索按钮来进行查询。
然后原来显示helloworld的TextView用来显示结果。
1. 增加输入城市名字的EditText
<EditText
android:id="@+id/editTextCity"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="@string/editTextCityHint"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/buttonSearch"/>
- 增加搜索按钮
<Button
android:id="@+id/buttonSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@+id/editTextCity"
app:layout_constraintBottom_toBottomOf="@+id/editTextCity"
app:layout_constraintStart_toEndOf="@+id/editTextCity"
app:layout_constraintEnd_toEndOf="parent"
android:text="@string/buttonSearchText" />
3. 增加显示的TextView
<TextView
android:id="@+id/weatherResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
使用broadcast的方式把收到的天气信息发送到界面显示。
Android的广播机制是一种用于在应用程序内和应用程序之间传递消息和事件的方式。通过广播,一个应用程序可以发送消息(被称为广播),而其他应用程序可以接收并处理这些广播。
- 广播发送者(Broadcast Sender):应用程序或者系统组件(如系统服务)可以通过发送广播来通知其他应用程序或组件事件的发生。广播发送者并不需要知道接收者是谁,只需要发送广播即可。
- 广播接收者(Broadcast Receiver):应用程序或者组件可以通过注册广播接收器来接收特定类型的广播。广播接收者可以在AndroidManifest.xml文件中声明静态接收器,也可以在代码中动态注册接收器。
- 广播的类型:Android广播可以分为普通广播和有序广播两种类型。
- 普通广播(Normal Broadcast):普通广播是一种异步的广播发送方式,广播发送者不需要等待接收者处理广播。这使得广播发送者能够快速地发送广播,而不会受到接收者处理时间的影响。
- 有序广播(Ordered Broadcast):有序广播是一种同步的广播发送方式,广播发送者会按照优先级的顺序发送广播,接收者依次处理广播。每个接收者处理完广播后可以选择终止广播或者将广播传递给下一个接收者。
- 广播过滤器(Broadcast Filter):广播过滤器允许应用程序指定它们所感兴趣的广播类型。广播接收者可以根据广播过滤器过滤来自特定来源或具有特定操作的广播。这样可以减少不必要的广播传递,提高性能。
- 系统广播(System Broadcast):Android系统内置了一些广播用于通知应用程序和组件系统事件的发生,例如设备启动、网络连接状态变化、电池低电量等。应用程序可以注册对这些系统广播感兴趣的接收者,以执行相应的操作。
通过广播机制,应用程序可以实现一种松耦合的通信方式,让不同的组件之间进行信息传递和事件触发。这种机制使得应用程序能够更好地响应系统事件、应用程序状态的变化,并且可以与其他应用程序之间进行交互。
4.注册一个自定义的广播:
将广播接收器的类名替换为您自己的接收器类名,并使用 intent-filter 添加您自定义的广播 action。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<application
<!-- ... -->
<activity
<!-- ... -->
</activity>
<receiver
android:name=".WeatherResponseReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.example.MyWeather.ACTION_WEATHER_DATA"/>
</intent-filter>
</receiver>
</application>
</manifest>
5.在RetrofitClient类中发送广播
在发送自定义广播时,您需要使用 sendBroadcast() 方法,并指定广播的 action。
private fun handleWeatherData(context: Context, weatherData: WeatherResponse?) {
if (weatherData != null) {
val intent = Intent("com.example.MyWeather.ACTION_WEATHER_DATA")
intent.putExtra("cityName", weatherData.name)
intent.putExtra("temperature", weatherData.main?.temp)
intent.putExtra("maxTemperature", weatherData.main?.temp_max)
intent.putExtra("minTemperature", weatherData.main?.temp_min)
val weatherStringArray = arrayListOf<String>()
for(weather in weatherData.weather) {
weatherStringArray += "main:${weather.main},description:${weather.description}"
}
intent.putStringArrayListExtra("weather", weatherStringArray)
context.sendBroadcast(intent)
printWeatherData(weatherData)
}
}
6.创建一个用来接受广播的类,并重写onReceive函数。
class WeatherResponseReceiver : BroadcastReceiver() {
private var textView: TextView? = null
fun setTextView(textView: TextView) {
this.textView = textView
}
override fun onReceive(context: Context?, intent: Intent?) {
if(intent?.action == "com.example.MyWeather.ACTION_WEATHER_DATA") {
val kelvins = 273.15
val cityName = intent.getStringExtra("cityName")
val temperature = intent.getFloatExtra("temperature", 0.0F) - kelvins
val maxTemperature = intent.getFloatExtra("maxTemperature", 0.0F) - kelvins
val minTemperature = intent.getFloatExtra("minTemperature", 0.0F) - kelvins
val weather = intent.getStringArrayListExtra("weather")
val decimalFormat = DecimalFormat("#.#")
@SuppressLint("SetTextI18n")
textView?.text = "$cityName\n${decimalFormat.format(temperature)}\n${decimalFormat.format(maxTemperature)}\n${decimalFormat.format(minTemperature)}\n$weather"
}
}
}
为了能让收到的广播消息能够显示在TextView中,我把TextView的指针传递给了接收广播的类。
class MainActivity : AppCompatActivity() {
private lateinit var weatherResponseReceiver: WeatherResponseReceiver
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
weatherResponseReceiver = WeatherResponseReceiver()
weatherResponseReceiver.setTextView(findViewById<TextView>(R.id.weatherResult))
val intentFilter = IntentFilter("com.example.MyWeather.ACTION_WEATHER_DATA")
registerReceiver(weatherResponseReceiver, intentFilter)
findViewById<Button>(R.id.buttonSearch).setOnClickListener { searchCityNameWeather(it) }
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(weatherResponseReceiver)
}
private fun searchCityNameWeather(view: View) {
val cityName = findViewById<EditText>(R.id.editTextCity).text.toString().trim()
RetrofitClient.getWeatherByCityName(view.context, cityName)
}
}