My application has 3 tabs and in one of them I want to display a map(HERE MAPS, not Google Maps). I was able to get the map to work perfectly in an Activity, but in Fragment Class when I try to cast the Fragment view to the MapFragment an error is thrown.
MapFragment mapFragment = (MapFragment)
getFragmentManager().findFragmentById(R.id.mapfragment);
Error:
Inconvetible types: cannot cast android.support.v4.app.support to com.here.android.mpa.mapping.MapFragment
Please correct me if Im wrong, but the reason for this to happen is because we canĀ“t use android.app.Fragment(used to display the map, as instructed in HERE MAPS DOC) in an android.support.v4.app.Fragment(used for the TabsLayout).
I found many questions related to this error using Google Maps. but just two(first,second)about the same error when using HERE MAPS, and none really helped to solve the problem.
In google Maps you can use SupportMapFragment(), but this mehod only works for Google Maps. Is there any solution for this using Here Maps? maybe a different approach to reach the same goal? or am I missing something when implementing this Here Maps in a TabLayout?
Any help will be appreciated!
My code:
MapFragment.java
public class Map extends Fragment {
public Map() {}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_map, container, false);
MapFragment mapFragment = (MapFragment)
getFragmentManager().findFragmentById(R.id.mapfragment);
mapFragment.init(new OnEngineInitListener() {
#Override
public void onEngineInitializationCompleted(
OnEngineInitListener.Error error) {
if (error == OnEngineInitListener.Error.NONE) {
com.here.android.mpa.mapping.Map map = mapFragment.getMap();
} else {
System.out.println("ERROR: Cannot initialize MapFragment");
}
}
};
return view;
}
fragment_map.xml
<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="com.example.modulos.tabsMenu.Config">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="#+id/mapFragmentContainer"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center"
android:background="#aaa" >
<fragment
class="com.here.android.mpa.mapping.MapFragment"
android:id="#+id/mapfragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center"
android:background="#aaa" >
<!-- other things here -->
</LinearLayout>
</FrameLayout>
Since the HERE Maps SDK only works with API Level 15 and above, there's no support for compatibility fragments (that you mainly need when you target lower API levels).
In some cases you still want to deal with support fragment even if you have Android 4 or newer as target, in those cases you have to use the the MapView of the HERE SDK and embedded it in your layout on your own.
See this code example where also MapView is used: https://tcs.ext.here.com/sdk_examples/MapDownloader.zip
So, it will look like this:
Add in your layout the MapView:
<com.here.android.mpa.mapping.MapView
android:id="#+id/ext_mapview"
android:visibility="visible"
android:layout_width="match_parent"
android:layout_height="match_parent" />
And then in your code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mapView = (MapView) findViewById(R.id.ext_mapview);
MapEngine.getInstance().init(this, engineInitHandler);
}
private OnEngineInitListener engineInitHandler = new OnEngineInitListener() {
#Override
public void onEngineInitializationCompleted(Error error) {
if (error == Error.NONE) {
map = new Map();
mapView.setMap(map);
// more map initial settings
} else {
Log.e(TAG, "ERROR: Cannot initialize MapEngine " + error);
}
}
};
#Override
public void onResume() {
super.onResume();
MapEngine.getInstance().onResume();
if (mapView != null) {
mapView.onResume();
}
}
#Override
public void onPause() {
if (mapView != null) {
mapView.onPause();
}
MapEngine.getInstance().onPause();
super.onPause();
}
It's important that you handle the MapEngine and MapView Pause and Resume, otherwise you would get poor performance results.
Surely is a silliness ask this, but do you check if are you using MapFragment from the right package?
You must be using this class com.here.android.mpa.mapping.MapFragment, maybe by error you import this one com.google.android.gms.maps.MapFragment.
Related
This question already has answers here:
Google Maps - Android App not load - null object reference
(2 answers)
Closed 7 months ago.
In my application i'm using navigation drawer with swipe tabs (following this) and inside one of these tabs i want to use google maps. I'm getting this error:
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.google.android.gms.maps.SupportMapFragment.getMapAsync(com.google.android.gms.maps.OnMapReadyCallback)' on a null object reference
I've searched and discovered that i can only call getMapAsync() on the main thread. However nearly all the solutions i faced were using deprecated methods. How can I initialise the map,to avoid the null exception, and only call it on this tab?
My Tab Fragment
public class PrimaryFragment extends Fragment implements OnMapReadyCallback {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.primary_layout,container,false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
SupportMapFragment supportMapFragment = ((SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map));
supportMapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
//toDO
}
}
The tab fragment xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:id="#+id/map"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
class="com.google.android.gms.maps.SupportMapFragment"/>
</FrameLayout>
You can replace this line --
SupportMapFragment supportMapFragment = ((SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map));
to this --
SupportMapFragment supportMapFragment = ((SupportMapFragment) view.getChildFragmentManager().findFragmentById(R.id.map));
Hope this helps!
I having trouble implementing Google Map in Fragment.
This is my the part of my fragment class:
public class FragmentStoreFinderMap extends Fragment implements OnMapReadyCallback {
// Google Map
private GoogleMap googleMap;
private int i;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
googleMap = ((SupportMapFragment)getActivity().getSupportFragmentManager().findFragmentById(
R.id.map)).getMapAsync(this);
I am getting an error in getMapAsync(this). I tells Incompatible type.
it says:
required: com.google.android.gms.map.GoogleMap
found: void
BTW here is my xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<fragment class="com.google.android.gms.maps.SupportMapFragment"
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
In your XML layout you should do like this
<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">
<com.google.android.gms.maps.MapView
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
inside your fragment implement this
private MapView mapView;
private GoogleMap googleMap;
override onCreateView if there is no onCreateView just like the code below
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.your_layout, container, false);
}
override onViewCreated() inside that
onViewCreated() put this
mapView = (MapView) view.findViewById(R.id.map);
mapView.onCreate(savedInstanceState);
mapView.onResume();
mapView.getMapAsync(this);//when you already implement OnMapReadyCallback in your fragment
when you already implement OnMapReadyCallback in your fragment put this/code like this
#Override
public void onMapReady(GoogleMap map) {
googleMap = map;
}
hope this helps you.
After a few overheats in my head, thanks to this post and https://stackoverflow.com/a/34732804/3925554, I would say that currently there are two ways of adding a MapFragment to your app:
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
class="com.google.android.gms.maps.SupportMapFragment"
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
By this way, you have to use a standard fragment and implement this inside. Actually you are inserting a fragment into another:
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
SupportMapFragment supportMapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map);
supportMapFragment.getMapAsync(this);
}
The other way would be extending the real SupportMapFragment and implement it in this manner without the need of an xml:
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getMapAsync(this);
}
And they work without having to set a layout in onCreateView neither call mapView.onCreate(savedInstanceState); and mapView.onResume(); manually inside onViewCreated(), what is not recommended anyway.
Hope it helps!
SupportMapFragment mMapFragment = SupportMapFragment.newInstance();
FragmentTransaction fragmentTransaction =
getChildFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.flMap, mMapFragment);
fragmentTransaction.commit();
mMapFragment.getMapAsync(this);
Your code is returning this error because getMapAsync() does not return anything. If you look at the documentation for this function:
public void getMapAsync (OnMapReadyCallback callback)
Sets a callback object which will be triggered when the GoogleMap
instance is ready to be used.
Note that:
This method must be called from the main thread. The callback will be
executed in the main thread. In the case where Google Play services is
not installed on the user's device, the callback will not be triggered
until the user installs it. In the rare case where the GoogleMap is
destroyed immediately after creation, the callback is not triggered.
The GoogleMap object provided by the callback is non-null.
OnMapReadyCallback is an interface that needs implemented and passed to through this function. Nothing is currently assigned to your googleMap variable you should instead set its value in this block of code which implements OnMapReadyCallback
#Override
public void onMapReady(GoogleMap googleMap) {
this.googleMap = googleMap;
}
This code should be in your Fragment somewhere. Since your Fragment already implements this interface you do pass it in as this.
I move my application eclipse to android studio. My code works perfect on Eclipse but on Android studio
mapView = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
return null
my xml is here
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
xmlns:ads="http://schemas.android.com/apk/res-auto"
>
<com.google.android.gms.ads.AdView
android:id="#+id/adMob"
android:layout_width="fill_parent"
android:layout_height="70dp"
android:layout_alignParentBottom="true"
ads:adSize="BANNER"
ads:adUnitId="#string/admob_unit_id" />
<fragment
android:id="#+id/map"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
class="com.google.android.gms.maps.SupportMapFragment"/>
</LinearLayout>
why it return null?
I searched and compileSdkVersion 21 cause it. But if I change it 19 still return null
getMap() is not guaranteed to return a map instance. Use getMapAsync(OnMapReadyCallback) where the callback will be invoked once the map is ready and you're guaranteed it won't be null. This is available since Google Play Services library v6.5.
When using this approach get rid of your mapView variable, the callback will receive a map reference anyway. Also note that SupportMapFragment is not MapView is not GoogleMap (I'm referring to the misnamed variable here, be careful.).
EDIT: Suggested solution:
public class MainActivity extends ActionBarActivity {
SupportMapFragment mMapFragment;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.activity_main);
mMapFragment = getSupportFragmentManager().findFragmentById(R.id.map);
// etc.
}
public void doSomethingWithMap() {
mMapFragment.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap googleMap) {
// do whatever you need with the map
}
});
}
}
The point is when you need to access the map, you ask the fragment for it, and it will be delivered to you via a callback.
I have an activity that hosts two fragments. One fragment provides some info to the user in various fields. The other fragment should show a Map.
For the fragment hosting the map I need to be able to add custom logic for displaying markers and several other things that I would like to reuse in other places in the app. What is the best way to create a map without defining the fragment in xml like:
<fragment
class="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Thanks,
Nathan
Edit:
I am now using nested fragments, not sure if that is the best way to handle this? My mapfragment is now:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<fragment
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.MapFragment" />
</LinearLayout>
and the Fragments code is:
public class ViewCurrentMapFragment extends Fragment implements View.OnClickListener {
public static final String TAG = "MAP_FRAGMENT";
private GoogleMap map;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_view_current_map, container, false);
return rootView;
}
private void getCurrentMarkers() {
// Getting reference to the SupportMapFragment of activity_main.xml
SupportMapFragment smf = ((SupportMapFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.map));
map = smf.getMap();
}
#Override
public void onClick(View v) {
}
#Override
public void onResume() {
super.onResume();
getCurrentMarkers();
}
}
The problem I am having now is that smf.getMap() is returning null. Any ideas?
Edit2:
Got it to work by changing:
com.google.android.gms.maps.MapFragment
to
com.google.android.gms.maps.SupportMapFragment
Maybe:
<fragment
class="com.mycompany.MyCustomFragmentExtendingMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
or nest fragments like here: http://code.google.com/p/gmaps-api-issues/issues/detail?id=5064#c1
In my application i have a sliding menu which has been developed by jfeinstein10.
It's working fine in my application ;)
I have a Fragment which is host of MapView. This fragment like my other fragments extended from Fragment class. Just in this Fragment, there is black cover/layer on top of menu contents when I open sliding menu. There is no black cover when I open menu in other fragments. Also, the thing that I found is height of box is exactly as same height as fragment.
Have you seen this problem before? any comments or suggestion would be appreciated.
=>
Update
Based on what Selei suggested I set background to transparent. However, regardless of what color I'm assigning (transparent or other colors) it's still visible and black :(
This is my code:
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.gms.maps.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="#+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
map:uiCompass="true"
android:background="#00000000"/>
The solution was adding map:zOrderOnTop="true" to XML.
For more info please refer to this link.
I tried all the methods here but none of them worked great. Using the GoogleOptions to move the zOrder to the top meant the basic zoom controls were hidden behind the map.
The last suggestion at this link: https://github.com/jfeinstein10/SlidingMenu/issues/168#issuecomment-17065660 (ckakei) fixed it for me.
The trick is to add an empty, transparent view to the layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<FrameLayout
android:id="#+id/view_map"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</FrameLayout>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent" />
I'm inflating this view then in a Fragment. I replace the view_map FrameLayout with the SuppportMapFragment.
This is the important part from that class:
private GoogleMap googleMap;
private SupportMapFragment mapFragment;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.view_map_layout, container,
false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
FragmentManager fm = getChildFragmentManager();
if (mapFragment == null) {
mapFragment = SupportMapFragment.newInstance();
}
if (savedInstanceState == null) {
mapFragment.setRetainInstance(true);
} else {
googleMap = mapFragment.getMap();
}
fm.beginTransaction().replace(R.id.view_map, mapFragment).commit();
}
set the MapView background transparent - android:background="#00000000"
I just made map copy view which copy the map when the sliding menu open or close
#SuppressWarnings("deprecation")
#SuppressLint("NewApi")
private void showMapCopy(boolean show) {
View map = findViewById(R.id.map);
View mapCopy = findViewById(R.id.map_copy);
if (show) {
map.setDrawingCacheEnabled(true);
Bitmap bitmap = map.getDrawingCache();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
mapCopy.setBackgroundDrawable(new BitmapDrawable(getResources(), bitmap));
else
mapCopy.setBackground(new BitmapDrawable(getResources(), bitmap));
mapCopy.setVisibility(View.VISIBLE);
} else {
map.setDrawingCacheEnabled(false);
mapCopy.setVisibility(View.GONE);
}
}
Sliding Menu Open Listener
mMenu.setOnClosedListener(new OnClosedListener() {
#Override
public void onClosed() {
showMapCopy(false);
}
});
OnOptionItemSelected
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.abs__home:
case android.R.id.home:
showMapCopy(true);
mMenu.toggle();
return true;
default:
return super.onOptionsItemSelected(item);
}
}