Select to view content in your preferred language

Map View in Fragment with Tab Action Bar

7884
11
06-04-2012 12:23 PM
AmelieBernier
Emerging Contributor
I have an application that uses ActionBarSherlock and Tab navigation with the Android compatibility library. I have 4 fragments that are attached or detached with FragmentTransaction depending on the selected tab.

One of the fragment should display a MapView, but I cannot seem to make it work.  Do you have examples of using a MapView within a fragment, or any tips for implementing this? 


Here is my code. One of the things I tried is to simply retrieve the MapView from the XML Layout, but the app just crashes at startup.

import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.ActionBar.Tab;
import com.actionbarsherlock.app.SherlockFragmentActivity; 
import android.os.Bundle;  
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;

public class ActionBarTabsActivity extends SherlockFragmentActivity {  
   
 @Override 
 public void onCreate(Bundle savedInstanceState) {  
  super.onCreate(savedInstanceState); 
  
  ActionBar actionBar = getSupportActionBar();  
  actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
      
  String label1 = getResources().getString(R.string.mapTabLabel);  
  Tab tab = actionBar.newTab();  
  tab.setText(label1);  
  TabListener<MapFragment> tl = new TabListener<MapFragment>(this,  
    label1, MapFragment.class);  
  tab.setTabListener(tl);    
  actionBar.addTab(tab); 
  
  String label2 = getResources().getString(R.string.listTabLabel);  
  tab = actionBar.newTab();  
  tab.setText(label2);  
  TabListener<ParkListFragment> tl2 = new TabListener<ParkListFragment>(this,  
    label2, ParkListFragment.class);  
  tab.setTabListener(tl2);  
  actionBar.addTab(tab);  
  
  String label3 = getResources().getString(R.string.filtersTabLabel);  
  tab = actionBar.newTab();  
  tab.setText(label3);  
  TabListener<FilterListFragment> tl3 = new TabListener<FilterListFragment>(this,  
    label3, FilterListFragment.class);  
  tab.setTabListener(tl3);  
  actionBar.addTab(tab);
  
  String label4 = getResources().getString(R.string.aboutTabLabel);  
  tab = actionBar.newTab();  
  tab.setText(label4);  
  TabListener<AboutFragment> tl4 = new TabListener<AboutFragment>(this,  
    label4, AboutFragment.class);  
  tab.setTabListener(tl4);  
  actionBar.addTab(tab);
  
  // Restore the current activated tab index
  if (savedInstanceState != null) 
  {         
   actionBar.setSelectedNavigationItem(savedInstanceState.getInt("tab_index", 0));     
  }   
 }  

 private class TabListener<T extends Fragment> implements ActionBar.TabListener {  
  
  private Fragment mFragment;  
  private final SherlockFragmentActivity mActivity;  
  private final String mTag;  
  private final Class<T> mClass;  

  /**  
   * Constructor used each time a new tab is created.  
   *  
   * @param activity  
   *            The host Activity, used to instantiate the fragment  
   * @param tag  
   *            The identifier tag for the fragment  
   * @param clz  
   *            The fragment's Class, used to instantiate the fragment  
   */ 

  public TabListener(SherlockFragmentActivity activity, String tag, Class<T> clz) {  
   
   mActivity = activity;  
   mTag = tag;  
   mClass = clz;  
  }  

  public void onTabSelected(Tab tab, FragmentTransaction ft) {  
   
   mFragment = mActivity.getSupportFragmentManager().findFragmentByTag(mTag); 
   // Check if the fragment is already initialized  
   if (mFragment == null) {  
    // If not, instantiate and add it to the activity  
    mFragment = Fragment.instantiate(mActivity, mClass.getName());  
    ft.add(android.R.id.content, mFragment, mTag);  
   } else {  
    // If it exists, simply attach it in order to show it  
    ft.attach(mFragment);  
   }  
  }  

  public void onTabUnselected(Tab tab, FragmentTransaction ft) {  

   if (mFragment != null) {  
    // Detach the fragment, because another one is being attached  
    ft.detach(mFragment);  
   }  
  }  

  public void onTabReselected(Tab tab, FragmentTransaction ft) {  

   // User selected the already selected tab. Usually do nothing.  
  }  
 } 
 
 @Override 
 protected void onSaveInstanceState(Bundle outState) 
 {     
  super.onSaveInstanceState(outState);
  // Save the current activated tab index
  outState.putInt("tab_index", getSupportActionBar().getSelectedNavigationIndex());   
 } 
}


import com.esri.android.map.MapView;
import com.esri.android.map.ags.ArcGISTiledMapServiceLayer;
import android.os.Bundle;  
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;  
import android.view.View;  
import android.view.ViewGroup;  
import android.widget.LinearLayout;  

public class MapFragment extends Fragment {  
 
 MapView map;
 
 @Override 
 public View onCreateView(LayoutInflater inflater, ViewGroup container,  
  Bundle savedInstanceState) {  
  
  super.onCreate(savedInstanceState);
  
  View layout = inflater.inflate(R.layout.map_test, container, false);
      
  // Retrieve the map and initial extent from XML layout
  map = (MapView) layout.findViewById(R.id.map_view);
 
  // Add dynamic layer to MapView
  map.addLayer(new ArcGISTiledMapServiceLayer(
   "http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"));
  
  return (LinearLayout) layout;  
 }  
}


[HTML]<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"> 
 
<!-- MapView layout and initial extent -->
<com.esri.android.map.MapView xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/map_view"
  initExtent="490969 5452639 508730 5473334" 
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
</com.esri.android.map.MapView>

</LinearLayout> [/HTML]
0 Kudos
11 Replies
AmelieBernier
Emerging Contributor
Good question, I'm not certain how this problem relates to ActionBarSherlock, or what changes to make to onConfigurationChanged.


So it seems that using android:configChanges="orientation" with ActionBarSherlock is not allowing the fake decor view that ActionBarSherlock installs to be re-initialized on rotation (http://stackoverflow.com/questions/10055264/actionbarsherlock-tabs-unresponsive-in-landscape-orienta...). That explains the unresponsive action bar!

The MapView have a very strange behavior. For example, removing a Fragment which contains a MapView using FragmentTransaction will cause the app to crash with the "call to OpenGL ES API with no current context (logged once per thread)" error. The same error also happens when trying to remove a MapView from its parent (see this post : http://forums.arcgis.com/threads/57684-activity-gets-killed-when-the-mapview-is-disposed).

It is too bad that we have to use android:configChanges="orientation" to handle the MapView. This is not a recommended practice. I wonder why the MapView behaves this way? I have other types of View in my app (TextView, LiostView) and they don't cause the same problem.
0 Kudos
GwenRoyakkers1
Deactivated User

The MapView have a very strange behavior. For example, removing a Fragment which contains a MapView using FragmentTransaction will cause the app to crash with the "call to OpenGL ES API with no current context (logged once per thread)" error. The same error also happens when trying to remove a MapView from its parent (see this post : http://forums.arcgis.com/threads/57684-activity-gets-killed-when-the-mapview-is-disposed).

It is too bad that we have to use android:configChanges="orientation" to handle the MapView. This is not a recommended practice. I wonder why the MapView behaves this way? I have other types of View in my app (TextView, LiostView) and they don't cause the same problem.


I'm still having the same problem.
I've contacted support about this issue.
They are working on it, but it seems to be a complicated problem.

I was also using the mapview in a fragment.
I made the remove view sample to show where the problem arises.

(In the previous api release there was a bug when the back button was pressed.
Graphics layers wouldn't show up when the activity was shown again.
I solved this by ending the process in code when the back button was pressed in the map activity.
This problem was solved in the 1.1.1 release, but somehow it now looks like the whole process is killed when the mapview gets garbage collected.)

Unfortunately I couldn't find a workaround for this behavior.
0 Kudos