1

我正在开发一个需要使用 Google Maps API 的应用程序。我已经处理这个问题两天了。我使用的是 API 的第 2 版,所以我使用的是地图片段。因此,当我尝试从地图片段中获取谷歌地图并将其分配给我的GoogleMap googleMap变量时,它会引发空指针异常。我猜它很难找到存储 GoogleMap 对象的片段。我几乎尝试了所有方法。我试图将片段放在我的主要活动的 xml 文件中,使用支持地图片段,并以编程方式将片段添加到我的 xml 文件中。这些解决方案出现了其他问题,但 NPE 在所有问题中都是一致的。我觉得我现在已经很接近了,但我只需要一点帮助就可以让它发挥作用。

这是我的 GoogleMaps 活动代码:

package com.parse.starter;

import android.app.*;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.*;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.*;
import com.google.android.gms.maps.SupportMapFragment;
import com.parse.*;
import com.parse.starter.R;

import java.util.List;

public class OutbreakMap extends FragmentActivity implements LocationListener {
    double lat=50;
    double longi=50;
    private LocationManager locationManager;
    private String provider;
    private GoogleMap googleMap;
    Fragment fragment;


    /** Called when the activity is first created. */

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(isGooglePlayOn())    {
            setContentView(R.layout.map_layout);
        }
        //Add the map fragment
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragment = new com.parse.starter.MapFragment();
        fragmentTransaction.add(R.id.myfragment, fragment);
        fragmentTransaction.commit();

        // Get the location manager
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
        boolean enabled = service.isProviderEnabled(LocationManager.GPS_PROVIDER);

         // Check if enabled and if not send user to the GSP settings
         // Better solution would be to display a dialog and suggesting to
        // go to the settings
        if (!enabled) {
            AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);

            // set title
            alertDialogBuilder.setTitle("Turn On Your GPS");

            // set dialog message
            alertDialogBuilder
                    .setMessage("Please turn on your GPS to track sickness in your area!")
                    .setCancelable(false)
                    .setPositiveButton("Yes",new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog,int id) {
                            // if this button is clicked, close
                            // current activity
                            OutbreakMap.this.finish();
                            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                            startActivity(intent);
                        }
                    })
                    .setNegativeButton("No",new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog,int id) {
                            // if this button is clicked, just close
                            // the dialog box and do nothing
                            dialog.cancel();
                        }
                    });

            // create alert dialog
            AlertDialog alertDialog = alertDialogBuilder.create();

            // show it
            alertDialog.show();

        }
        // Define the criteria how to select the locatioin provider -> use
        // default
        Criteria criteria = new Criteria();
        provider = locationManager.getBestProvider(criteria, false);
        Location location = locationManager.getLastKnownLocation(provider);

        // Initialize the location fields
        if (location != null) {
            System.out.println("Provider " + provider + " has been selected.");
            onLocationChanged(location);
        } else {
            Toast.makeText(getApplicationContext(),"Location not found",Toast.LENGTH_SHORT).show();
        }

        setUpMapIfNeeded();
        googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
        if(location != null)  {
            lat=location.getLatitude();
            longi=location.getLongitude();
        }

        CameraPosition cameraPosition = new CameraPosition.Builder()
                    .target(new LatLng(lat,longi))      // Sets the center of the map to lat,longi (which is 50,50 if the current location isnt found)
                    .zoom(17)                   // Sets the zoom
                    .build();                   // Creates a CameraPosition from the builder
        googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));

        UiSettings uiSettings=googleMap.getUiSettings();
        uiSettings.setAllGesturesEnabled(false);
        // Initialize the location fields
        if (location != null) {
            System.out.println("Provider " + provider + " has been selected.");
            onLocationChanged(location);
        } else {
        Toast.makeText(getApplicationContext(),"Couldn't Find Location",Toast.LENGTH_SHORT).show();
        }



        ParseGeoPoint userLoc= new ParseGeoPoint(lat,longi);
        ParseQuery query= new ParseQuery("Outbreak");
        query.whereWithinMiles("location",userLoc,1);
        query.findInBackground(new FindCallback() {
            public void done(List<ParseObject> objects, ParseException e) {
                if (e == null) {
                GetOutbreaks.getOutBreaksNearMe(googleMap,lat,longi,objects);
                Toast.makeText(getApplicationContext(),"Recieved Outbreak Data",Toast.LENGTH_SHORT).show();
                } else {
                    e.printStackTrace();
                    Toast.makeText(getApplicationContext(),"Could Not Download Data",Toast.LENGTH_SHORT).show();
                }
            }

        });


//        moveToPrescription();
//        moveToPrescription();
    }


    /* Request updates at startup */
    @Override
    protected void onResume() {
        super.onResume();
        locationManager.requestLocationUpdates(provider, 400, 1, this);
    }

    /* Remove the locationlistener updates when Activity is paused */
    @Override
    protected void onPause() {
        super.onPause();
        locationManager.removeUpdates(this);
    }

    @Override
    public void onLocationChanged(Location location) {
        int lat = (int) (location.getLatitude());
        int lng = (int) (location.getLongitude());
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onProviderEnabled(String provider) {
        Toast.makeText(this, "Enabled new provider " + provider,
                Toast.LENGTH_SHORT).show();

    }

    @Override
    public void onProviderDisabled(String provider) {
        Toast.makeText(this, "Disabled provider " + provider,
                Toast.LENGTH_SHORT).show();
    }

    public void moveToPrescription(){
        Intent intent = new Intent(this,Prescription.class);
        startActivity(intent);
    }

    public void setUpMapIfNeeded() {
        if(googleMap==null) {
           googleMap= ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();

        }
        else {

        }
    }

    public boolean isGooglePlayOn() {
        int status=GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
        if(status== ConnectionResult.SUCCESS)   {
            return true;
        }
        ((Dialog) GooglePlayServicesUtil.getErrorDialog(status,this,10)).show();
        Toast.makeText(this,"Google Play Services cannot be found", Toast.LENGTH_SHORT).show();
        return false;
    }

}

这是我的活动的 xml 文件(内部线性布局是地图片段的持有者):

    <?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <FrameLayout
            android:id="@+id/mapContainer"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent">
        <LinearLayout
                android:id="@+id/myfragment"
                android:layout_width="match_parent"
                android:layout_weight="4"
                android:layout_height="match_parent" />
    </FrameLayout>
</LinearLayout>

这是地图片段的 xml 文件:

<?xml version="1.0" encoding="utf-8"?>

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
          android:tag="map_fragment"
          android:id="@+id/map"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          class="com.google.android.gms.maps.MapFragment"/>

最后是我的 Android 清单:

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

    <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="15"/>
    <permission
            android:name="com.parse.starter.permission.MAPS_RECEIVE"
            android:protectionLevel="signature"/>
    <uses-permission android:name="com.parse.starter.permission.MAPS_RECEIVE"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.INTERNET" />
    <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"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>

    <application
        android:name="ParseApplication"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".ParseStarterProjectActivity"

            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".Register"/>
        <activity android:name=".Login"/>
        <activity android:name=".Home"/>
        <activity android:name=".OutbreakMap"/>
        <activity android:name=".Prescription"/>
        <activity android:name=".MyPrescriptions"/>
        <receiver android:name=".AlarmManagerBroadcastReceiver"></receiver>

        <uses-library android:name="com.google.android.maps"/>
        <meta-data
                android:name="com.google.android.maps.v2.API_KEY"
                android:value="MY API KEY IS HERE"/>
    </application>
    <uses-feature android:glEsVersion="0x00020000" android:required="true"/>

</manifest>

抱歉,我没有我的 LogCat 对话框,因为它被删除了,而且我正在测试的手机属于一个不得不离开的朋友。但它基本上说在它说setUpMapIfNeeded();and的那一行有一个 NPE googleMap= ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();。此外,值得注意的是,在 AndroidManifest.xml 文件中,它在最底部显示“无法解析符号 '0x00020000'” <uses-feature android:glEsVersion="0x00020000" android:required="true"/>。但这并不能阻止应用程序编译和安装。感谢所有的帮助,非常感谢。

4

2 回答 2

1

有几件事搞砸了:

  1. 使用 FragmentActivity 时使用 getSupportFragmentManager
  2. if you want to find fragment by id, then it must exists in layout file
  3. you want to add fragment in layout or in code (fragment = new com.parse.starter.MapFragment();) - not both
  4. what is com.parse.starter.MapFragment anyway?

Edit: and there are things in Manifest too...

There is probably something more, but I would suggest starting from a simple project like maps samples in google play services lib.

Edit 2: wrong things in Manifest:

  1. <uses-library android:name="com.google.android.maps"/> is unnecessary
  2. <uses-sdk android:minSdkVersion="4" should be 8 - probably the reason for Cannot resolve symbol '0x00020000'

You can't nest fragment inside fragment with xml. You can only instantiate nested fragment with code and use getChildFragmentManager.

I still don't see your MapFragment code, but if you really need this additional fragment, think of encapsulation: if Google's MapFragment is inside your MapFragment (would be good to change the name), then your MapFragment should be doing any interaction with nested fragment, not Activity.

于 2013-04-07T22:43:42.250 回答
-1

Use getSupportFragmentManager when working with FragmentActivity

if you want to find fragment by id, then it must exists in layout file you want to add fragment in layout or in code (fragment = new com.parse.starter.MapFragment();)

Note: Must not use both

what is com.parse.starter.MapFragment anyway?

于 2014-04-22T06:48:40.920 回答