Why is SupportMapFragment is null (support back to API 9) - android

I have created a Github project that demonstrates the issue.
git clone https://github.com/anujgoyal/buggymap.git
I realize there are existing questions, but very few of them have distilled the program down to this level. In addition I have a hard requirement to use the android.support.v4.app.Fragment class, not FragmentActivity, not MapFragment.
Note that you will have to change android:value for your com.google.android.maps.v2.API_KEY in AndroidManifest.xml
Why is SupportMapFragment NULL?
// MainActivity.java
package com.txt2lrn.buggymap;
import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
}
public static class PlaceholderFragment extends Fragment implements OnMapReadyCallback {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
//SupportMapFragment smf0 =
// (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
SupportMapFragment smf1 =
(SupportMapFragment) getFragmentManager().findFragmentById(R.id.map);
SupportMapFragment smf2 =
(SupportMapFragment)
getActivity().getSupportFragmentManager().findFragmentById(R.id.map);
Log.d("maps", "smf1: "+smf1); // always NULL
Log.d("maps", "smf2: "+smf2); // always NULL
//smf.getMapAsync(this);
return rootView;
}
#Override
public void onMapReady(GoogleMap map) {
// code will go here once getMapAsync works
}
}
}
Here is the fragment_main.xml
<RelativeLayout 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"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity$PlaceholderFragment">
<fragment
android:id="#+id/map"
class="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>

You appear to be trying to use nested fragments. In that case, you get those nested fragments via the FragmentManager returned by getChildFragmentManager() called on your fragment, not getSupportFragmentManager() called on your activity.

Related

how do i solve integrating google map in fragment in android

I have a problem integrating google map in fragment in android. I know how to do it in activity but fragment reference on this site are very old and not working in 2018. I don't have any error.below is fragment file. Any help will be highly appreciated. I have added API key and proper manifest file.
package com.example.narmail.truck30mint.Api.Fragments;
import android.Manifest;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.example.narmail.truck30mint.R;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.MapsInitializer;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import java.util.ArrayList;
public class ViewTrucksFragment extends Fragment {
TextView pageTitle;
MapView mMapView;
private GoogleMap googleMap;
public ViewTrucksFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_view_trucks, container, false);
pageTitle = rootView.findViewById(R.id.view_trucks_title);
String load_id = getArguments().getString("load_id");
String load_from = getArguments().getString("load_from");
String load_to = getArguments().getString("load_to");
if (load_id != null && load_from != null && load_to != null) {
pageTitle.setText("Matching Trucks for "+load_from+" to "+load_to);
}
mMapView= rootView.findViewById(R.id.view_trucks_map);
mMapView.onCreate(savedInstanceState);
mMapView.onResume();
try {
MapsInitializer.initialize(getActivity().getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
mMapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap mMap) {
googleMap = mMap;
googleMap.getUiSettings().setCompassEnabled(true);
googleMap.getUiSettings().setMyLocationButtonEnabled(true);
googleMap.getUiSettings().setRotateGesturesEnabled(true);
// For dropping a marker at a point on the Map
LatLng sydney = new LatLng(30.374219,76.782055);
googleMap.addMarker(new MarkerOptions().position(sydney).
title("Title").snippet("TitleName"));
// 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;
}
}
and below is my layout file
<?xml version="1.0" encoding="utf-8"?>
<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"
android:background="#color/colorWhite"
tools:context=".Api.Fragments.ViewTrucksFragment">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/view_trucks_title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textAlignment="center"
android:layout_marginRight="10dp"
android:layout_marginLeft="10dp"
android:padding="10dp"
android:textColor="#color/colorPrimary"
android:textSize="15sp"
android:text="#string/hello_blank_fragment" />
<com.google.android.gms.maps.MapView
android:id="#+id/view_trucks_map"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.google.android.gms.maps.MapView>
</LinearLayout>
</FrameLayout>
Please follow below step to finish your task. Just need to create 3 files
(1) Create XML layout for map inside your fragment layout fragment_map.xml
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
(2) Create Fragment to load MAP MapFragment.Java
public class MapFragment extends Fragment implements OnMapReadyCallback {
private GoogleMap mMap;
public MapFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_map, container, false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
if(getActivity()!=null) {
SupportMapFragment mapFragment = (SupportMapFragment) getActivity().getSupportFragmentManager()
.findFragmentById(R.id.map);
if (mapFragment != null) {
mapFragment.getMapAsync(this);
}
}
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
//Do your stuff here
}
}
(3) Create Activity to load MAP fragment MapsActivity.java
public class MapsActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.content,new MapFragment());
fragmentTransaction.commit();
}
}
For MAP key you need to follow same step you have done in your project. Hope this step will help you.
Inside Gradle please use below gradle
implementation 'com.google.android.gms:play-services-maps:15.0.1'
AndroidManifest.xml define below things.
<uses-permission android:name="android.permission.INTERNET"/>
Inside Application Tag.
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR MAP KEY" />

MapView in scroll tab display nothing

please help.
I am trying to display a google map in a scroll tab, but I am getting a blank google map.
Since I am using the scroll tab, I use android.support.v4.app.Fragment in the PagerAdapter class and the fragment class which should display the map.
The following is fragment class to display a google map
package ui;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.bdushimi.bjhangout.R;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.MapsInitializer;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
public class MapTab extends Fragment implements OnMapReadyCallback {
public static View view;
private GoogleMap mGoogleMap;
private MapView mapView;
private FusedLocationProviderClient mFusedLocationProviderClient;
private SupportMapFragment mapFragment;
public MapTab() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_map, container, false);
return view;
}
#Override
public void onViewCreated(View v, #Nullable Bundle savedInstanceState) {
super.onViewCreated(v, savedInstanceState);
mapView = (MapView) this.view.findViewById(R.id.map);
if (mapView != null) {
mapView.onCreate(savedInstanceState);
mapView.onResume();
mapView.getMapAsync(this);
}
}
#Override
public void onMapReady(GoogleMap googleMap) {
MapsInitializer.initialize(this.getActivity());
mGoogleMap = googleMap;
googleMap.addMarker(new MarkerOptions().position(new LatLng(40.689247, -74.044502))
.title("You're here"));
}
}
The following is the xml
<RelativeLayout 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="ui.MapTab">
<com.google.android.gms.maps.MapView
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.google.android.gms.maps.MapView>
</RelativeLayout>
I would like to know where I am getting wrong or possibly another approach I should consider. Thanks

java.lang.IllegalStateException: Activity has been destroyed at Calling fragment inside another fragment to replace on framelayout

I am new to android and learning fragment instead of multiple, i have problem. when i call planet fragment from friends "java.lang.IllegalStateException: Activity has been destroyed" android runtime FATAL exception occurs here is my code. i saw this page but couldn't figure out how to use it. I will be grateful for any help
fragment_planet.xml
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
android:gravity="center"
android:padding="32dp" />
Friends.java
package com.app.hubara;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class Friends extends Fragment {
public Friends() { }
View rootView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.content_friends, container, false);
MainActivity main = new MainActivity();
main.friends();
return rootView;
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="100dp"/>
<Button
android:id="#+id/display"
android:height="70dp"
android:width="300dp"
android:layout_marginTop="0dp"
android:text="Display"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
MainActivity
package com.app.hubara;
import android.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import java.util.Locale;
import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity {
FragmentManager fragmentManager;
FragmentTransaction fragmentTransaction;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.display);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Friends frag_friends = new Friends();
fragmentManager = getFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content_frame, frag_friends);
fragmentTransaction.commit();
}
});
}
public void friends(){
PlanetFragment planetFragment = new PlanetFragment();
fragmentManager = getFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content_frame, planetFragment);
fragmentTransaction.commit();
}
public static class PlanetFragment extends Fragment {
public PlanetFragment() { }
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_planet, container, false);
int i = getArguments().getInt("Earth");
String planet = getResources().getStringArray(R.array.planets_array)[i];
int imageId = getResources().getIdentifier(planet.toLowerCase(Locale.getDefault()),
"drawable", "Earth");
((ImageView) rootView.findViewById(R.id.image)).setImageResource(imageId);
getActivity().setTitle(planet);
return rootView;
}
}
}
To access an Activity, you shouldn't do this:
MainActivity main = new MainActivity();
main.friends();
Because this destroys current Activity then instantiates another new Activity.
You can access it appropriately by calling getActivity():
MainActivity main = getActivity();
main.friends();
Note that actually you are recommended to define and use an interface to communicate between Fragment and Activity. If you want to learn further, please refer to the official training.

Drawer menu view requires 2 clicks

A repo with example: https://bitbucket.org/troffel/drawer-button-error
I've come across an issue I can't for the life of me figure out. From a much larger project I was able to deduce it into a smaller dummy project.
Problem:
When the app launches, the buttons in the drawer menu works correctly. However, after changing orientation one or more times the buttons all of a sudden require two key presses.
When logging out events, it shows that the eventlistener connected to the clicked views is triggered, however nothing seem to happen on first click.
I added the main files to the post, repo so you can replicate it if interested.
Any help is much appreciated.
Main layout:
</LinearLayout>
<LinearLayout
android:id="#+id/left_drawer"
android:orientation="vertical"
android:layout_width="300dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#android:color/background_light">
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
layout of initial fragment(category_fragment):
<ListView
android:id="#+id/left_drawer_listview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:choiceMode="singleChoice"/>
<View
android:layout_height="1dp"
android:layout_width="match_parent"
android:background="#ecebec"/>
<TextView
android:id="#+id/drawer_settings"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textColor="#android:color/black"
android:textSize="20sp"
android:clickable="true"
android:onClick="openSettings"
android:gravity="center_vertical"
android:text="Settings"
android:paddingLeft="10sp"/>
</LinearLayout>
fragment that replaces the initial(preffragment):
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="#+id/settings_checkbox_container"
android:layout_weight="1">
</LinearLayout>
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:id="#+id/settings_back"
android:text="Save"
android:layout_weight="1"/>
</LinearLayout>
Mainactivity:
package com.example.testdrawer;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.left_drawer, new CategoryFragment());
fragmentTransaction.commit();
}
public void openSettings(View v){
FragmentManager fmanager = getSupportFragmentManager();
FragmentTransaction ftrans = fmanager.beginTransaction();
PrefFragment prefFragment = new PrefFragment();
ftrans.replace(R.id.left_drawer, prefFragment);
ftrans.commit();
Log.i("test", "Opening settings");
}
}
categoryfragment code:
package com.example.testdrawer;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class CategoryFragment extends Fragment{
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View v = inflater.inflate(R.layout.category_fragment, container, false);
//drawer menu
return v;
}
}
Preffragment.java:
package com.example.testdrawer;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
public class PrefFragment extends Fragment{
private Context context;
private View checkbox_container;
private Button settingsBack;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = getActivity().getApplicationContext();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.preffragment, container, false);
checkbox_container = v;
settingsBack = (Button) v.findViewById(R.id.settings_back);
settingsBack.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
saveSettings();
}
});
//setupSimplePreferencesScreen();
return v;
}
public void saveSettings(){
//setSettings(checkbox_container);
FragmentManager fmanager = getFragmentManager();
FragmentTransaction ftrans = fmanager.beginTransaction();
ftrans.replace(R.id.left_drawer, new CategoryFragment());
ftrans.commit();
Log.i("test", "saving settings");
}
}
OK! This is super weird, but I found the problem.
Using replace(container, fragment) instead of add(container, fragment) in my solved the issue.
The problem was that I was calling add(container, fragment) in my activitys onCreate method. This meant that when an orientation change happened, it would call add(container, fragment) on top of the already existing one.
replace(container, fragment) works because it, logically, replaces the existing one.
A solution that includes using add(container, fragment) would be to have remove(fragment) in my activitys onDestroy method, thus avoiding doable drawing.
Hope it saves someone else some time!

How to access map fragment from main view

I have a java class that extends fragment and inflates an xml layout. Below is my code for that java class:
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.SupportMapFragment;
/**
* Created by Mike on 3/17/14.
*/
public class BreweryMap extends Fragment {
public BreweryMap(){}
String beerId = "";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.activity_brewmap, container, false);
setHasOptionsMenu(true);
//get user information
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
String userName = prefs.getString("userName", null);
String userID = prefs.getString("userID", null);
//call async to get breweries to add to
GoogleMap mMap;
mMap = ((SupportMapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
//add url
String url = "hmyURL";
//send mMap over with async task
new GetVisitedBreweries(getActivity(), mMap).execute(url);
return rootView;
}
}
Here is the xml layout that is being inflated:
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.google.android.gms.maps.MapFragment"/>
My null pointer error is coming from this line:
mMap = ((SupportMapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
After looking at my code this makes sense to me that it is NULL because the fragment ID that it is looking for is in my rootView which is stored on this line:
View rootView = inflater.inflate(R.layout.activity_brewmap, container, false);
How can I successfully access the map fragment from my rootView?
I have tried:
mMap = ((SupportMapFragment) rootView.getFragmentManager().findFragmentById(R.id.map)).getMap();
and other combinations. I feel like I am close but not quite.
You are mixing Fragment and SupportFragment. Use SupportFragment everywhere:
In your layout: use com.google.android.gms.maps.SupportMapFragment
In onCreate(): use getSupportFragmentManager()

Categories

Resources