27

I am looking at using ActionbarSherlock but have one query that's holding me back.

So my application needs to be fully backwards compatible to API Level 7.

I need to implement the new Google Maps in my application and to do that I need to use the SupportMapFragment class.

** My Question **

Is it possible to use the SupportMapFragment class alongside ActionBarSherlock?

Thanks in advance

EDIT

I have downloaded and had a look at the library. The only changes to the extended Fragments I can see are very simple and the same for all of them.

Do you think I could add support myself?

here is how they are supported.

package com.actionbarsherlock.app;

import android.app.Activity;
import android.support.v4.app.DialogFragment;
import com.actionbarsherlock.internal.view.menu.MenuItemWrapper;
import com.actionbarsherlock.internal.view.menu.MenuWrapper;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;

import static com.actionbarsherlock.app.SherlockFragmentActivity.OnCreateOptionsMenuListener;
import static com.actionbarsherlock.app.SherlockFragmentActivity.OnOptionsItemSelectedListener;
import static com.actionbarsherlock.app.SherlockFragmentActivity.OnPrepareOptionsMenuListener;

public class SherlockDialogFragment extends DialogFragment implements OnCreateOptionsMenuListener, OnPrepareOptionsMenuListener, OnOptionsItemSelectedListener {
    private SherlockFragmentActivity mActivity;

public SherlockFragmentActivity getSherlockActivity() {
    return mActivity;
}

@Override
public void onAttach(Activity activity) {
    if (!(activity instanceof SherlockFragmentActivity)) {
        throw new IllegalStateException(getClass().getSimpleName() + " must be attached to a SherlockFragmentActivity.");
    }
    mActivity = (SherlockFragmentActivity)activity;

    super.onAttach(activity);
}

@Override
public void onDetach() {
    mActivity = null;
    super.onDetach();
}

@Override
public final void onCreateOptionsMenu(android.view.Menu menu, android.view.MenuInflater inflater) {
    onCreateOptionsMenu(new MenuWrapper(menu), mActivity.getSupportMenuInflater());
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    //Nothing to see here.
}

@Override
public final void onPrepareOptionsMenu(android.view.Menu menu) {
    onPrepareOptionsMenu(new MenuWrapper(menu));
}

@Override
public void onPrepareOptionsMenu(Menu menu) {
    //Nothing to see here.
}

@Override
public final boolean onOptionsItemSelected(android.view.MenuItem item) {
    return onOptionsItemSelected(new MenuItemWrapper(item));
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    //Nothing to see here.
    return false;
}

}

StuStirling
  • 14,888
  • 22
  • 88
  • 143

6 Answers6

61

It all works like a charm, mainly thanks to Jake's great work on ActionBarSherlock

Here are the steps I followed:

  1. Create a SherlockMapFragment class in your actiobarsherlock library project. I simply made a copy of SherlockFragment because I also needed support for setHasOptionsMenu(true)
  2. The activity extends SherlockFragmentActivity (as usual)
  3. The fragment extends the newly created SherlockMapFragment
  4. ActionBarSherlock requires the new google-play-services_lib library
  5. Your project requires the ActionBarSherlock library. No need to include the google-play-services again, or to build against Google API.
  6. As mentionned by Graham, you have to drop support for API 7 devices: <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" />

And here's some code for a more detailed explanation:

SherlockMapFragment

package com.actionbarsherlock.app;

import com.actionbarsherlock.internal.view.menu.MenuItemWrapper;
import com.actionbarsherlock.internal.view.menu.MenuWrapper;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import com.google.android.gms.maps.SupportMapFragment;

import android.app.Activity;
import android.support.v4.app.Watson.OnCreateOptionsMenuListener;
import android.support.v4.app.Watson.OnOptionsItemSelectedListener;
import android.support.v4.app.Watson.OnPrepareOptionsMenuListener;

public class SherlockMapFragment extends SupportMapFragment
        implements OnCreateOptionsMenuListener,
        OnPrepareOptionsMenuListener,
        OnOptionsItemSelectedListener {
    private SherlockFragmentActivity mActivity;

    public SherlockFragmentActivity getSherlockActivity() {
        return mActivity;
    }

    @Override
    public void onAttach(Activity activity) {
        if (!(activity instanceof SherlockFragmentActivity)) {
            throw new IllegalStateException(getClass().getSimpleName()
                    + " must be attached to a SherlockFragmentActivity.");
        }
        mActivity = (SherlockFragmentActivity) activity;

        super.onAttach(activity);
    }

    @Override
    public void onDetach() {
        mActivity = null;
        super.onDetach();
    }

    @Override
    public final void onCreateOptionsMenu(android.view.Menu menu, android.view.MenuInflater inflater) {
        onCreateOptionsMenu(new MenuWrapper(menu), mActivity.getSupportMenuInflater());
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        // Nothing to see here.
    }

    @Override
    public final void onPrepareOptionsMenu(android.view.Menu menu) {
        onPrepareOptionsMenu(new MenuWrapper(menu));
    }

    @Override
    public void onPrepareOptionsMenu(Menu menu) {
        // Nothing to see here.
    }

    @Override
    public final boolean onOptionsItemSelected(android.view.MenuItem item) {
        return onOptionsItemSelected(new MenuItemWrapper(item));
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Nothing to see here.
        return false;
    }
}

The activity:

public class MainActivity extends SherlockFragmentActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

The activity XML layout:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <fragment
        android:id="@+id/fragment_map"
        android:name=".ui.fragments.MapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:tag="tag_fragment_map" />

    <fragment
        android:id="@+id/fragment_help"
        android:name=".ui.fragments.HelpFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:tag="tag_fragment_help" />
</FrameLayout>

The map fragment:

public class MapFragment extends SherlockMapFragment {
    private GoogleMap mMap;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View root = super.onCreateView(inflater, container, savedInstanceState);
        mMap = getMap();
        return root;
    }
}
Mudar
  • 1,695
  • 13
  • 16
  • 6
    I did this as well and it works fine. You could also put the SherlockMapFragment in you main project if you don't want to go messing with the ABS library project. – Jason Hanley Dec 05 '12 at 16:19
  • All done and I thank you. Next problem is getting it to work properly. Please see my other questionrelating to retrieving the maps. http://stackoverflow.com/questions/13727992/google-maps-api-v2-failed-to-load-map-could-not-contact-google-servers/13728039#13728039 – StuStirling Dec 05 '12 at 16:49
  • Do you know if this code might have any problem when using an Android Maven Project? I tried the same code and I'm getting the error reported in here: http://stackoverflow.com/questions/14004668/google-maps-android-v2-not-working-with-actionbarsherlock-fragment-activity – Juliano Nunes Silva Oliveira Dec 22 '12 at 17:10
  • I have tryied this... but something strange happens in my project: http://stackoverflow.com/questions/14430716/actionbarsherlock-googlemaps-v2-map-not-shown-without-map-log-errors – cesards Jan 21 '13 at 07:33
  • Thanks a great explanation – Aiden Fry Jan 29 '13 at 13:27
  • can you upload a working example please????? I have to do the same but I have some errors that I don't know. – michele Apr 11 '13 at 15:47
  • Is there any gotchas setting up the project in IntelliJ when I subclass SupportMapFragmant it doesn't allow me to override some of the SupportFragment methods like onOptionsItemSelected(android.view.MenuItem item) – djandreski May 17 '13 at 06:56
  • Just on `android:name=".ui.fragments.HelpFragment"` i needed to put de full path of the package, like: br.com.... and not the relative path of the package. – Guido May 18 '13 at 14:35
  • This same solution works for HoloEverywhere. You need only change SherlockFragmentActivity to (holoeverywhere)Activity and getSherlockActivity to getSupportActivity. You don't need to implement onPrepareOptionsMenu and onOptionsItemSelected. – JPMagalhaes Jun 12 '13 at 07:51
  • I have implemented this. My problem is that the on `onOptionsItemSelected` is getting called twice. Please help me out with this. – Naddy Oct 24 '13 at 11:28
  • @Naddy Your issue is quite vague! However, you should probably return `true` when you do handle an item in `onOptionsItemSelected()` – Mudar Oct 24 '13 at 14:35
  • [Here](http://stackoverflow.com/questions/19564870/android-onoptionsitemselected-method-called-twice) I have asked the same question. Have a look. I tried returning true. But in that case the `menu items` are not getting displayed. – Naddy Oct 24 '13 at 15:22
4

I heard that Jake is not going to do too much more to ABS as Google may be bringing out their own backward compatible ActionBar. I think if I remember correctly it was discussed in one of the Android related Google+ hangouts.

The new maps requires API level 8 onward so before even worrying about the actionbar you will run into problems if you must support API level 7.

My advice would be produce 2 layout files one for level 7 and and one for 8+. In the level 7 use the now old MapView although they are deprecating it, which for me shows how API level 7 is not necessarily worth considering as a target. In the 8+ layout use the new map system.

As for the actionbar, we are porting an app right now and have easily and successfully added a map to a ViewPager, by creating the Fragment programtically (rather than in XML). We have tested it on multiple devices.

We have also had no issues using the new map system as described in Google demos with ABS. We declared the fragment in an XML layout and set this as the content of the activity. The ActionBar displays as normal. The Activity is a SherlockFragmentActivity.

Graham Smith
  • 25,307
  • 10
  • 44
  • 69
3

Basically what i am sure of is that this SupportMapFragment is totally fresh and maybe the maintainer of ActionBarSherlock didn't yet have the time to add it on the ABS Project.

Also it requires API Lvl 8+ so you can just remove your support to the API lvl 7 devices or you will have to wait for Jake to add support for the new SupportMapFragment.

For other API lvls you can find a work around here:http://xrigau.wordpress.com/2012/03/22/howto-actionbarsherlock-mapfragment-listfragment/

Pavlos
  • 2,153
  • 2
  • 18
  • 27
3

I tried implementing SupportMapFragment with ActionBarSherlock.

It is working very fine.

enter image description here

Below is code snippet.

package com.example.newmapview;

import android.os.Bundle;
import android.widget.Toast;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.SubMenu;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;

public class MainActivity extends SherlockFragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        SupportMapFragment fragment = SupportMapFragment.newInstance();
        getSupportFragmentManager().beginTransaction()
                .add(R.id.mapLayout, fragment).commit();

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        SubMenu subMenu = menu.addSubMenu("Type");

        subMenu.add("Normal");
        subMenu.add("SATELLITE");

        subMenu.getItem().setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        if (item.getTitle().toString().equalsIgnoreCase("Normal")) {
            Toast.makeText(this, "Clicked Normal", Toast.LENGTH_LONG).show();
            GoogleMap googleMap = ((SupportMapFragment) getSupportFragmentManager()
                    .findFragmentById(R.id.mapLayout)).getMap();

            if (googleMap != null)
                googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
            else
                Toast.makeText(this, "GoogleMap is null", Toast.LENGTH_LONG)
                        .show();
        } else if (item.getTitle().toString().equalsIgnoreCase("SATELLITE")) {
            Toast.makeText(this, "Clicked SATELLITE", Toast.LENGTH_LONG).show();
            GoogleMap googleMap = ((SupportMapFragment) getSupportFragmentManager()
                    .findFragmentById(R.id.mapLayout)).getMap();

            if (googleMap != null)
                googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
            else
                Toast.makeText(this, "GoogleMap is null", Toast.LENGTH_LONG)
                        .show();
        }

        return true;

    }
}

Hope this will help.

Vipul
  • 31,716
  • 7
  • 69
  • 86
  • 1
    can you please share the xml also. i am trying to implement it inside a Fragment – suresh cheemalamudi Dec 05 '12 at 14:53
  • Thank you for the answer and I'm glad you have it work as it shows me its definitely possible. The problem now is I need to be able to create a subclass of this SupportMapFragment, however I am running into all sorts of class cast exceptions. Any idea? – StuStirling Dec 05 '12 at 15:50
  • in your xml layout, change MapFragment to SupportMapFragment, it should look like this: – Gruzilkin May 29 '13 at 05:26
0

I can't comment everywhere yet, that's why I answer @sureshcheemalamudi If you are trying to implement it on a Fragment, or SherlockFragment, take a look at this: https://stackoverflow.com/a/17803561/1755300

Community
  • 1
  • 1
unmultimedio
  • 1,184
  • 2
  • 12
  • 38
0
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // toggle mapType
    if (mapFragment != null) {
        googleMap = mapFragment.getMap();
    }
    switch (item.getItemId()) {
    case R.id.action_normal:
        googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
        Toast.makeText(getActivity(), "normal", Toast.LENGTH_LONG).show();
        return true;
    case R.id.action_satellite:
        googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
        Toast.makeText(getActivity(), "satellite", Toast.LENGTH_LONG)
                .show();
        return true;
    case R.id.action_terrian:
        googleMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
        Toast.makeText(getActivity(), "terian", Toast.LENGTH_LONG).show();
        return true;
    case R.id.action_hybrid:
        googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
        Toast.makeText(getActivity(), "hybrid", Toast.LENGTH_LONG).show();
        return true;
    default:

        return super.onOptionsItemSelected(item);
    }
}
Rahul
  • 23
  • 6
  • How is this piece of code an answer to the question? Please expand or delete. – laalto Mar 12 '14 at 12:20
  • Just check mapfragment is null or not just once and no need to check map is null every time while changing map type as shown in above code – Rahul Mar 12 '14 at 13:04