2

My code is throwing a NullPointerException on this line in my code:

map=((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap()

I can see that it is throwing the exception in LogCat. I've tried to fix this many times, and I've read all the similar problems on this forum. I've tried some of the solutions, but in vain. When I comment out that line, I get the Google map to display, but when I try to get the fragment in my code, I still get the same exception.

Here is my code:

package cs.exmpl;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;

import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;

public class MainActivity extends ActionBarActivity {
    private GoogleMap map;
    private final LatLng loc=new LatLng(566544, 556554);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

            map=((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();

        //SupportMapFragment mapFrag = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
       // map = mapFrag.getMap();



            map.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
        CameraUpdate up=CameraUpdateFactory.newLatLngZoom(loc, 14);
        map.animateCamera(up);






        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.container, new PlaceholderFragment()).commit();
        }

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    /**
     * A placeholder fragment containing a simple view.
     */
    public static class PlaceholderFragment extends Fragment {

        public PlaceholderFragment() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_main, container,
                    false);
            return rootView;
        }
    }

}

Here is my 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="cs.exmpl.MainActivity$PlaceholderFragment" >

    <TextView
        android:id="@+id/header"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

    <fragment 
          android:id="@+id/map"
          android:name="com.google.android.gms.maps.MapFragment"
          android:layout_below="@+id/header"
          android:layout_width="match_parent"
          android:layout_height="match_parent"/>

</RelativeLayout>
Carl Anderson
  • 3,446
  • 1
  • 25
  • 45
  • 1
    Move `map=((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();` to onStart. The view may not be completely drawn yet so it may return null. – zgc7009 May 20 '14 at 16:10
  • Can you be more explicit please. i dont get your point thank you –  May 20 '14 at 16:14
  • setContentView says you want to inflate your layout that contains your map view, but it doesn't do it instantly. onStart is called once your view is done being draw (and thus your fragment is ready to be fetched). – zgc7009 May 20 '14 at 16:18
  • @user3448582 what is min sdk is it below 11 since you extend `ActionBarActivity` in which case you will need to use `SupportMapFragment` – Raghunandan May 20 '14 at 16:29
  • can you give th instruction that can solve my problem please –  May 20 '14 at 16:31
  • @user3448582 sure but what is that you want. Want to just display map. What all api levels do you want to target. You want map inside a fragment? Is your min sdk below 11? – Raghunandan May 20 '14 at 16:32
  • yeas it 11 my aim now is to specify the place exactly i get the map and but when i add the instruction map=(...) getFra... i get the exception. thank you –  May 20 '14 at 16:37
  • @user3448582 there is no point in having min api level 11 as not many devices run on that. You can make it 13. Extend Activity and nest a map in a fragment or use MapFragment in activity layout and then display map. – Raghunandan May 20 '14 at 16:41
  • please i have the map i get it to understand me more i follow this tutorial : https://www.youtube.com/watch?v=awX5T-EwLPc –  May 20 '14 at 16:43

2 Answers2

2

getMap() could return null

Quoting docs

A GoogleMap can only be acquired using getMap() when the underlying maps system is loaded and the underlying view in the fragment exists. This class automatically initializes the maps system and the view; however you cannot be guaranteed when it will be ready because this depends on the availability of the Google Play services APK. If a GoogleMap is not available, getMap() will return null.

Check the availability of google play services before initializing GoogleMap object.

Check the topic Check for Google Play Services

http://developer.android.com/training/location/retrieve-current.html

Edit:

tools:context="cs.exmpl.MainActivity$PlaceholderFragment"

It also looks like the MapFragment is in fragment layout while you initialize it in Activity. Use a MapView follow

Android - android.view.InflateException: Binary XML file line #8: Error inflating class fragment

Or extend MapFragment instead of Fragment.

Edit 3:

Example:

activity_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="cs.exmpl.MainActivity"
    tools:ignore="MergeRootFrame" />

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="cs.exmpl.MainActivity$PlaceholderFragment" >

    <TextView
        android:id="@+id/header"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

   <com.google.android.gms.maps.MapView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/map"
    />


</RelativeLayout>

MainActivity.java

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();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    /**
     * A placeholder fragment containing a simple view.
     */
    public static class PlaceholderFragment extends Fragment {
        MapView mapView;
        GoogleMap map;
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_main, container, false);
        // Gets the MapView from the XML layout and creates it

        MapsInitializer.initialize(getActivity());


        switch (GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity()) )
        {
        case ConnectionResult.SUCCESS:
          Toast.makeText(getActivity(), "SUCCESS", Toast.LENGTH_SHORT).show();
          mapView = (MapView) v.findViewById(R.id.map);
          mapView.onCreate(savedInstanceState);
          // Gets to GoogleMap from the MapView and does initialization stuff
          if(mapView!=null)
          {
          map = mapView.getMap();
          map.getUiSettings().setMyLocationButtonEnabled(false);
          map.setMyLocationEnabled(true);
          CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(43.1, -87.9), 10);
          map.animateCamera(cameraUpdate);
          }
          break;
        case ConnectionResult.SERVICE_MISSING: 
          Toast.makeText(getActivity(), "SERVICE MISSING", Toast.LENGTH_SHORT).show();
          break;
        case ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED: 
          Toast.makeText(getActivity(), "UPDATE REQUIRED", Toast.LENGTH_SHORT).show();
          break;
        default: Toast.makeText(getActivity(), GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity()), Toast.LENGTH_SHORT).show();
        }




        // Updates the location and zoom of the MapView

        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();
        }
        }

}

Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cs.exmpl"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />
    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true"/> 

     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
     <!-- The following two permissions are not required to use
     Google Maps Android API v2, but are recommended. -->
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="cs.exmpl.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
               <meta-data
    android:name="com.google.android.maps.v2.API_KEY"
    android:value="YOUR API KEY FROM GOOGLE API CONSOLE"/>
        <meta-data android:name="com.google.android.gms.version"
          android:value="@integer/google_play_services_version" />
    </application>

</manifest>

Snap on device

enter image description here

Community
  • 1
  • 1
Raghunandan
  • 132,755
  • 26
  • 225
  • 256
  • @user3448582 why do i want to see that tutorial. Follow the docs instead. – Raghunandan May 20 '14 at 16:50
  • @user3448582 posted a complete example. Rest it upto you to modify accordingly. Note to test on emulator you require google platform 4.4.2 and above. – Raghunandan May 20 '14 at 17:13
  • ok Raghunandan i will try with it. tell me for the activity_main.xml it still the same whithout changes ? –  May 20 '14 at 17:20
  • @user3448582 posted everything. All you need to reference google play services. generate map api key from google api console. copy it in manifest. Rest all just copy paste from here. I don't think you require help for that also. if you need help for that also google search or search on stackoverflow i myself have answered a few. – Raghunandan May 20 '14 at 17:23
  • @user3448582 i posted both pls have a look at the post again. Did you even read the post full??. i posted the whole project code coz i know your will end up asking again. There is nothing more to do except copy pasting from here – Raghunandan May 20 '14 at 17:39
  • Raghunandan thank you very much for the help. I beg your pardon it works good –  May 20 '14 at 17:54
  • please Raghunandan when i test on emulator i get white card without google map can you help me please –  May 20 '14 at 18:11
  • @user3448582 key is not right. you are supposed to generate map api key from google api console. Now i can't do that for you. You need to follow the docs for that. If you ahve the right api key it will work without any further problem – Raghunandan May 20 '14 at 18:12
  • the key is correct i dont think so that it the problem. is there another ressource ? i generate the api key correctly –  May 20 '14 at 18:14
  • @user3448582 yes it is the problem regenerate the key and it should work. If you don't think that is the problem i can't help you any further. I did all i can from my side. Posted a working code full with snap shot. What i can do now is give me your teamviewer id i will access your desky and do your work. – Raghunandan May 20 '14 at 18:16
  • So kind of you Raghunandan. beg pardon to You –  May 20 '14 at 18:21
0

This is because findFragmentById searches in the activity_main layout, while the Map is located in the fragment's layout fragment_main.

Move that piece of code in the onCreateView() method of the fragment:

//...
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
map=((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
//...

Notice that now you access it through rootView view:

otherwise you would get again NullPointerException.

EDIT

So change your onCreateView() as follows

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_main, container,
                false);
        map=((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
        return rootView;
    }
Lal
  • 14,726
  • 4
  • 45
  • 70
  • Can you please tell what to do im new to android programming thank you –  May 20 '14 at 16:13
  • See the edit...you just do that and remove that from `onCreate()` – Lal May 20 '14 at 16:14
  • The reason he is getting a `NPE` is due to what zgc7009 says. The `MapFragment` is not inflated until after `onCreate()` because `onCreateView()` gets called after `onCreate()`. – Emmanuel May 20 '14 at 16:21
  • do you mean i delete what is inside of oncreateView ? –  May 20 '14 at 16:22
  • I know you want to gain reputation fast, but do not do it at expense of clarity and actually providing good quality answers. The important thing here is to explain why he is getting the NPE. For example, he doesn't even use `findViewById()` anywhere in his code, he does try to get a reference of the `Fragment` correctly, but not at the right time. – Emmanuel May 20 '14 at 16:25
  • Sorry..that was a mistake..actually i meant `findFragmentById`..Thanks for pointing out that... @Emmanuel – Lal May 20 '14 at 16:30
  • so i have to delete map=((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap(); in onCreate() ?? –  May 20 '14 at 16:41
  • i get the error cant cast fragment to MapFragment and cant make static reference –  May 20 '14 at 16:47
  • you please do one thing...copy the whole contents of fragment_main.xml to activity_main.xml..and undo the changes done in MainActivity.java..This is the easiest solution.. – Lal May 20 '14 at 16:50
  • i undo the changes done in MainActivity.java, i replace activity_main.xml code by the code of fragment but the same exception exist –  May 20 '14 at 16:56
  • Use `SupportMapFragment mapFrag = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map); map = mapFrag.getMap();` instead of `map=((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();` – Lal May 20 '14 at 17:01
  • also use `` in your xml – Lal May 20 '14 at 17:02
  • @user3448582 give me 2 minutes i will post an example – Raghunandan May 20 '14 at 17:08
  • Lal i have the same problem always Exception –  May 20 '14 at 17:10