片段中的android MapView
Posted
技术标签:
【中文标题】片段中的android MapView【英文标题】:android MapView in Fragment 【发布时间】:2014-11-28 06:01:36 【问题描述】:我想在我的Fragment
中加入MapView
这是我的FragmentLayout
xml 文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:background="#17df0d"
android:orientation="vertical" >
<com.google.android.gms.maps.MapView
android:id="@+id/mapview"
android:layout_
android:layout_
android:layout_above="@+id/textView1"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="70dp" >
</com.google.android.gms.maps.MapView>
</RelativeLayout>
我的AndroidManifest.xml
文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="a.b.c.d"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="your_api_key" />
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
</application>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<permission
android:name="a.b.c.d.permission.MAPS_RECEIVE"
android:protectionLevel="signature" />
<uses-permission android:name="a.b.c.d.permission.MAPS_RECEIVE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>
还有我的 Fragment 类
public class ReportFragment extends Fragment implements LocationListener
MapView mapView = null; //eventually it is being read from view and assigned
当我启动应用程序时,我在 Fragment 中看不到任何地图视图
【问题讨论】:
你的MapView
在你的布局中在哪里?
您确实看到了它,因为您没有在任何地方添加mapview
。
我认为您使用的是GoogleMap v2
,所以最好使用MapFragment
或SupportMapFragment
而不是MapView
。
我可以在 Fragment 中使用 Fragment 吗? @X'因素
@user3833308 好的。查看我的答案并实施您的 MapView。
【参考方案1】:
来自Josh Holtz's example on GitHub:
你应该在你的Layout
中添加MapView
喜欢
<com.google.android.gms.maps.MapView
android:id="@+id/mapview"
android:layout_
android:layout_ />
并实现你的Fragment
喜欢
public class SomeFragment extends Fragment
MapView mapView;
GoogleMap map;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
View v = inflater.inflate(R.layout.some_layout, container, false);
// Gets the MapView from the XML layout and creates it
mapView = (MapView) v.findViewById(R.id.mapview);
mapView.onCreate(savedInstanceState);
// Gets to GoogleMap from the MapView and does initialization stuff
map = mapView.getMap();
map.getUiSettings().setMyLocationButtonEnabled(false);
map.setMyLocationEnabled(true);
// Needs to call MapsInitializer before doing any CameraUpdateFactory calls
try
MapsInitializer.initialize(this.getActivity());
catch (GooglePlayServicesNotAvailableException e)
e.printStackTrace();
// Updates the location and zoom of the MapView
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(43.1, -87.9), 10);
map.animateCamera(cameraUpdate);
return v;
@Override
public void onResume()
mapView.onResume();
super.onResume();
@Override
public void onDestroy()
super.onDestroy();
mapView.onDestroy();
@Override
public void onLowMemory()
super.onLowMemory();
mapView.onLowMemory();
【讨论】:
我在使用 MapView 时遇到了一些内存泄漏,有类似的经历吗? 是的,我也有。你找到解决办法了吗? 这里一样,但没有解决办法 用MapFragment
代替MapView
尝试从onDestroyView调用mapView.onDestroy()【参考方案2】:
添加到 M D 的答案:
来自documentation:
必须使用 getMapAsync(OnMapReadyCallback) 获取 GoogleMap。 MapView 自动初始化地图系统和视图。
据此,更正确的初始化GoogleMap
的方法是使用getMapAsync
。
注意你的类必须实现OnMapReadyCallback
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
View v = inflater.inflate(R.layout.fragment_map_page, container, false);
mMapView = (MapView) v.findViewById(R.id.map_view);
mMapView.onCreate(savedInstanceState);
mMapView.getMapAsync(this); //this is important
return v;
@Override
public void onMapReady(GoogleMap googleMap)
mGoogleMap = googleMap;
mGoogleMap.getUiSettings().setZoomControlsEnabled(true);
mGoogleMap.addMarker(new MarkerOptions().position(/*some location*/));
mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(/*some location*/, 10));
@Override
public void onResume()
super.onResume();
mMapView.onResume();
@Override
public void onPause()
super.onPause();
mMapView.onPause();
@Override
public void onDestroy()
super.onDestroy();
mMapView.onDestroy();
@Override
public void onSaveInstanceState(Bundle outState)
super.onSaveInstanceState(outState);
mMapView.onSaveInstanceState(outState);
@Override
public void onLowMemory()
super.onLowMemory();
mMapView.onLowMemory();
【讨论】:
【参考方案3】:如果有人正在寻找 Kotlin 版本的 MapView Fragment ;)
class MapViewKotlinFragment : Fragment(), OnMapReadyCallback
private var mMap: MapView? = null
override fun onSaveInstanceState(outState: Bundle?)
super.onSaveInstanceState(outState)
mMap?.onSaveInstanceState(outState)
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View?
val view = inflater?.inflate(R.layout.fragment_map, container, false)
mMap = view?.findViewById(R.id.mapViewPlaces) as MapView
mMap?.onCreate(savedInstanceState)
mMap?.getMapAsync(this)
return view
override fun onResume()
super.onResume()
mMap?.onResume()
override fun onPause()
super.onPause()
mMap?.onPause()
override fun onStart()
super.onStart()
mMap?.onStart()
override fun onStop()
super.onStop()
mMap?.onStop()
override fun onDestroy()
super.onDestroy()
mMap?.onDestroy()
override fun onLowMemory()
super.onLowMemory()
mMap?.onLowMemory()
override fun onMapReady(googleMap: GoogleMap)
googleMap.addMarker(MarkerOptions().position(LatLng(0.0, 0.0)).title("Marker"))
【讨论】:
谢谢,它对我有用,除了我必须将mMap
声明为 MapView?
而不是 GoogleMap?
【参考方案4】:
确保您覆盖或调用 OnDestroyView 以及 OnDestroy。有点像...
public override void OnDestroy()
base.OnDestroy();
MapView.OnDestroy();
OnDestroyView();
public override void OnDestroyView()
base.OnDestroyView();
mapReadyCallbackList.Clear();
【讨论】:
【参考方案5】:旧帖子,但可能对希望在片段中实现地图的人有所帮助。下面是使用 kotlin 的详细示例:
首先,在AndroidManifest.xml文件中添加权限:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
然后在AndroidManifest.xml文件的application标签下添加元数据:
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/map_api_key"/>
<uses-library
android:name="org.apache.http.legacy"
android:required="false" />
*获取api链接访问:https://developers.google.com/maps/documentation/android-sdk/get-api-key
在 build.gradle 文件中实现播放服务:
implementation "com.google.android.gms:play-services-location:15.0.1"
implementation "com.google.android.gms:play-services-places:15.0.1"
implementation 'com.google.android.libraries.places:places:2.3.0'
添加插件:应用插件:'com.google.gms.google-services'
在您的 fragment.xml 文件中添加地图片段:
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:id="@+id/map"
android:layout_
android:layout_/>
在您的 fragment.kt 文件中,实现 OnMapReadyCallback。使用 getMapAsync() 初始化谷歌地图。下面的代码将让您集成谷歌地图并将其指向您当前的位置。
package "Your_Package_Name"
import android.Manifest
import android.content.ContentValues.TAG
import android.content.DialogInterface
import android.content.pm.PackageManager
import android.location.Location
import android.os.Bundle
import androidx.core.app.ActivityCompat
import androidx.fragment.app.Fragment
import androidx.core.content.ContextCompat
import androidx.appcompat.app.AlertDialog
import android.util.Log
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.TextView
import android.widget.Toast
import com.example.utilitybox.R
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.maps.*
import com.google.android.gms.maps.model.CameraPosition
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.Marker
import com.google.android.gms.maps.model.MarkerOptions
import com.google.android.libraries.places.api.model.Place
import com.google.android.libraries.places.api.net.FindCurrentPlaceRequest
import com.google.android.libraries.places.api.net.PlacesClient
class FragmentHome : Fragment(), OnMapReadyCallback
private var v:View?=null
private var locationPermissionGranted = false
private var googleMap: GoogleMap?=null
private var fusedLocationProviderClient: FusedLocationProviderClient?=null
private val defaultLocation = LatLng(-33.8523341, 151.2106085)
private var cameraPosition: CameraPosition? = null
private var placesClient: PlacesClient?=null
private var lastKnownLocation: Location? = null
private var likelyPlaceNames: Array<String?> = arrayOfNulls(0)
private var likelyPlaceAddresses: Array<String?> = arrayOfNulls(0)
private var likelyPlaceAttributions: Array<List<*>?> = arrayOfNulls(0)
private var likelyPlaceLatLngs: Array<LatLng?> = arrayOfNulls(0)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View?
if (savedInstanceState != null)
lastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION)
cameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION)
v = inflater.inflate(R.layout.fragment_fragment_home, container, false)
if(getString(R.string.map_api_key).isEmpty())
Toast.makeText(activity, "Add your own API key in MapWithMarker/app/secure.properties as MAPS_API_KEY=YOUR_API_KEY", Toast.LENGTH_LONG).show()
val mapFragment = childFragmentManager.findFragmentById(R.id.map) as? SupportMapFragment
mapFragment?.getMapAsync(this)
getLocationPermission()
return v
override fun onSaveInstanceState(outState: Bundle)
googleMap?.let map ->
outState.putParcelable(KEY_CAMERA_POSITION, map.cameraPosition)
outState.putParcelable(KEY_LOCATION, lastKnownLocation)
super.onSaveInstanceState(outState)
override fun onOptionsItemSelected(item: MenuItem): Boolean
if (item.itemId == R.id.option_get_place)
showCurrentPlace()
return true
override fun onMapReady(googleMap: GoogleMap)
this.googleMap = googleMap
this.googleMap?.setInfoWindowAdapter(object : GoogleMap.InfoWindowAdapter
override fun getInfoWindow(arg0: Marker): View?
return null
override fun getInfoContents(marker: Marker): View
val infoWindow = layoutInflater.inflate(R.layout.custom_info_contents,
v?.findViewById(R.id.map), false)
val title = infoWindow.findViewById<TextView>(R.id.title)
title.text = marker.title
val snippet = infoWindow.findViewById<TextView>(R.id.snippet)
snippet.text = marker.snippet
return infoWindow
)
getLocationPermission()
updateLocationUI()
getDeviceLocation()
private fun getLocationPermission()
if (ContextCompat.checkSelfPermission(this.requireContext(),
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED)
locationPermissionGranted = true
else
ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION)
override fun onRequestPermissionsResult(requestCode: Int,
permissions: Array<String>,
grantResults: IntArray)
locationPermissionGranted = false
when (requestCode)
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION ->
if (grantResults.isNotEmpty() &&
grantResults[0] == PackageManager.PERMISSION_GRANTED)
locationPermissionGranted = true
updateLocationUI()
private fun showCurrentPlace()
if (googleMap == null)
return
if (locationPermissionGranted)
val placeFields = listOf(Place.Field.NAME, Place.Field.ADDRESS, Place.Field.LAT_LNG)
val request = FindCurrentPlaceRequest.newInstance(placeFields)
val placeResult = placesClient?.findCurrentPlace(request)
placeResult?.addOnCompleteListener task ->
if (task.isSuccessful && task.result != null)
val likelyPlaces = task.result
val count = if (likelyPlaces != null && likelyPlaces.placeLikelihoods.size < M_MAX_ENTRIES)
likelyPlaces.placeLikelihoods.size
else
M_MAX_ENTRIES
var i = 0
likelyPlaceNames = arrayOfNulls(count)
likelyPlaceAddresses = arrayOfNulls(count)
likelyPlaceAttributions = arrayOfNulls<List<*>?>(count)
likelyPlaceLatLngs = arrayOfNulls(count)
for (placeLikelihood in likelyPlaces?.placeLikelihoods ?: emptyList())
likelyPlaceNames[i] = placeLikelihood.place.name
likelyPlaceAddresses[i] = placeLikelihood.place.address
likelyPlaceAttributions[i] = placeLikelihood.place.attributions
likelyPlaceLatLngs[i] = placeLikelihood.place.latLng
i++
if (i > count - 1)
break
openPlacesDialog()
else
Log.e(TAG, "Exception: %s", task.exception)
else
Log.i(TAG, "The user did not grant location permission.")
googleMap?.addMarker(MarkerOptions()
.title(getString(R.string.default_info_title))
.position(defaultLocation)
.snippet(getString(R.string.default_info_snippet)))
getLocationPermission()
private fun updateLocationUI()
if (googleMap == null)
return
try
if (locationPermissionGranted)
googleMap?.isMyLocationEnabled = true
googleMap?.uiSettings?.isMyLocationButtonEnabled = true
else
googleMap?.isMyLocationEnabled = false
googleMap?.uiSettings?.isMyLocationButtonEnabled = false
lastKnownLocation = null
getLocationPermission()
catch (e: SecurityException)
Log.e("Exception: %s", e.message, e)
private fun getDeviceLocation()
try
if (locationPermissionGranted)
val locationResult = fusedLocationProviderClient?.lastLocation
if (locationResult != null)
locationResult.addOnCompleteListener(this.requireActivity()) task ->
if (task.isSuccessful)
// Set the map's camera position to the current location of the device.
lastKnownLocation = task.result
if (lastKnownLocation != null)
googleMap?.moveCamera(CameraUpdateFactory.newLatLngZoom(
LatLng(lastKnownLocation!!.latitude,
lastKnownLocation!!.longitude), DEFAULT_ZOOM.toFloat()))
else
Log.d(TAG, "Current location is null. Using defaults.")
Log.e(TAG, "Exception: %s", task.exception)
googleMap?.moveCamera(CameraUpdateFactory
.newLatLngZoom(defaultLocation, DEFAULT_ZOOM.toFloat()))
googleMap?.uiSettings?.isMyLocationButtonEnabled = false
catch (e: SecurityException)
Log.e("Exception: %s", e.message, e)
private fun openPlacesDialog()
val listener = DialogInterface.OnClickListener dialog, which ->
val markerLatLng = likelyPlaceLatLngs[which]
var markerSnippet = likelyPlaceAddresses[which]
if (likelyPlaceAttributions[which] != null)
markerSnippet = """
$markerSnippet
$likelyPlaceAttributions[which]
""".trimIndent()
googleMap?.addMarker(MarkerOptions()
.title(likelyPlaceNames[which])
.position(markerLatLng!!)
.snippet(markerSnippet))
googleMap?.moveCamera(CameraUpdateFactory.newLatLngZoom(markerLatLng,
DEFAULT_ZOOM.toFloat()))
AlertDialog.Builder(this.requireContext())
.setTitle(R.string.pick_place)
.setItems(likelyPlaceNames, listener)
.show()
companion object
private const val DEFAULT_ZOOM = 15
private const val PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1
private const val KEY_CAMERA_POSITION = "camera_position"
private const val KEY_LOCATION = "location"
private const val M_MAX_ENTRIES = 5
完成后在布局文件夹中添加 custom_info_contents.xml 文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:layoutDirection="locale"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_
android:layout_
android:layout_gravity="center_horizontal"
android:textColor="#ff000000"
android:textStyle="bold" />
<TextView
android:id="@+id/snippet"
android:layout_
android:layout_
android:textColor="#ff7f7f7f" />
</LinearLayout>
在strings.xml文件中添加以下代码:
<string name="map_api_key">YOUR_API_KEY</string>
<!--Map strings-->
<string name="title_activity_maps">Current Place Details</string>
<string name="default_info_title">Default Location</string>
<string name="default_info_snippet">No places found, because location permission is disabled.</string>
<string name="option_get_place">Get place</string>
<string name="pick_place">Choose a place</string>
在菜单文件夹中创建 current_place_menu.xml 文件并添加以下代码:
<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/option_get_place"
android:title="@string/option_get_place"
app:showAsAction="always"/>
</menu>
希望这会有所帮助...
【讨论】:
以上是关于片段中的android MapView的主要内容,如果未能解决你的问题,请参考以下文章