Google的Android位置更新示例中的onConnected()出错

时间:2013-12-18 06:27:17

标签: android location google-play-services

无法直接复制Google的LocationUpdates培训示例。 NullPointerException如下所示。

代码与Google的代码相同:http://developer.android.com/training/location/retrieve-current.html

12-18 00:23:41.776  21601-21601/com.neil.practice E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.NullPointerException
        at com.neil.practice.google.geo.MainActivity.onConnected(MainActivity.java:366)
        at com.google.android.gms.internal.p.k(Unknown Source)
        at com.google.android.gms.internal.p$f.a(Unknown Source)
        at com.google.android.gms.internal.p$f.a(Unknown Source)
        at com.google.android.gms.internal.p$b.p(Unknown Source)
        at com.google.android.gms.internal.p$a.handleMessage(Unknown Source)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:4950)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1004)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:771)
        at dalvik.system.NativeStart.main(Native Method)

更新1 :轻松发布MainActivity.java代码

package com.example.android.location;


import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;

import android.content.IntentSender;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import java.io.IOException;
import java.util.List;
import java.util.Locale;

/**
* This the app's main Activity. It provides buttons for requesting the various features of the
* app, displays the current location, the current address, and the status of the location client
* and updating services.
*
* {@link #getLocation} gets the current location using the Location Services getLastLocation()
* function. {@link #getAddress} calls geocoding to get a street address for the current location.
* {@link #startUpdates} sends a request to Location Services to send periodic location updates to
* the Activity.
* {@link #stopUpdates} cancels previous periodic update requests.
*
* The update interval is hard-coded to be 5 seconds.
*/
public class MainActivity extends FragmentActivity implements
    LocationListener,
    GooglePlayServicesClient.ConnectionCallbacks,
    GooglePlayServicesClient.OnConnectionFailedListener {

// A request to connect to Location Services
private LocationRequest mLocationRequest;

// Stores the current instantiation of the location client in this object
private LocationClient mLocationClient;

// Handles to UI widgets
private TextView mLatLng;
private TextView mAddress;
private ProgressBar mActivityIndicator;
private TextView mConnectionState;
private TextView mConnectionStatus;

// Handle to SharedPreferences for this app
SharedPreferences mPrefs;

// Handle to a SharedPreferences editor
SharedPreferences.Editor mEditor;

/*
 * Note if updates have been turned on. Starts out as "false"; is set to "true" in the
 * method handleRequestSuccess of LocationUpdateReceiver.
 *
 */
boolean mUpdatesRequested = false;

/*
 * Initialize the Activity
 */
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Get handles to the UI view objects
    mLatLng = (TextView) findViewById(R.id.lat_lng);
    mAddress = (TextView) findViewById(R.id.address);
    mActivityIndicator = (ProgressBar) findViewById(R.id.address_progress);
    mConnectionState = (TextView) findViewById(R.id.text_connection_state);
    mConnectionStatus = (TextView) findViewById(R.id.text_connection_status);

    // Create a new global location parameters object
    mLocationRequest = LocationRequest.create();

    /*
     * Set the update interval
     */
    mLocationRequest.setInterval(LocationUtils.UPDATE_INTERVAL_IN_MILLISECONDS);

    // Use high accuracy
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

    // Set the interval ceiling to one minute
    mLocationRequest.setFastestInterval(LocationUtils.FAST_INTERVAL_CEILING_IN_MILLISECONDS);

    // Note that location updates are off until the user turns them on
    mUpdatesRequested = false;

    // Open Shared Preferences
    mPrefs = getSharedPreferences(LocationUtils.SHARED_PREFERENCES, Context.MODE_PRIVATE);

    // Get an editor
    mEditor = mPrefs.edit();

    /*
     * Create a new location client, using the enclosing class to
     * handle callbacks.
     */
    mLocationClient = new LocationClient(this, this, this);

}

/*
 * Called when the Activity is no longer visible at all.
 * Stop updates and disconnect.
 */
@Override
public void onStop() {

    // If the client is connected
    if (mLocationClient.isConnected()) {
        stopPeriodicUpdates();
    }

    // After disconnect() is called, the client is considered "dead".
    mLocationClient.disconnect();

    super.onStop();
}
/*
 * Called when the Activity is going into the background.
 * Parts of the UI may be visible, but the Activity is inactive.
 */
@Override
public void onPause() {

    // Save the current setting for updates
    mEditor.putBoolean(LocationUtils.KEY_UPDATES_REQUESTED, mUpdatesRequested);
    mEditor.commit();

    super.onPause();
}

/*
 * Called when the Activity is restarted, even before it becomes visible.
 */
@Override
public void onStart() {

    super.onStart();

    /*
     * Connect the client. Don't re-start any requests here;
     * instead, wait for onResume()
     */
    mLocationClient.connect();

}
/*
 * Called when the system detects that this Activity is now visible.
 */
@Override
public void onResume() {
    super.onResume();

    // If the app already has a setting for getting location updates, get it
    if (mPrefs.contains(LocationUtils.KEY_UPDATES_REQUESTED)) {
        mUpdatesRequested = mPrefs.getBoolean(LocationUtils.KEY_UPDATES_REQUESTED, false);

    // Otherwise, turn off location updates until requested
    } else {
        mEditor.putBoolean(LocationUtils.KEY_UPDATES_REQUESTED, false);
        mEditor.commit();
    }

}

/*
 * Handle results returned to this Activity by other Activities started with
 * startActivityForResult(). In particular, the method onConnectionFailed() in
 * LocationUpdateRemover and LocationUpdateRequester may call startResolutionForResult() to
 * start an Activity that handles Google Play services problems. The result of this
 * call returns here, to onActivityResult.
 */
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {

    // Choose what to do based on the request code
    switch (requestCode) {

        // If the request code matches the code sent in onConnectionFailed
        case LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST :

            switch (resultCode) {
                // If Google Play services resolved the problem
                case Activity.RESULT_OK:

                    // Log the result
                    Log.d(LocationUtils.APPTAG, getString(R.string.resolved));

                    // Display the result
                    mConnectionState.setText(R.string.connected);
                    mConnectionStatus.setText(R.string.resolved);
                break;

                // If any other result was returned by Google Play services
                default:
                    // Log the result
                    Log.d(LocationUtils.APPTAG, getString(R.string.no_resolution));

                    // Display the result
                    mConnectionState.setText(R.string.disconnected);
                    mConnectionStatus.setText(R.string.no_resolution);

                break;
            }

        // If any other request code was received
        default:
           // Report that this Activity received an unknown requestCode
           Log.d(LocationUtils.APPTAG,
                   getString(R.string.unknown_activity_request_code, requestCode));

           break;
    }
}

/**
 * Verify that Google Play services is available before making a request.
 *
 * @return true if Google Play services is available, otherwise false
 */
private boolean servicesConnected() {

    // Check that Google Play services is available
    int resultCode =
            GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);

    // If Google Play services is available
    if (ConnectionResult.SUCCESS == resultCode) {
        // In debug mode, log the status
        Log.d(LocationUtils.APPTAG, getString(R.string.play_services_available));

        // Continue
        return true;
    // Google Play services was not available for some reason
    } else {
        // Display an error dialog
        Dialog dialog = GooglePlayServicesUtil.getErrorDialog(resultCode, this, 0);
        if (dialog != null) {
            ErrorDialogFragment errorFragment = new ErrorDialogFragment();
            errorFragment.setDialog(dialog);
            errorFragment.show(getSupportFragmentManager(), LocationUtils.APPTAG);
        }
        return false;
    }
}

/**
 * Invoked by the "Get Location" button.
 *
 * Calls getLastLocation() to get the current location
 *
 * @param v The view object associated with this method, in this case a Button.
 */
public void getLocation(View v) {

    // If Google Play Services is available
    if (servicesConnected()) {

        // Get the current location
        Location currentLocation = mLocationClient.getLastLocation();

        // Display the current location in the UI
        mLatLng.setText(LocationUtils.getLatLng(this, currentLocation));
    }
}

/**
 * Invoked by the "Get Address" button.
 * Get the address of the current location, using reverse geocoding. This only works if
 * a geocoding service is available.
 *
 * @param v The view object associated with this method, in this case a Button.
 */
// For Eclipse with ADT, suppress warnings about Geocoder.isPresent()
@SuppressLint("NewApi")
public void getAddress(View v) {

    // In Gingerbread and later, use Geocoder.isPresent() to see if a geocoder is available.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD && !Geocoder.isPresent()) {
        // No geocoder is present. Issue an error message
        Toast.makeText(this, R.string.no_geocoder_available, Toast.LENGTH_LONG).show();
        return;
    }

    if (servicesConnected()) {

        // Get the current location
        Location currentLocation = mLocationClient.getLastLocation();

        // Turn the indefinite activity indicator on
        mActivityIndicator.setVisibility(View.VISIBLE);

        // Start the background task
        (new MainActivity.GetAddressTask(this)).execute(currentLocation);
    }
}

/**
 * Invoked by the "Start Updates" button
 * Sends a request to start location updates
 *
 * @param v The view object associated with this method, in this case a Button.
 */
public void startUpdates(View v) {
    mUpdatesRequested = true;

    if (servicesConnected()) {
        startPeriodicUpdates();
    }
}

/**
 * Invoked by the "Stop Updates" button
 * Sends a request to remove location updates
 * request them.
 *
 * @param v The view object associated with this method, in this case a Button.
 */
public void stopUpdates(View v) {
    mUpdatesRequested = false;

    if (servicesConnected()) {
        stopPeriodicUpdates();
    }
}

/*
 * Called by Location Services when the request to connect the
 * client finishes successfully. At this point, you can
 * request the current location or start periodic updates
 */
@Override
public void onConnected(Bundle bundle) {
    mConnectionStatus.setText(R.string.connected);

    if (mUpdatesRequested) {
        startPeriodicUpdates();
    }
}

/*
 * Called by Location Services if the connection to the
 * location client drops because of an error.
 */
@Override
public void onDisconnected() {
    mConnectionStatus.setText(R.string.disconnected);
}

/*
 * Called by Location Services if the attempt to
 * Location Services fails.
 */
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {

    /*
     * Google Play services can resolve some errors it detects.
     * If the error has a resolution, try sending an Intent to
     * start a Google Play services activity that can resolve
     * error.
     */
    if (connectionResult.hasResolution()) {
        try {

            // Start an Activity that tries to resolve the error
            connectionResult.startResolutionForResult(
                    this,
                    LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST);

            /*
            * Thrown if Google Play services canceled the original
            * PendingIntent
            */

        } catch (IntentSender.SendIntentException e) {

            // Log the error
            e.printStackTrace();
        }
    } else {

        // If no resolution is available, display a dialog to the user with the error.
        showErrorDialog(connectionResult.getErrorCode());
    }
}

/**
 * Report location updates to the UI.
 *
 * @param location The updated location.
 */
@Override
public void onLocationChanged(Location location) {

    // Report to the UI that the location was updated
    mConnectionStatus.setText(R.string.location_updated);

    // In the UI, set the latitude and longitude to the value received
    mLatLng.setText(LocationUtils.getLatLng(this, location));
}

/**
 * In response to a request to start updates, send a request
 * to Location Services
 */
private void startPeriodicUpdates() {

    mLocationClient.requestLocationUpdates(mLocationRequest, this);
    mConnectionState.setText(R.string.location_requested);
}

/**
 * In response to a request to stop updates, send a request to
 * Location Services
 */
private void stopPeriodicUpdates() {
    mLocationClient.removeLocationUpdates(this);
    mConnectionState.setText(R.string.location_updates_stopped);
}

/**
 * An AsyncTask that calls getFromLocation() in the background.
 * The class uses the following generic types:
 * Location - A {@link android.location.Location} object containing the current location,
 *            passed as the input parameter to doInBackground()
 * Void     - indicates that progress units are not used by this subclass
 * String   - An address passed to onPostExecute()
 */
protected class GetAddressTask extends AsyncTask<Location, Void, String> {

    // Store the context passed to the AsyncTask when the system instantiates it.
    Context localContext;

    // Constructor called by the system to instantiate the task
    public GetAddressTask(Context context) {

        // Required by the semantics of AsyncTask
        super();

        // Set a Context for the background task
        localContext = context;
    }

    /**
     * Get a geocoding service instance, pass latitude and longitude to it, format the returned
     * address, and return the address to the UI thread.
     */
    @Override
    protected String doInBackground(Location... params) {
        /*
         * Get a new geocoding service instance, set for localized addresses. This example uses
         * android.location.Geocoder, but other geocoders that conform to address standards
         * can also be used.
         */
        Geocoder geocoder = new Geocoder(localContext, Locale.getDefault());

        // Get the current location from the input parameter list
        Location location = params[0];

        // Create a list to contain the result address
        List <Address> addresses = null;

        // Try to get an address for the current location. Catch IO or network problems.
        try {

            /*
             * Call the synchronous getFromLocation() method with the latitude and
             * longitude of the current location. Return at most 1 address.
             */
            addresses = geocoder.getFromLocation(location.getLatitude(),
                location.getLongitude(), 1
            );

            // Catch network or other I/O problems.
            } catch (IOException exception1) {

                // Log an error and return an error message
                Log.e(LocationUtils.APPTAG, getString(R.string.IO_Exception_getFromLocation));

                // print the stack trace
                exception1.printStackTrace();

                // Return an error message
                return (getString(R.string.IO_Exception_getFromLocation));

            // Catch incorrect latitude or longitude values
            } catch (IllegalArgumentException exception2) {

                // Construct a message containing the invalid arguments
                String errorString = getString(
                        R.string.illegal_argument_exception,
                        location.getLatitude(),
                        location.getLongitude()
                );
                // Log the error and print the stack trace
                Log.e(LocationUtils.APPTAG, errorString);
                exception2.printStackTrace();

                //
                return errorString;
            }
            // If the reverse geocode returned an address
            if (addresses != null && addresses.size() > 0) {

                // Get the first address
                Address address = addresses.get(0);

                // Format the first line of address
                String addressText = getString(R.string.address_output_string,

                        // If there's a street address, add it
                        address.getMaxAddressLineIndex() > 0 ?
                                address.getAddressLine(0) : "",

                        // Locality is usually a city
                        address.getLocality(),

                        // The country of the address
                        address.getCountryName()
                );

                // Return the text
                return addressText;

            // If there aren't any addresses, post a message
            } else {
              return getString(R.string.no_address_found);
            }
    }

    /**
     * A method that's called once doInBackground() completes. Set the text of the
     * UI element that displays the address. This method runs on the UI thread.
     */
    @Override
    protected void onPostExecute(String address) {

        // Turn off the progress bar
        mActivityIndicator.setVisibility(View.GONE);

        // Set the address in the UI
        mAddress.setText(address);
    }
}

/**
 * Show a dialog returned by Google Play services for the
 * connection error code
 *
 * @param errorCode An error code returned from onConnectionFailed
 */
private void showErrorDialog(int errorCode) {

    // Get the error dialog from Google Play services
    Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
        errorCode,
        this,
        LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST);

    // If Google Play services can provide an error dialog
    if (errorDialog != null) {

        // Create a new DialogFragment in which to show the error dialog
        ErrorDialogFragment errorFragment = new ErrorDialogFragment();

        // Set the dialog in the DialogFragment
        errorFragment.setDialog(errorDialog);

        // Show the error dialog in the DialogFragment
        errorFragment.show(getSupportFragmentManager(), LocationUtils.APPTAG);
    }
}

/**
 * Define a DialogFragment to display the error dialog generated in
 * showErrorDialog.
 */
public static class ErrorDialogFragment extends DialogFragment {

    // Global field to contain the error dialog
    private Dialog mDialog;

    /**
     * Default constructor. Sets the dialog field to null
     */
    public ErrorDialogFragment() {
        super();
        mDialog = null;
    }

    /**
     * Set the dialog to display
     *
     * @param dialog An error dialog
     */
    public void setDialog(Dialog dialog) {
        mDialog = dialog;
    }

    /*
     * This method must return a Dialog to the DialogFragment.
     */
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return mDialog;
    }
}
}

0 个答案:

没有答案