In my application there is a fragment activity containing three tabs(map,list,settings). I have put remove and commit at onPause() method of map tab(extends fragment). When i toggle between tabs, it is working fine but when I move to next page(next activity) and come back, it throws nullpointer exception.
Because when I switch to next activity, onPause() map fragment has been removed and committed and when comes back it found it null and throws exception. I am unable to figure out, where to place my onPause() method code or how to init fragment again on restart or resume.
public class LocatorMainActivity extends FragmentActivity {
public class MapSectionFragment extends Fragment {
GoogleMap map;
public MapSectionFragment() {
}
/*
* (non-Javadoc)
*
* #see android.support.v4.app.Fragment#onDestroyView()
*/
#Override
public void onDestroyView() {
// TODO Auto-generated method stub
super.onDestroyView();
Log.e("", "onDestroyView");
/*try{
Fragment fragment = (getFragmentManager()
.findFragmentById(R.id.map));
ft = getFragmentManager()
.beginTransaction();
//ft.addToBackStack(null);
ft.remove(fragment);
ft.commit();
//getFragmentManager().executePendingTransactions();
//ft.commitAllowingStateLoss();
}catch(Exception e){
Log.e("", "Exception::" + e.toString());
}*/
}
#Override
public void onPause(){
super.onPause();
Log.e("", "onPause");
try{
Fragment fragment = (getFragmentManager()
.findFragmentById(R.id.map));
ft = getFragmentManager()
.beginTransaction();
//if(ft.isAddToBackStackAllowed()){
//ft.hide(fragment);
if(ft.isAddToBackStackAllowed()){
Log.e("", "back stack allowed");
ft.remove(fragment);
//ft.addToBackStack(getTag());
//ft.addToBackStack(null);
ft.commit();
}
//}
//getFragmentManager().executePendingTransactions();
//ft.commitAllowingStateLoss();
}catch(Exception e){
Log.e("", "Exception::" + e.toString());
}
}
/*
#Override
public void onResume(){
super.onResume();
Log.e("inner", "onResume");
}*/
#Override
public void onStop() {
super.onStop();
Log.e("inner", "onStop");
//mReturningWithResult = false;
}
View rootView = null;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//code
});
return rootView;
}
}
}
Please suggest me where I am wrong.
Thanks.
In my working map fragment code, I've got the remove/commit of the map fragment (I'm using SupportMapFragment) within the onDestroyView() method, and I've got the initialization of the map within the onActivityCreated() method, as shown below:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
FragmentManager fm = getFragmentManager();
myMapFragment = (SupportMapFragment) fm.findFragmentById(R.id.id_for_your_map_fragment);
if (myMapFragment == null) {
myMapFragment = (SupportMapFragment) SupportMapFragment.newInstance();
/* Code omitted here... all you have to do here is get your
* fragment manager and run a replace() operation to swap the new fragment in
*/
}
myMap = myMapFragment.getMap();
}
#Override
public void onDestroyView () {
super.onDestroyView();
try {
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.remove(myMapFragment).commit();
}
catch (Exception e) {
e.printStackTrace();
}
}
And finally, within onResume(), I run this check to make sure that the map is not null; if it is, I run the getMap() method:
#Override
public void onResume() {
if (myMap == null) {
FragmentManager fm = getFragmentManager();
myMapFragment = (SupportMapFragment) fm.findFragmentById(R.id.id_for_your_map_fragment);
myMap = myMapFragment.getMap();
}
}
Having these snippets arranged in the places specified above has worked for me so far. I hope this helps! :)
my issue resolved by putting these code:
public class Fragment1 extends Fragment {
GoogleMap map;
#Override
public void onStart() {
// TODO Auto-generated method stub
map = ((SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map)).getMap();
super.onStart();
}
/*
* (non-Javadoc)
*
* #see android.support.v4.app.Fragment#onDestroyView()
*/
#Override
public void onDestroyView() {
// TODO Auto-generated method stub
Fragment fragment = (getFragmentManager()
.findFragmentById(R.id.map));
if (fragment.isResumed()) {
getFragmentManager().beginTransaction().remove(fragment)
.commit();
}
super.onDestroyView();
}
Related
I have two activities A and B which is extending one Base class Main and this Base class has one Framelayout in its layout which we are including in both of the activities A and B respective layouts.
I am checking the instance creation of fragment in Fragment which I am also inflating when I go into particular acitivity.
Here my code is :
public class BaseAcitvity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base_acitvity);
}
}
Here is my FirstActivity::
public class FirstActivity extends BaseAcitvity {
public FirstFragment firstFragment ;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.firstactivitylayout);
firstFragment = new FirstFragment();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.card_view_layout,firstFragment).commit();
Button buttonclick = (Button)findViewById(R.id.clickfirstactivity);
buttonclick.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent(getApplicationContext(),SecondActivity.class);
startActivity(intent);
}
});
}
}
public class SecondActivity extends BaseAcitvity {
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.secondactivity);
FirstFragment fragment = FirstFragment.getInstance();
if(fragment == null)
{
fragment = new FirstFragment();
}
else {
FragmentManager fragmentManager = getFragmentManager();
if(fragment !=null)
{
fragmentManager.beginTransaction().replace(R.id.card_view_layout,fragment).commit();
}
}
}
}
And The Fragment is ::
public class FirstFragment extends Fragment {
private static FirstFragment currentInstance;
FirstFragment () {
currentInstance = this;
}
public static synchronized FirstFragment getInstance() {
if (currentInstance == null)
currentInstance = new FirstFragment();
return currentInstance;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
return inflater.inflate(R.layout.fragment_one, container, false);
}
}
Now my issue is if I have already created the instance of fragment in FirstActivity and checking the singleInstance in Fragment , the at the time of SecondActivity why the OncreatView() of fragment doesn't call where the instance gives not null.
Please help me..so that is there any way to call OncreateView() to inflate the fragmentLayout.
public class Trees extends FragmentActivity implements GoogleMap.OnMarkerClickListener {
private GoogleMap mMap;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_trees);
setUpMapIfNeeded();
}
#Override
protected void onResume() {
super.onResume();
setUpMap();
}
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the map.
if (mMap == null) {
// Try to obtain the map from the SupportMapFragment.
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
mMap.setMyLocationEnabled(true);
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(latitude, longitude),17));
}
}
}
First of all, change your FragmentActivity to Fragment. Also since MapFragment is also a Fragment, so you will be having nested Fragments now. There are plenty of solutions/hacks available to use nested Fragment (for your case it is MapFragment inside Fragment). But the most recommended one is to add MapFragment dynamically to your Fragemnt. For that you have to follow these simple steps.
First of all you should simply have a FrameLayout in your mapfragment.xml like this
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android
android:id="#+id/fl_map"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</FrameLayout>
Now you have to dynamically add SupportMapFragment in your Fragment
private SupportMapFragment fragment;
Inside your onActivityCreated(), copy this code
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
FragmentManager fm = getChildFragmentManager();
if (fragment == null) {
fragment = SupportMapFragment.newInstance();
fm.beginTransaction().replace(R.id.fl_map, fragment).commit();
}
}
since FragmentTransaction will take some time so you have to initialise your map in onResume() like this
#Override
public void onResume() {
super.onResume();
if (mMap == null)
mMap = fragment.getMap();
try {
if (mMap != null) {
builder = new LatLngBounds.Builder();
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
mMap.getUiSettings().setZoomControlsEnabled(false);
mMap.getUiSettings().setZoomGesturesEnabled(true);
mMap.setMyLocationEnabled(true);
// do whatever you want to do with map
}
} catch (Exception e) {
e.printStackTrace();
}
}
Also don't forget to add this code in onDetach() of Fragment
#Override
public void onDetach() {
super.onDetach();
try {
Field childFragmentManager = Fragment.class
.getDeclaredField("mChildFragmentManager");
childFragmentManager.setAccessible(true);
childFragmentManager.set(this, null);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (Exception e) {
e.printStackTrace();
}
}
Hope this will help you.
I had created tabview with swipe using Fragments and FragmentPagerAdapter. In the fragment's hosting activity, I had added a fragment and that fragment shows tabview using TabHost. 1st tab has a listview that displays data from DB using CursorLoader and the 2nd one is mapView.
Everything works fine in portrait mode.
Problem occurs in following case:
User is using app in landscape mode. He opened tabbed view screen. Data is displayed in the listview from the cursor loader. Mapview is also displayed in the second tab. So far everything is working as required.
He left the app as is.(Means, he did not pressed back button, home button or switched to another app)
Screen went off after some time.
When user unlocks the device, my app's tabbed view will be visible again. But,now listview does not show any data and mapview also disappeared.
ClientListFragment
public class ClientListFragment extends SwipeRefreshListFragment {
private static final String TAG = "ClientListFragment";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e(TAG, "onCreate");
setHasOptionsMenu(true);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setColorScheme(R.color.gplus_color_1, R.color.gplus_color_2,
R.color.gplus_color_3, R.color.gplus_color_4);
}
#Override
public void onResume() {
super.onResume();
Log.e(TAG, "onResume");
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.e(TAG, "onActivityCreated");
}
#Override
public void onPause() {
// Log.i(TAG, "onPause");
super.onPause();
}
#Override
public void onStop() {
super.onStop();
Log.e(TAG, "onStop");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy");
}
}
Map Fragment
public class ClientMapFragment extends Fragment {
private static final String TAG = "ClientMapFragment";
private GoogleMap googleMap;
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.map_fragment, container, false);
googleMap = ((MapFragment) getFragmentManager().findFragmentById(
R.id.map)).getMap();
googleMap.setMyLocationEnabled(true);
return v;
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onStop() {
super.onStop();
}
#Override
public void onPause() {
super.onPause();
}
}
Activity
public class ClientActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean isTablet = getResources().getBoolean(R.bool.isTablet);
if (isTablet)
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
else
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
setContentView(R.layout.activity_clients);
ClientFragment clientFragment = new ClientFragment();
Bundle bundle = new Bundle();
bundle.putBoolean("ShouldChangeActionBarTitle", true);
clientFragment.setArguments(bundle);
getFragmentManager()
.beginTransaction()
.add(R.id.fragmentContainer, clientFragment,
getResources().getString(R.string.clients_fragment))
.commit();
}
}
FragmentpagerAdapter
public class TabsPagerAdapter extends FragmentStatePagerAdapter {
private static final String TAG = "TabsPagerAdapter";
private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
FragmentManager fm;
public TabsPagerAdapter(FragmentManager fm) {
super(fm);
this.fm = fm;
mFragments.add(new ClientListFragment());
mFragments.add(new ClientMapFragment());
}
#Override
public Fragment getItem(int index) {
Log.e(TAG, "getItem");
return mFragments.get(index);
}
#Override
public int getCount() {
return mFragments.size();
}
}
Update 1
So, after doing hours of research I came to a conclusion that, it is problem with fragment's state in the FragmentPagerAdapter. When screen is turned off fragmentpager's saveState is called.. When the device is unlocked again, fragment's will be restored from previous state. I verified that LoaderManager callbacks are called, and data was also fetched from DB. But, didn't appeared on screen.
I didn't even bothered about looking at my activities code at once. Everytime, a new fragment was created in onCreate(). The fix is very simple.
if (savedInstanceState == null) {
Log.e(TAG, "onCreate savedInstanceState == null");
ClientFragment clientFragment = new ClientFragment();
Bundle bundle = new Bundle();
bundle.putBoolean("ShouldChangeActionBarTitle",
shouldChangeActionBarTitle);
clientFragment.setArguments(bundle);
getFragmentManager()
.beginTransaction()
.add(R.id.fragmentContainer, clientFragment,
getResources().getString(R.string.clients_fragment))
.commit();
}
I have a MainActivity which has an ActionBar with two tab, the first tab is to show the sensor data value and the second tab I want to show the Map.
But I have a problem to implement the map in the fragment on the second tab
The MainActivity is shown as below:
public class MainActivity extends Activity
{
private static final String DATA_FRAGMENT_BAR = "Data";
private static final String MAP_FRAGMENT_BAR = "Map";
private DataCollection mDataCollection;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Config.mContext = this;
ActionBar actionBar = getActionBar();
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME| ActionBar.DISPLAY_SHOW_CUSTOM);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab dataTab = actionBar.newTab().setText(DATA_FRAGMENT_BAR);
ActionBar.Tab mapTab = actionBar.newTab().setText(MAP_FRAGMENT_BAR);
Fragment dataFragment = new FragmentData();
Fragment mapFragment = new FragmentMap();
dataTab.setTabListener(new MyTabsListener(dataFragment));
mapTab.setTabListener(new MyTabsListener(mapFragment));
actionBar.addTab(dataTab);
actionBar.addTab(mapTab);
mDataCollection = DataCollection.getInstance();
}
....
}
The TabsListener is shown as below
public class MyTabsListener implements ActionBar.TabListener
{
private Fragment fragment;
public MyTabsListener(Fragment fragment)
{
this.fragment = fragment;
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
ft.replace(R.id.fragment_container, fragment);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
ft.remove(fragment);
}
}
The the map fragment class is shown as below:
public class FragmentMap extends Fragment
{
MapView mapView;
GoogleMap map;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.fragment_map, 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);
map.addMarker(new MarkerOptions().position(new LatLng(50.167003,19.383262)));
// 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();
}
}
I set a break point in the FragmentMap class at the line "mapView.onCreate(savedInstanceState);" the savedInstanceState is null and the program will crash after line.
Can someone help. Thanks in advance.
Google released the Map API Version 2. This gives you a MapFragment and a SupportMapFragment. This allows you to add a Map without extending MapActivity.
Google Maps v2 In fragment cashes when clicked twice
It is not really clear in the documentation, but the MapView.onCreate() method should be called in the Fragment.onActivityCreated(), not in Fragment.onCreate()
Also, MapView.getMap() can return null, don't forget to check with that.
And you should call super.onResume() before mapView.onResume()
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