片段中的android MapView

时间:2014-10-03 06:57:00

标签: java android google-maps android-mapview

我希望MapView

中有Fragment

这是我的FragmentLayout xml文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#17df0d"
    android:orientation="vertical" >

<com.google.android.gms.maps.MapView
    android:id="@+id/mapview"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    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>

和我的片段类

public class ReportFragment extends Fragment implements LocationListener {
    MapView mapView = null; //eventually it is being read from view and assigned

当我启动应用程序时,我在Fragment中看不到任何地图视图

5 个答案:

答案 0 :(得分:39)

来自Josh Holtz's example on GitHub

您应该在MapView中添加Layout

 <com.google.android.gms.maps.MapView 
    android:id="@+id/mapview"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" />

并实施您的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();
  }

}

答案 1 :(得分:18)

加入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();
}

答案 2 :(得分:5)

如果有人正在寻找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"))
}

答案 3 :(得分:0)

确保您要覆盖或调用OnDestroy View 以及OnDestroy。像...

    public override void OnDestroy()
    {            
        base.OnDestroy();
        MapView.OnDestroy();
        OnDestroyView();            
    }

    public override void OnDestroyView()
    {            
        base.OnDestroyView();
        mapReadyCallbackList.Clear();            
}

答案 4 :(得分:0)

旧帖子,但可能对正在片段中实现地图的人有所帮助。以下是使用kotlin的详细示例:

首先,在AndroidManifest.xml文件中添加权限:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

然后在application标记下在AndroidManifest.xml文件中添加元数据:

<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_width="match_parent"
          android:layout_height="match_parent"/>

在fragment.kt文件中,实现OnMapReadyCallback。使用getMapAsync()初始化Google地图。下面的代码可让您集成Google地图并将其指向您当前的位置。

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_width="wrap_content"
              android:layout_height="wrap_content"
              android:layoutDirection="locale"
              android:orientation="vertical">
    <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:textColor="#ff000000"
            android:textStyle="bold" />

    <TextView
            android:id="@+id/snippet"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            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>

希望这对您有帮助...