Android开发:如何从Google Map获取地址信息并自动填充editbox
一步步实现你的Android地图需求(新手友好版)
嗨,作为Android新手能想到这么完整的需求已经很棒啦!我一步步给你拆解实现方法,保证每一步都清晰易懂~
一、先做前置准备:权限与依赖配置
1. 配置AndroidManifest.xml
首先要给App加上必要的权限和Google Maps的配置:
<!-- 定位权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- Google Maps 必要配置 --> <uses-feature android:glEsVersion="0x00020000" android:required="true" /> <application ...> <!-- 替换成你自己的Google Maps API密钥 --> <meta-data android:name="com.google.android.geo.API_KEY" android:value="你的API_KEY"/> <!-- 地图Activity声明 --> <activity android:name=".MapActivity" /> </application>
小贴士:API密钥需要去Google Cloud控制台申请,记得启用Maps SDK for Android哦
2. 添加Gradle依赖
在你的app模块的build.gradle(Module级)里添加Maps和定位服务的依赖:
dependencies { // Google Maps implementation 'com.google.android.gms:play-services-maps:18.1.0' // 定位服务 implementation 'com.google.android.gms:play-services-location:21.0.1' }
二、主界面(MainActivity)实现
主界面需要一个触发地图的图片,以及用来填充地址的输入框:
1. 布局文件(activity_main.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <!-- 点击打开地图的图片 --> <ImageView android:id="@+id/iv_open_map" android:layout_width="match_parent" android:layout_height="200dp" android:src="@drawable/ic_map_launcher" android:clickable="true" android:contentDescription="打开地图"/> <!-- 地址输入框区域 --> <EditText android:id="@+id/et_street" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="街道名称" android:layout_marginTop="16dp"/> <EditText android:id="@+id/et_zipcode" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="邮政编码" android:layout_marginTop="8dp"/> <EditText android:id="@+id/et_state" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="州" android:layout_marginTop="8dp"/> <EditText android:id="@+id/et_country" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="国家" android:layout_marginTop="8dp"/> </LinearLayout>
2. MainActivity代码逻辑
主要是点击图片跳转到MapActivity,并且接收返回的地址信息填充输入框:
class MainActivity : AppCompatActivity() { private lateinit var etStreet: EditText private lateinit var etZipcode: EditText private lateinit var etState: EditText private lateinit var etCountry: EditText // 定义请求码,用于接收MapActivity的返回结果 private val MAP_REQUEST_CODE = 1001 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) initViews() setupMapLauncher() } private fun initViews() { etStreet = findViewById(R.id.et_street) etZipcode = findViewById(R.id.et_zipcode) etState = findViewById(R.id.et_state) etCountry = findViewById(R.id.et_country) } private fun setupMapLauncher() { findViewById<ImageView>(R.id.iv_open_map).setOnClickListener { startActivityForResult(Intent(this, MapActivity::class.java), MAP_REQUEST_CODE) } } // 接收MapActivity返回的地址信息 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == MAP_REQUEST_CODE && resultCode == RESULT_OK) { data?.apply { etStreet.setText(getStringExtra("STREET")) etZipcode.setText(getStringExtra("ZIPCODE")) etState.setText(getStringExtra("STATE")) etCountry.setText(getStringExtra("COUNTRY")) } } } }
三、地图页面(MapActivity)核心实现
这部分是重点,要实现显示当前位置、点击地图加标记、逆地理编码获取地址三个功能:
1. 布局文件(activity_map.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!-- Google Map 容器 --> <fragment android:id="@+id/map_fragment" android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> <!-- 提交按钮 --> <Button android:id="@+id/btn_submit" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="确认地址" android:layout_margin="16dp"/> </LinearLayout>
2. MapActivity代码逻辑
class MapActivity : AppCompatActivity(), OnMapReadyCallback { private lateinit var mMap: GoogleMap private lateinit var fusedLocationClient: FusedLocationProviderClient private var selectedMarker: Marker? = null // 保存用户点击的标记 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_map) // 初始化定位客户端 fusedLocationClient = LocationServices.getFusedLocationProviderClient(this) // 获取地图实例 val mapFragment = supportFragmentManager.findFragmentById(R.id.map_fragment) as SupportMapFragment mapFragment.getMapAsync(this) // 提交按钮点击事件 findViewById<Button>(R.id.btn_submit).setOnClickListener { selectedMarker?.position?.let { latLng -> getAddressFromLatLng(latLng) } ?: run { Toast.makeText(this, "请先在地图上选择位置", Toast.LENGTH_SHORT).show() } } } // 地图初始化完成回调 override fun onMapReady(googleMap: GoogleMap) { mMap = googleMap // 先请求定位权限,再显示当前位置 requestLocationPermission() // 设置地图点击监听,添加标记 setupMapClickListener() } // 动态请求定位权限 private fun requestLocationPermission() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1002 ) } else { // 权限已授予,显示当前位置 showCurrentLocation() } } // 显示用户当前位置 private fun showCurrentLocation() { mMap.isMyLocationEnabled = true // 显示我的位置按钮 fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? -> location?.let { val currentLatLng = LatLng(it.latitude, it.longitude) // 移动地图到当前位置,缩放级别15(数值越大越近) mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 15f)) } ?: run { Toast.makeText(this, "无法获取当前位置", Toast.LENGTH_SHORT).show() } } } // 处理权限请求结果 override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == 1002) { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { showCurrentLocation() } else { Toast.makeText(this, "需要定位权限才能显示当前位置", Toast.LENGTH_SHORT).show() } } } // 设置地图点击监听,添加标记 private fun setupMapClickListener() { mMap.setOnMapClickListener { latLng -> // 移除之前的标记,保证只有一个选中标记 selectedMarker?.remove() // 添加新标记 selectedMarker = mMap.addMarker(MarkerOptions().position(latLng)) } } // 通过经纬度获取地址信息(逆地理编码) private fun getAddressFromLatLng(latLng: LatLng) { val geocoder = Geocoder(this, Locale.getDefault()) lifecycleScope.launch { try { val addresses = geocoder.getFromLocation(latLng.latitude, latLng.longitude, 1) addresses?.firstOrNull()?.let { address -> // 提取需要的地址信息 val street = address.thoroughfare ?: "" // 街道 val zipcode = address.postalCode ?: "" // 邮编 val state = address.adminArea ?: "" // 州/省 val country = address.countryName ?: "" // 国家 // 返回结果给MainActivity val resultIntent = Intent().apply { putExtra("STREET", street) putExtra("ZIPCODE", zipcode) putExtra("STATE", state) putExtra("COUNTRY", country) } setResult(RESULT_OK, resultIntent) finish() } ?: run { Toast.makeText(this@MapActivity, "无法获取地址信息", Toast.LENGTH_SHORT).show() } } catch (e: IOException) { Toast.makeText(this@MapActivity, "地址解析失败:${e.message}", Toast.LENGTH_SHORT).show() } } } }
四、关键细节提示
- API密钥申请:一定要去Google Cloud控制台创建项目,启用Maps SDK for Android,然后生成API密钥,不然地图会加载失败。
- 权限处理:如果用户拒绝定位权限,要友好提示,或者提供手动选择位置的备选方案。
- 逆地理编码异常:Geocoder可能因为网络或地区问题解析失败,一定要加异常捕获。
- 标记管理:代码里每次点击地图都会移除之前的标记,保证只有一个选中的位置,避免用户混淆。
内容的提问来源于stack exchange,提问作者user8472639




