I am trying to display a simple map in my Android application, using the MapView class.
I use the following onCreate method in my activity :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
MapsInitializer.initialize(this);
} catch (GooglePlayServicesNotAvailableException e) {
Log.e("Address Map", "Could not initialize google play", e);
}
MapView mapView = new MapView(this);
CameraUpdate camPos = CameraUpdateFactory.newLatLng(new LatLng(11.562276,104.920292));
mapView.getMap().moveCamera(camPos);
setContentView(mapView);
}
I have a NullPointerException, because the method mapView.getMap() returns null.
Don't understand why, Google play services are apparently present and initialized.
Could not get MapView to work, I finally ended using the class SupportMapFragment.
For those that it may help, here is the complete code of my activity :
public class AddressMap extends android.support.v4.app.FragmentActivity {
private final static int FRAGMENT_ID = 0x101;
private GoogleMap mMap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.HORIZONTAL);
layout.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
SupportMapFragment fragment = SupportMapFragment.newInstance();
layout.setId(0x101);
{
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(FRAGMENT_ID, fragment);
fragmentTransaction.commit();
}
setContentView(layout);
}
#Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
if (mMap == null) {
mMap = ((SupportMapFragment) getSupportFragmentManager()
.findFragmentById(FRAGMENT_ID)).getMap();
if (mMap != null) {
mMap.moveCamera(
CameraUpdateFactory.newLatLngZoom(new LatLng(11.562276, 104.920292), 10));
}
}
}
}
Also, mapView.onCreate() must be called.
You are trying to access Google Maps Android v1 Api which is now deprecated, please use Google Map Android Api v2
I used it like this and it worked, this is with the new api:
compile 'com.google.android.gms:play-services-maps:10.2.6'
public class MapViewFragment extends Fragment{
public static final String TAG = MapViewFragment.class.getSimpleName();
MapView mapView;
GoogleMap map;
static MapViewFragment instance;
public static MapViewFragment newInstance(){
if(instance == null){
instance = new MapViewFragment();
return instance;
}else{
return instance;
}
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
Log.i(TAG, "onCreateView: " );
View view = inflater.inflate(R.layout.map_view_fragment, container, false);
mapView = (MapView) view.findViewById(R.id.mvMap);
if(mapView != null){
mapView.onCreate(null); //Don't forget to call onCreate after get the mapView!
mapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap googleMap) {
map = googleMap;
//Do what you want with the map!!
}
});
MapsInitializer.initialize(this.getActivity());
}else{
Log.i(TAG, "onCreateView: mapView is null");
}
return view;
}
#Override
public void onResume() {
mapView.onResume();
super.onResume();
}
#Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}
And here is my layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.gms.maps.MapView
android:id="#+id/mvMap"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.google.android.gms.maps.MapView>
</LinearLayout>
Related
Title can be a bit complicated but the problem is literally as described. I'm trying to use google map fragment within a fragment stack. When the application starts the user will see a button and when the user pushes the button, current view will be replaced with map fragment. Currently, I'm able to replace the fragments but when the map fragment is shown, the view still has the button of previous fragment.Also I'm trying to replace fragments in one of the tabs of my app. Here is my code;
Map Fragment;
public class MapFragment extends Fragment {
MapView mMapView;
private GoogleMap googleMap;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.activity_maps, container, false);
mMapView = (MapView) rootView.findViewById(R.id.mapView);
mMapView.onCreate(savedInstanceState);
mMapView.onResume(); // needed to get the map to display immediately
try {
MapsInitializer.initialize(getActivity().getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
mMapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap mMap) {
googleMap = mMap;
try {
googleMap.setMyLocationEnabled(true);
} catch (SecurityException e) {
e.printStackTrace();
}
// For dropping a marker at a point on the Map
LatLng sydney = new LatLng(-34, 151);
googleMap.addMarker(new MarkerOptions().position(sydney).title("Marker Title").snippet("Marker Description"));
// For zooming automatically to the location of the marker
CameraPosition cameraPosition = new CameraPosition.Builder().target(sydney).zoom(12).build();
googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
});
return rootView;
}
#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 onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}
}
Home Fragment;
public class HomeFragment extends RootFragment {
public HomeFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Obtain the shared Tracker instance.
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.home_tab, container, false);
Button go = (Button)v.findViewById(R.id.btn_go);
go.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Intent intent = new Intent(getActivity(), MapFragment.class);
//startActivity(intent);
enterNextFragment();
}
});
return v;
}
#Override
public void onResume() {
super.onResume();
}
private void enterNextFragment() {
// Pushing MapView Fragment
Fragment fragment = Fragment.instantiate(this.getContext(), MapFragment.class.getName());
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment_mainLayout, fragment);
ft.commit();
}
}
Map Layout;
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.google.android.gms.maps.MapView
android:id="#+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
Home Fragment;
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HomeFragment"
android:background="#android:color/white"
android:id="#+id/fragment_mainLayout">
<!-- TODO: Update blank fragment layout -->
<android.support.v7.widget.AppCompatButton
android:id="#+id/btn_go"
android:layout_width="fill_parent"
android:layout_marginRight="20dp"
android:layout_marginLeft="20dp"
android:layout_height="wrap_content"
android:layout_marginTop="170dp"
android:text="GO"/>
</FrameLayout>
Often you will want one Fragment to communicate with another, for
example to change the content based on a user event. All
Fragment-to-Fragment communication is done through the associated
Activity. Two Fragments should never communicate directly.
Your fragments shouldn't communicate directly according to the documentation.
If you've managed to communicate with your fragments considering the documentation. Then you can use this simple method to be able to change and reuse any fragment.
In your host activity :
private void changeFragment(Fragment frag, boolean saveInBackstack) {
String backStateName = ((Object) frag).getClass().getName();
try {
FragmentManager manager = getSupportFragmentManager();
if (manager.findFragmentByTag(backStateName) == null) {
//fragment not in back stack, create it.
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.container, frag, backStateName);
if (saveInBackstack) {
Log.d(TAG, "Change Fragment: addToBackTack " + backStateName);
transaction.addToBackStack(backStateName);
} else {
Log.d(TAG, "Change Fragment: NO addToBackTack");
}
transaction.commit();
} else {
manager.popBackStack();
}
} catch (IllegalStateException exception) {
Log.w(TAG, "Unable to commit fragment, could be activity as been killed in
}
}
just add android:background="#android:color/white" on the main view of the map_layout xml file
Here is the solution;
Home Fragment;
public class HomeFragment extends RootFragment {
private LocationManager locationManager;
public HomeFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Obtain the shared Tracker instance.
locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.home_tab, container, false);
Button go = (Button) v.findViewById(R.id.btn_go);
go.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), MapFragment.class);
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
//Toast.makeText(getContext(), "GPS is Enabled in your devide", Toast.LENGTH_SHORT).show();
startActivity(intent);
}
}
});
return v;
}
#Override
public void onResume() {
super.onResume();
}
}
MapFragment (it is now fragmentActivity not fragment);
public class MapFragment extends FragmentActivity implements OnMapReadyCallback,
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
LocationListener {
MapView mMapView;
private GoogleMap googleMap;
// private GoogleMap map;
private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private Location mLastLocation;
private Marker marker;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
mMapView = (MapView) findViewById(R.id.mapView);
mMapView.onCreate(savedInstanceState);
mMapView.onResume(); // needed to get the map to display immediately
try {
MapsInitializer.initialize(this.getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
mMapView.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap mMap) {
googleMap = mMap;
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
Location location = null;
try {
googleMap.setMyLocationEnabled(true);
location = locationManager.getLastKnownLocation(locationManager.getBestProvider(criteria, false));
} catch (SecurityException e) {
e.printStackTrace();
}
if (location != null) {
googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location.getLatitude(), location.getLongitude()), 13));
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(new LatLng(location.getLatitude(), location.getLongitude())) // Sets the center of the map to location user
.zoom(17) // Sets the zoom
.bearing(90) // Sets the orientation of the camera to east
.tilt(40) // Sets the tilt of the camera to 30 degrees
.build(); // Creates a CameraPosition from the builder
googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
}
}
I'm working with Google Maps. I am able to successfully create and can show a Google Map. Now I want to add CameraUpdate(latitude, longitude). I googled and I found some source code but I'm getting a NullPointerException.
The LogCat error message is:
java.lang.NullPointerException: CameraUpdateFactory is not initialized
This is my source. What am I doing wrong?
public class StradaContact extends Fragment {
public final static String TAG = StradaContact.class.getSimpleName();
private MapView mMapView;
private GoogleMap mMap;
private Bundle mBundle;
double longitude = 44.79299800000001, latitude = 41.709981;
public StradaContact() {
}
public static StradaContact newInstance() {
return new StradaContact();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.strada_contact, container,false);
mMapView = (MapView) rootView.findViewById(R.id.pointMap);
mMapView.onCreate(mBundle);
setUpMapIfNeeded(rootView);
return rootView;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBundle = savedInstanceState;
}
private void setUpMapIfNeeded(View inflatedView) {
if (mMap == null) {
mMap = ((MapView) inflatedView.findViewById(R.id.pointMap)).getMap();
if (mMap != null) {
CameraUpdate center = CameraUpdateFactory.newLatLng(new LatLng(latitude, longitude));
CameraUpdate zoom = CameraUpdateFactory.zoomTo(15);
mMap.moveCamera(center);
mMap.animateCamera(zoom);
}
}
}
#Override
public void onResume() {
super.onResume();
mMapView.onResume();
}
#Override
public void onPause() {
super.onPause();
mMapView.onPause();
}
#Override
public void onDestroy() {
mMapView.onDestroy();
super.onDestroy();
}
}
<com.google.android.gms.maps.MapView
android:id="#+id/pointMap"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.MapFragment" />
Try this in "onCreate":
try {
MapsInitializer.initialize(this);
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
Try with following method initialize google map api before using
MapsInitializer.initialize(getActivity());
I have a layout with ActionBar.NAVIGATION_MODE_TABS. The first tab is to display the results in listview and the second in a map. Everything worked great until I have upgraded to the latest version of Google Play Services lib.
Here the fragment used to display the map:
public class PlaceMapFragment extends Fragment {
MapView mapView;
GoogleMap map;
ResultsListener mCallback;
List<Place> places;
private HashMap<String, Place> placeMarker = new HashMap<String, Place>();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
places = mCallback.getPlaces();
View rootView = inflater.inflate(R.layout.mapview, container, false);
mapView = (MapView) rootView.findViewById(R.id.mapview);
mapView.onCreate(savedInstanceState);
map = mapView.getMap();
setUpMap();
return rootView;
}
private void setUpMap() {
map.getUiSettings().setMyLocationButtonEnabled(true);
map.setMyLocationEnabled(true);
/*
try {
MapsInitializer.initialize(this.getActivity());
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
*/
// add markers
}
#Override
public void onResume() {
mapView.onResume();
super.onResume();
setUpMap();
}
#Override
public void onPause() {
mapView.onPause();
super.onPause();
}
#Override
public void onDestroy() {
mapView.onDestroy();
super.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
public interface ResultsListener {
public List<Place> getPlaces();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (ResultsListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement ResultsListener");
}
}
}
I get these errors:
04-05 03:58:22.040: E/AndroidRuntime(661): FATAL EXCEPTION: main
04-05 03:58:22.040: E/AndroidRuntime(661): java.lang.NullPointerException
04-05 03:58:22.040: E/AndroidRuntime(661): at com.tomsyweb.mapslee.fragments.PlaceMapFragment.setUpMap(PlaceMapFragment.java:54)
04-05 03:58:22.040: E/AndroidRuntime(661): at com.tomsyweb.mapslee.fragments.PlaceMapFragment.onCreateView(PlaceMapFragment.java:48)
I have commented the MapsInitializer.initialize(this.getActivity()); part because GooglePlayServicesNotAvailableException gives error.
mapview.xml
<com.google.android.gms.maps.MapView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mapview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
My code is taken from Getting Google Map Fragment in onCreateView using ActionBar tabs
Your map may be null if the device doesn't have the latest version of Maps installed, or perhaps for other reasons. Trying to create it may even prompt the user to start a different activity to update their device. So it's recommended to create an initMap() method like this, and call it in your onCreate(...) and onResume():
private void initMap() {
if(map == null) {
map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
if(map != null) {
// set up map
}
}
}
I have a very simple SupportMapFragment to display a small Google map which I use in this view
The idea is that the user can click it to view a full screen map.
How can I get rid of the +/- button from the map?
If it's not possible, is there an alternative method to get a map?
Here is my MapFragment code:
public class CustomMapFragment extends SupportMapFragment {
private static LatLng mPosFija;
public CustomMapFragment() {
super();
}
public static CustomMapFragment newInstance(LatLng position) {
CustomMapFragment fragment = new CustomMapFragment();
mPosFija = position;
return fragment;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (getMap() != null) {
initMap();
Log.d(getClass().getSimpleName(), "Map ready for use!");
}
}
#Override
public void onResume() {
super.onResume();
initMap();
}
private void initMap() {
Log.v("CustomMapFragment", "initMap");
if (getMap() != null) {
UiSettings settings = getMap().getUiSettings();
settings.setAllGesturesEnabled(true);
settings.setMyLocationButtonEnabled(false);
getMap().clear();
getMap().moveCamera(CameraUpdateFactory.newLatLngZoom(mPosFija, 5));
getMap().addMarker(new MarkerOptions().position(mPosFija).draggable(false));
}
}
}
This is the code for my DialogFragment that adds the mapFragment to the view:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity()) == ConnectionResult.SERVICE_INVALID
|| GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity()) == ConnectionResult.SERVICE_MISSING) {
Log.e("HERE", "Google play not active");
TextViewFragment tvf = new TextViewFragment();
getChildFragmentManager().beginTransaction().replace(R.id.mapview, tvf).commit();
} else {
CustomMapFragment mMapFragment = CustomMapFragment.newInstance(new LatLng(offer.latitude, offer.longitude));
getChildFragmentManager().beginTransaction().replace(R.id.mapview, mMapFragment).commit();
}
}
Ok, so this was staring me in the face and was as simple as
UiSettings settings = getMap().getUiSettings();
settings.setAllGesturesEnabled(false);
settings.setMyLocationButtonEnabled(false);
settings.setZoomControlsEnabled(false);
I have a question and a problem. First of all I don't know is this possible:
I have a fragment activity with tabs. On one tab (which is a fragment) I have a map with a hidden list of items. Map is putted in a frame of that fragment. The list is downloaded and on a button press is visible again. On a map I have markers that represents that items.
My problem is this: I always get map to be null when a use getMap() from a fragment that I put in a frame.
Is this possible? And if not what do you recommend? Thanks in advance.
EDITED
public class MapExplore extends Fragment{
private FrameLayout frame;
private ListView list;
private String api_key;
private GoogleMap map;
private MapExploreAdapter adapter;
private SupportMapFragment map_fragment;
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
api_key = Configuration.get_prefereence_string(getActivity(), "user_activation_key", null);
adapter = new MapExploreAdapter();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.map_explore, null);
frame = (FrameLayout) view.findViewById(R.id.frameMap);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
setUpMapFragment();
}
private void setUpMapFragment(){
if(map_fragment == null){
map_fragment = SupportMapFragment.newInstance();
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.add(frame.getId(), map_fragment, Utils.MAP_FRAGMENT_TAG);
ft.commit();
}
}
private void setUpMap(){
Log.i("SET UP MAP", "Started");
if(map == null){
map = ((SupportMapFragment) map_fragment).getMap();
}
if(map != null){
map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(Utils.SF_LAT, Utils.SF_LON), 13));
}
}
#Override
public void onResume() {
// TODO Auto-generated method stub
super.onResume();
setUpMap();
}
I edited my question with some code...
If you could post some of you code it would be easier to diagnose your problem:
meantime try creating your SupportMap fragment dynamically as follows:
mMapFragment = new SupportMapFragment() {
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
GoogleMap map = mMapFragment.getMap();
if (map != null) {
//Your initialization code goes here
}
}
};
Altenative approach to use Mapview inside fragment as follows:
public class Yourfragment extends Fragment {
private MapView mMapView;
private GoogleMap mMap;
private Bundle mBundle;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View inflatedView = inflater.inflate(R.layout.map_fragment, container, false);
try {
MapsInitializer.initialize(getActivity());
} catch (GooglePlayServicesNotAvailableException e) {
// TODO handle this situation
}
mMapView = (MapView) inflatedView.findViewById(R.id.map);
mMapView.onCreate(mBundle);
setUpMapIfNeeded(inflatedView);
return inflatedView;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBundle = savedInstanceState;
}
private void setUpMapIfNeeded(View inflatedView) {
if (mMap == null) {
mMap = ((MapView) inflatedView.findViewById(R.id.map)).getMap();
if (mMap != null) {
setUpMap();
}
}
}
private void setUpMap() {
mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
}
#Override
public void onResume() {
super.onResume();
mMapView.onResume();
}
#Override
public void onPause() {
super.onPause();
mMapView.onPause();
}
#Override
public void onDestroy() {
mMapView.onDestroy();
super.onDestroy();
}
}
And put map view in XML as follows:
<com.google.android.gms.maps.MapView
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Here is a link to the official documentation for MapView