user3448582
user3448582

Reputation:

NullPointerException using GoogleMaps in Android

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>

Upvotes: 2

Views: 1936

Answers (2)

Raghunandan
Raghunandan

Reputation: 133560

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

Upvotes: 2

Lal
Lal

Reputation: 14810

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

Upvotes: 0

Related Questions