I want to query parse to return list of names stored on the Parse Cloud. I am implemented geoLocation and I am using getLatitude and getLongitutude to ParseGeoPoint to get the list of names.
public class TakePhotoActivity extends BaseActivity implements RevealBackgroundView.OnStateChangeListener, LocationListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
CameraHostProvider {
public static final String ARG_REVEAL_START_LOCATION = "reveal_start_location";
private static final Interpolator ACCELERATE_INTERPOLATOR = new AccelerateInterpolator();
private static final Interpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();
private static final int STATE_TAKE_PHOTO = 0;
private static final int STATE_SETUP_PHOTO = 1;
/*
* Define a request code to send to Google Play services This code is returned in
* Activity.onActivityResult
*/
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
/*
* Constants for location update parameters
*/
// Milliseconds per second
private static final int MILLISECONDS_PER_SECOND = 1000;
// The update interval
private static final int UPDATE_INTERVAL_IN_SECONDS = 5;
// A fast interval ceiling
private static final int FAST_CEILING_IN_SECONDS = 1;
// Update interval in milliseconds
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = MILLISECONDS_PER_SECOND
* UPDATE_INTERVAL_IN_SECONDS;
// A fast ceiling of update intervals, used when the app is visible
private static final long FAST_INTERVAL_CEILING_IN_MILLISECONDS = MILLISECONDS_PER_SECOND
* FAST_CEILING_IN_SECONDS;
#Bind(R.id.vRevealBackground)
RevealBackgroundView vRevealBackground;
#Bind(R.id.vPhotoRoot)
View vTakePhotoRoot;
#Bind(R.id.vShutter)
View vShutter;
#Bind(R.id.ivTakenPhoto)
ImageView ivTakenPhoto;
#Bind(R.id.vUpperPanel)
ViewSwitcher vUpperPanel;
#Bind(R.id.vLowerPanel)
ViewSwitcher vLowerPanel;
#Bind(R.id.cameraView)
CameraView cameraView;
#Bind(R.id.rvFilters)
RecyclerView rvFilters;
#Bind(R.id.btnTakePhoto)
Button btnTakePhoto;
private float radius;
private float lastRadius;
private boolean pendingIntro;
private int currentState;
private Location lastLocation;
private Location currentLocation;
// A request to connect to Location Services
private LocationRequest locationRequest;
// Stores the current instantiation of the location client in this object
private GoogleApiClient locationClient;
private File photoPath;
public static void startCameraFromLocation(int[] startingLocation, Activity startingActivity) {
Intent intent = new Intent(startingActivity, TakePhotoActivity.class);
intent.putExtra(ARG_REVEAL_START_LOCATION, startingLocation);
startingActivity.startActivity(intent);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_take_photo);
updateStatusBarColor();
updateState(STATE_TAKE_PHOTO);
setupRevealBackground(savedInstanceState);
setupPhotoFilters();
radius = InstaMaterialApplication.getSearchDistance();
lastRadius = radius;
// Create a new global location parameters object
locationRequest = LocationRequest.create();
// Set the update interval
locationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
// Use high accuracy
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the interval ceiling to one minute
locationRequest.setFastestInterval(FAST_INTERVAL_CEILING_IN_MILLISECONDS);
// Create a new location client, using the enclosing class to handle callbacks.
locationClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
vUpperPanel.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
vUpperPanel.getViewTreeObserver().removeOnPreDrawListener(this);
pendingIntro = true;
vUpperPanel.setTranslationY(-vUpperPanel.getHeight());
vLowerPanel.setTranslationY(vLowerPanel.getHeight());
return true;
}
});
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void updateStatusBarColor() {
if (Utils.isAndroid5()) {
getWindow().setStatusBarColor(0xff111111);
}
}
private void setupRevealBackground(Bundle savedInstanceState) {
vRevealBackground.setFillPaintColor(0xFF16181a);
vRevealBackground.setOnStateChangeListener(this);
if (savedInstanceState == null) {
final int[] startingLocation = getIntent().getIntArrayExtra(ARG_REVEAL_START_LOCATION);
vRevealBackground.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
vRevealBackground.getViewTreeObserver().removeOnPreDrawListener(this);
vRevealBackground.startFromLocation(startingLocation);
return true;
}
});
} else {
vRevealBackground.setToFinishedFrame();
}
}
FiltersQueryAdapter mainAdapter = new FiltersQueryAdapter(this, PhotoFiltersAdapter.class
, new ParseRecyclerQueryAdapter.QueryFactory() {
public ParseQuery create() {
Location myLoc = (currentLocation == null) ? lastLocation : currentLocation;
ParseQuery query = ParseQuery.getQuery("PlaceFilters");
//query.include("user");
query.orderByAscending("GeoArea");
query.whereWithinKilometers("GeoArea", geoPointFromLocation(myLoc), radius);
query.setLimit(6);
return query;
}
});
private void setupPhotoFilters() {
rvFilters.setHasFixedSize(true);
rvFilters.setAdapter(mainAdapter);
rvFilters.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
}
#Override
protected void onResume() {
super.onResume();
cameraView.onResume();
// Get the latest search distance preference
radius = InstaMaterialApplication.getSearchDistance();
// Checks the last saved location to show cached data if it's available
if (lastLocation != null) {
// If the search distance preference has been changed, move
// map to new bounds.
if (lastRadius != radius) {
// Save the current radius
lastRadius = radius;
doListQuery();
}
}
}
#Override
protected void onPause() {
super.onPause();
cameraView.onPause();
}
/*
* Called when the Activity is no longer visible at all. Stop updates and disconnect.
*/
#Override
public void onStop() {
// If the client is connected
if (locationClient.isConnected()) {
stopPeriodicUpdates();
}
// After disconnect() is called, the client is considered "dead".
locationClient.disconnect();
super.onStop();
}
/*
* Called when the Activity is restarted, even before it becomes visible.
*/
#Override
public void onStart() {
super.onStart();
// Connect to the location services client
locationClient.connect();
}
#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 CONNECTION_FAILURE_RESOLUTION_REQUEST:
switch (resultCode) {
// If Google Play services resolved the problem
case Activity.RESULT_OK:
if (InstaMaterialApplication.APPDEBUG) {
// Log the result
Log.d(InstaMaterialApplication.APPTAG, "Connected to Google Play services");
}
break;
// If any other result was returned by Google Play services
default:
if (InstaMaterialApplication.APPDEBUG) {
// Log the result
Log.d(InstaMaterialApplication.APPTAG, "Could not connect to Google Play services");
}
break;
}
// If any other request code was received
default:
if (InstaMaterialApplication.APPDEBUG) {
// Report that this Activity received an unknown requestCode
Log.d(InstaMaterialApplication.APPTAG, "Unknown request code received for the activity");
}
break;
}
}
#OnClick(R.id.btnTakePhoto)
public void onTakePhotoClick() {
btnTakePhoto.setEnabled(false);
cameraView.takePicture(true, true);
animateShutter();
}
#OnClick(R.id.btnAccept)
public void onAcceptClick() {
PublishActivity.openWithPhotoUri(this, Uri.fromFile(photoPath));
}
/*
* 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) {
if (InstaMaterialApplication.APPDEBUG) {
// In debug mode, log the status
Log.d(InstaMaterialApplication.APPTAG, "Google 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(), InstaMaterialApplication.APPTAG);
}
return false;
}
}
/*
* 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
*/
public void onConnected(Bundle bundle) {
if (InstaMaterialApplication.APPDEBUG) {
Log.d("Location Connected", InstaMaterialApplication.APPTAG);
}
currentLocation = getLocation();
startPeriodicUpdates();
}
/*
* Called by Location Services if the connection to the location client drops because of an error.
*/
public void onDisconnected() {
if (InstaMaterialApplication.APPDEBUG) {
Log.d("Location Disconnected", InstaMaterialApplication.APPTAG);
}
}
#Override
public void onConnectionSuspended(int i) {
Log.i(InstaMaterialApplication.APPTAG, "GoogleApiClient connection has been suspend");
}
/*
* Called by Location Services if the attempt to Location Services fails.
*/
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, CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
if (InstaMaterialApplication.APPDEBUG) {
// Thrown if Google Play services canceled the original PendingIntent
Log.d(InstaMaterialApplication.APPTAG, "An error occurred when connecting to location services.", e);
}
}
} else {
// If no resolution is available, display a dialog to the user with the error.
showErrorDialog(connectionResult.getErrorCode());
}
}
/*
* Report location updates to the UI.
*/
public void onLocationChanged(Location location) {
currentLocation = location;
if (lastLocation != null
&& geoPointFromLocation(location)
.distanceInKilometersTo(geoPointFromLocation(lastLocation)) < 0.01) {
// If the location hasn't changed by more than 10 meters, ignore it.
return;
}
lastLocation = location;
// Update map radius indicator
doListQuery();
}
/*
* In response to a request to start updates, send a request to Location Services
*/
private void startPeriodicUpdates() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(
locationClient, locationRequest, this);
}
/*
* In response to a request to stop updates, send a request to Location Services
*/
private void stopPeriodicUpdates() {
locationClient.disconnect();
}
/*
* Get the current location
*/
private Location getLocation() {
// If Google Play Services is available
if (servicesConnected()) {
// Get the current location
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
}
return LocationServices.FusedLocationApi.getLastLocation(locationClient);
} else {
return null;
}
}
/*
* Set up a query to update the list view
*/
private void doListQuery() {
Location myLoc = (currentLocation == null) ? lastLocation : currentLocation;
// If location info is available, load the data
if (myLoc != null) {
// Refreshes the list view with new data based
// usually on updated location data.
// mainAdapter.;
}
}
/*
* Helper method to get the Parse GEO point representation of a location
*/
private ParseGeoPoint geoPointFromLocation(Location loc) {
return new ParseGeoPoint(loc.getLatitude(), loc.getLongitude());
}
/*
* Show a dialog returned by Google Play services for the connection error code
*/
private void showErrorDialog(int errorCode) {
// Get the error dialog from Google Play services
Dialog errorDialog =
GooglePlayServicesUtil.getErrorDialog(errorCode, this,
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(), InstaMaterialApplication.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;
}
}
private void animateShutter() {
vShutter.setVisibility(View.VISIBLE);
vShutter.setAlpha(0.f);
ObjectAnimator alphaInAnim = ObjectAnimator.ofFloat(vShutter, "alpha", 0f, 0.8f);
alphaInAnim.setDuration(100);
alphaInAnim.setStartDelay(100);
alphaInAnim.setInterpolator(ACCELERATE_INTERPOLATOR);
ObjectAnimator alphaOutAnim = ObjectAnimator.ofFloat(vShutter, "alpha", 0.8f, 0f);
alphaOutAnim.setDuration(200);
alphaOutAnim.setInterpolator(DECELERATE_INTERPOLATOR);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(alphaInAnim, alphaOutAnim);
animatorSet.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
vShutter.setVisibility(View.GONE);
}
});
animatorSet.start();
}
#Override
public void onStateChange(int state) {
if (RevealBackgroundView.STATE_FINISHED == state) {
vTakePhotoRoot.setVisibility(View.VISIBLE);
if (pendingIntro) {
startIntroAnimation();
}
} else {
vTakePhotoRoot.setVisibility(View.INVISIBLE);
}
}
private void startIntroAnimation() {
vUpperPanel.animate().translationY(0).setDuration(400).setInterpolator(DECELERATE_INTERPOLATOR);
vLowerPanel.animate().translationY(0).setDuration(400).setInterpolator(DECELERATE_INTERPOLATOR).start();
}
#Override
public CameraHost getCameraHost() {
return new MyCameraHost(this);
}
class MyCameraHost extends SimpleCameraHost {
private Camera.Size previewSize;
public MyCameraHost(Context ctxt) {
super(ctxt);
}
#Override
public boolean useFullBleedPreview() {
return true;
}
#Override
public Camera.Size getPictureSize(PictureTransaction xact, Camera.Parameters parameters) {
return previewSize;
}
#Override
public Camera.Parameters adjustPreviewParameters(Camera.Parameters parameters) {
Camera.Parameters parameters1 = super.adjustPreviewParameters(parameters);
previewSize = parameters1.getPreviewSize();
return parameters1;
}
#Override
public void saveImage(PictureTransaction xact, final Bitmap bitmap) {
runOnUiThread(new Runnable() {
#Override
public void run() {
showTakenPicture(bitmap);
}
});
}
#Override
public void saveImage(PictureTransaction xact, byte[] image) {
super.saveImage(xact, image);
photoPath = getPhotoPath();
}
}
private void showTakenPicture(Bitmap bitmap) {
vUpperPanel.showNext();
vLowerPanel.showNext();
ivTakenPhoto.setImageBitmap(bitmap);
updateState(STATE_SETUP_PHOTO);
}
#Override
public void onBackPressed() {
if (currentState == STATE_SETUP_PHOTO) {
btnTakePhoto.setEnabled(true);
vUpperPanel.showNext();
vLowerPanel.showNext();
updateState(STATE_TAKE_PHOTO);
} else {
super.onBackPressed();
}
}
private void updateState(int state) {
currentState = state;
if (currentState == STATE_TAKE_PHOTO) {
vUpperPanel.setInAnimation(this, R.anim.slide_in_from_right);
vLowerPanel.setInAnimation(this, R.anim.slide_in_from_right);
vUpperPanel.setOutAnimation(this, R.anim.slide_out_to_left);
vLowerPanel.setOutAnimation(this, R.anim.slide_out_to_left);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
ivTakenPhoto.setVisibility(View.GONE);
}
}, 400);
} else if (currentState == STATE_SETUP_PHOTO) {
vUpperPanel.setInAnimation(this, R.anim.slide_in_from_left);
vLowerPanel.setInAnimation(this, R.anim.slide_in_from_left);
vUpperPanel.setOutAnimation(this, R.anim.slide_out_to_right);
vLowerPanel.setOutAnimation(this, R.anim.slide_out_to_right);
ivTakenPhoto.setVisibility(View.VISIBLE);
}
}
}
Here is my Logcat:
02-16 17:32:40.700 22343-22343/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.google.peep, PID: 22343
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.google.peep/com.google.peep.activity.TakePhotoActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2484)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2544)
at android.app.ActivityThread.access$900(ActivityThread.java:150)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1394)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:168)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:687)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference
at com.google.peep.activity.TakePhotoActivity.geoPointFromLocation(TakePhotoActivity.java:501)
at com.google.peep.activity.TakePhotoActivity.access$300(TakePhotoActivity.java:66)
at com.google.peep.activity.TakePhotoActivity$3.create(TakePhotoActivity.java:223)
at com.javon.parserecyclerviewadapter.ParseRecyclerQueryAdapter.loadParseData(ParseRecyclerQueryAdapter.java:96)
at com.javon.parserecyclerviewadapter.ParseRecyclerQueryAdapter.registerAdapterDataObserver(ParseRecyclerQueryAdapter.java:176)
at android.support.v7.widget.RecyclerView.setAdapterInternal(RecyclerView.java:886)
at android.support.v7.widget.RecyclerView.setAdapter(RecyclerView.java:847)
at com.google.peep.activity.TakePhotoActivity.setupPhotoFilters(TakePhotoActivity.java:232)
at com.google.peep.activity.TakePhotoActivity.onCreate(TakePhotoActivity.java:152)
Your getlocation is before the google api client actually connects,pass setup photofilters in onConnected and it will run.Tatasthu!
Related
I am struggling with a problem to display my reverse geocoding results automatically. It works fine when I click button to get location, but I want it to simply display the location automatically when the app is loaded.
My code is in a Java class called geocoding, eventually i want to display this code on a marker on my map, which i have already created.
but this thread is to eliminate the button and display location as son as map loads.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); // uses layout from mainactivity
mResultReceiver = new AddressResultReceiver(new Handler());
mLocationAddressTextView = (TextView) findViewById(R.id.location_address_view);
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
mFetchAddressButton = (Button) findViewById(R.id.fetch_address_button);
// Set defaults, then update using values stored in the Bundle.
mAddressRequested = false;
mAddressOutput = "";
updateValuesFromBundle(savedInstanceState);
updateUIWidgets();
buildGoogleApiClient();
}
public void buttonOnClick(View view) { // this links the maps activity via the XML layout file
startActivity(new Intent(Geocode.this, MapsActivity.class));
}
/**
* Updates fields based on data stored in the bundle.
*/
private void updateValuesFromBundle(Bundle savedInstanceState) {
if (savedInstanceState != null) {
// Check savedInstanceState to see if the address was previously requested.
if (savedInstanceState.keySet().contains(ADDRESS_REQUESTED_KEY)) {
mAddressRequested = savedInstanceState.getBoolean(ADDRESS_REQUESTED_KEY);
}
// Check savedInstanceState to see if the location address string was previously found
// and stored in the Bundle. If it was found, display the address string in the UI.
if (savedInstanceState.keySet().contains(LOCATION_ADDRESS_KEY)) {
mAddressOutput = savedInstanceState.getString(LOCATION_ADDRESS_KEY);
displayAddressOutput();
}
}
}
/**
* Builds a GoogleApiClient. Uses {#code #addApi} to request the LocationServices API.
*/
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
public void fetchAddressButtonHandler(View view) {
// We only start the service to fetch the address if GoogleApiClient is connected.
if (mGoogleApiClient.isConnected() && mLastLocation != null) {
startIntentService();
}
mAddressRequested = true;
updateUIWidgets();
}
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
/**
* Runs when a GoogleApiClient object successfully connects.
*/
#Override
public void onConnected(Bundle connectionHint) {
// Gets the best and most recent location currently available, which may be null
// in rare cases when a location is not available.
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
return;
}
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mLastLocation != null) {
// Determine whether a Geocoder is available.
if (!Geocoder.isPresent()) {
Toast.makeText(this, R.string.no_geocoder_available, Toast.LENGTH_LONG).show();
return;
}
if (mAddressRequested) {
startIntentService();
}
}
}
/**
* Creates an intent, adds location data to it as an extra, and starts the intent service for
* fetching an address.
*/
protected void startIntentService() {
// Create an intent for passing to the intent service responsible for fetching the address.
Intent intent = new Intent(this, FetchAddressIntentService.class);
// Pass the result receiver as an extra to the service.
intent.putExtra(Constants.RECEIVER, mResultReceiver);
// Pass the location data as an extra to the service.
intent.putExtra(Constants.LOCATION_DATA_EXTRA, mLastLocation);
startService(intent);
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in
// onConnectionFailed.
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
}
#Override
public void onConnectionSuspended(int cause) {
// The connection to Google Play services was lost for some reason. We call connect() to
// attempt to re-establish the connection.
Log.i(TAG, "Connection suspended");
mGoogleApiClient.connect();
}
/**
* Updates the address in the UI.
*/
protected void displayAddressOutput() {
mLocationAddressTextView.setText(mAddressOutput);
}
/**
* Toggles the visibility of the progress bar. Enables or disables the Fetch Address button.
*/
private void updateUIWidgets() {
if (mAddressRequested) {
mProgressBar.setVisibility(ProgressBar.VISIBLE);
mFetchAddressButton.setEnabled(false);
} else {
mProgressBar.setVisibility(ProgressBar.GONE);
mFetchAddressButton.setEnabled(true);
}
}
/**
* Shows a toast with the given text.
*/
protected void showToast(String text) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save whether the address has been requested.
savedInstanceState.putBoolean(ADDRESS_REQUESTED_KEY, mAddressRequested);
// Save the address string.
savedInstanceState.putString(LOCATION_ADDRESS_KEY, mAddressOutput);
super.onSaveInstanceState(savedInstanceState);
}
/**
* Receiver for data sent from FetchAddressIntentService.
*/
class AddressResultReceiver extends ResultReceiver {
public AddressResultReceiver(Handler handler) {
super(handler);
}
/**
* Receives data sent from FetchAddressIntentService and updates the UI in MainActivity.
*/
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
// Display the address string or an error message sent from the intent service.
mAddressOutput = resultData.getString(Constants.RESULT_DATA_KEY);
displayAddressOutput();
// Show a toast message if an address was found.
if (resultCode == Constants.SUCCESS_RESULT) {
showToast(getString(R.string.address_found));
}
// Reset. Enable the Fetch Address button and stop showing the progress bar.
mAddressRequested = false;
updateUIWidgets();
}
}
}
set mAdressRequested from False to True,
so in OnConnected, startIntentService can be called
// Set defaults, then update using values stored in the Bundle.
mAddressRequested = true;
mAddressOutput = "";
updateValuesFromBundle(savedInstanceState);
How can i remove the Geofence? everytime i click the reset button it shows the following error-
Caused by: java.lang.IllegalStateException: GoogleApiClient is not connected yet.
Here is my code-
public class GeofenceStore implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<Status>, LocationListener {
private Context mContext;
/**
* Google API client object.
*/
private GoogleApiClient mGoogleApiClient;
/**
* Geofencing PendingIntent
*/
private PendingIntent mPendingIntent;
/**
* List of geofences to monitor.
*/
private ArrayList<Geofence> mGeofences;
/**
* Geofence request.
*/
private GeofencingRequest mGeofencingRequest;
/**
* Location Request object.
*/
private LocationRequest mLocationRequest;
public GeofenceStore(Context context, ArrayList<Geofence> geofences) {
mContext = context;
mGeofences = new ArrayList<Geofence>(geofences);
mPendingIntent = null;
// Build a new GoogleApiClient, specify that we want to use LocationServices
// by adding the API to the client, specify the connection callbacks are in
// this class as well as the OnConnectionFailed method.
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
Log.i("APi is :", "+" + mGoogleApiClient);
mLocationRequest = new LocationRequest();
// We want a location update every 10 seconds.
mLocationRequest.setInterval(10000);
// We want the location to be as accurate as possible.
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mGoogleApiClient.connect();
}
#Override
public void onConnected(Bundle bundle) {
// We're connected, now we need to create a GeofencingRequest with
// the geofences we have stored.
mGeofencingRequest = new GeofencingRequest.Builder().addGeofences(
mGeofences).build();
mPendingIntent = createRequestPendingIntent();
// This is for debugging only and does not affect
// geofencing.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ActivityCompat.checkSelfPermission(mContext,Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext,Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
GeofenceStore.this.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 100);
// public void requestPermissions(#NonNull String[] permissions, int requestCode)
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for Activity#requestPermissions for more details.
return;
}
}
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
// Submitting the request to monitor geofences.
PendingResult<Status> pendingResult = LocationServices.GeofencingApi
.addGeofences(mGoogleApiClient, mGeofencingRequest,
mPendingIntent);
// Set the result callbacks listener to this class.
pendingResult.setResultCallback(this);
}
private void requestPermissions(String[] strings, int i) {
switch(i)
{
case 100: {
{
Log.i("thanks","asdm");
}
}
}
}
public void removeGeofence(){
LocationServices.GeofencingApi.removeGeofences(
mGoogleApiClient,
// This is the same pending intent that was used in addGeofences().
mPendingIntent
).setResultCallback(this); // Result processed in onResult().
}
private void requestPermissions(int requestCode,String[] permissions, int[] grantResults) {
switch (requestCode) {
case 100: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(mContext, "Thanks for the permission", Toast.LENGTH_LONG).show();
// permission was granted, yay! do the
// calendar task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
Toast.makeText(mContext, "You did not allow to access your current location", Toast.LENGTH_LONG).show();
}
}
// other 'switch' lines to check for other
// permissions this app might request
}
}
/**
* This creates a PendingIntent that is to be fired when geofence transitions
* take place. In this instance, we are using an IntentService to handle the
* transitions.
*
* #return A PendingIntent that will handle geofence transitions.
*/
private PendingIntent createRequestPendingIntent() {
if (mPendingIntent == null) {
Log.v("HERE", "Creating PendingIntent");
Intent intent = new Intent(mContext, GeofenceIntentService.class);
Log.i("another class called",""+intent);
mPendingIntent = PendingIntent.getService(mContext, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
try {
mPendingIntent.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
}
return mPendingIntent;
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onLocationChanged(Location location) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
public void onProviderEnabled(String provider) {
}
public void onProviderDisabled(String provider) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.v("THE CONNECTION HAS", "failed.");
}
public void onSuccess(AsyncTask.Status status) {
}
public void onFailure(Status status) {
}
#Override
public void onResult(Status result) {
if (result.isSuccess()) {
Log.v("THE RESULT IS", "Success!");
} else if (result.hasResolution()) {
// TODO Handle resolution
} else if (result.isCanceled()) {
Log.v("THE RESULT IS", "Canceled");
} else if (result.isInterrupted()) {
Log.v("THE RESULT IS", "Interrupted");
} else {
}
}
}
and here is the function to call from my maps activity, i have used a reset button to reset the geofence added.Pendind intent can be found in the above mentioned code. i want to know what is the problem with it?
The button is-
public void Reset(View view){
db.execSQL("DELETE FROM Coordinates");
//delete all rows in a table
request=request-1;
GeofenceStore mgeofencestore=new GeofenceStore(this,mGeofences);
mgeofencestore.removeGeofence();
db.close();
Toast.makeText(this,"The Data was reset,Please click on 'Add Geofence' to add more Geofence",Toast.LENGTH_LONG).show();
}
You're creating a new GoogleAPIClient every time create a new GeofenceStore object. Since you call removeGeofences() immediately after, the GoogleAPIClient never has a chance to connect, and throws the error you are seeing. Either place a copy of the GeofenceStore object you initially make in the calling class, or create a static instance method to get the current object and avoid recreating it.
i'm trying to use FusedLocationApi with pending intent to get period location updates so i can send the data to some server for processing. Everything works. However, there are some instances where the broadcast just stops receiving. I would need to restart the service again in order for it to continue.
I already have the service onStartCommand to return START_STICKY so even if the app is killed it should start the service again. Furthermore, I also added a Boot Completed Intent Receiver so if the phone died and user restarted phone it would restart my service.
So it seems everything is fine and working but just at some point, everything just stops. I did notice a few times that when it does stop working, the last location i received was NULL (i log every location update and error messages throughout my project).
Any ideas why location services just stops working?
P.S. there is no connection failure because i put a message and hook into that function and it's not being called. And it's not internet failure either as i log that as well. Once internet is restored it would continue as normal/expected.
Thanks.
This is the main activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayShowHomeEnabled(false);
actionBar.setDisplayShowTitleEnabled(false);
if (findViewById(android.R.id.home) != null) {
findViewById(android.R.id.home).setVisibility(View.GONE);
}
LayoutInflater inflator = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflator.inflate(R.layout.header_logo, null);
ActionBar.LayoutParams params = new ActionBar.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT, Gravity.CENTER);
actionBar.setDisplayShowCustomEnabled(true);
actionBar.setCustomView(view, params);
}
setContentView(R.layout.activity_main);
TextView textView = (TextView) findViewById(R.id.status_text);
// init preferences and status handler
MyStatusHandler.init(getApplicationContext(), textView);
// init web service call class
...;
// check for location services
if (!isLocationEnabled(getApplicationContext())){
String msg = "Location services not turned on";
MyStatusHandler.setStatusText(msg);
}
}
public static boolean isLocationEnabled(Context context) {
int locationMode = 0;
String locationProviders;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
try {
locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
return locationMode != Settings.Secure.LOCATION_MODE_OFF;
}else{
locationProviders = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
return !TextUtils.isEmpty(locationProviders);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.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();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
// create new intent activity for the settings page
Intent i = new Intent(this, MySettingsActivity.class);
startActivity(i);
return true;
}
else if (id == R.id.action_about){
// 1. Instantiate an AlertDialog.Builder with its constructor
AlertDialog.Builder builder = new AlertDialog.Builder(this);
// 2. Chain together various setter methods to set the dialog characteristics
if (Constants.DEBUG_BUILD == true) {
builder.setMessage("v." + MyStatusHandler.getReleaseVersionNum() + " dev Build: " + MyStatusHandler.getDevVersionNum())
.setTitle("About")
.setCancelable(false)
.setPositiveButton("OK", null);
}
else{
builder.setMessage("v." + MyStatusHandler.getReleaseVersionNum())
.setTitle("About")
.setCancelable(false)
.setPositiveButton("OK", null);
}
// 3. Get the AlertDialog from create()
AlertDialog dialog = builder.create();
// show it
dialog.show();
return true;
}
return super.onOptionsItemSelected(item);
}
// check email entered
public boolean isSettingsEntered(){
boolean result = true;
if (MyStatusHandler.getEmailText().equals("") || MyStatusHandler.getPasswordText().equals("")){
// 1. Instantiate an AlertDialog.Builder with its constructor
AlertDialog.Builder builder = new AlertDialog.Builder(this);
// 2. Chain together various setter methods to set the dialog characteristics
builder.setMessage("Please ensure both email and password are entered in settings")
.setTitle("Email and/or Password not set")
.setCancelable(false)
.setPositiveButton("OK",null);
// 3. Get the AlertDialog from create()
AlertDialog dialog = builder.create();
// show it
dialog.show();
result = false;
}
return result;
}
/** Called when the user clicks the Opt in button */
public void startService(View view) {
// Do something in response to button
if (isSettingsEntered() && isLocationEnabled(getApplicationContext())) {
// send opt in to web service
...;
// start service
startService(new Intent(this, BackgroundLocationService.class));
// update status text
String msg = "Connecting ...";
MyStatusHandler.setStatusText(msg);
}
}
/** Called when the user clicks the Opt out button */
public void stopService(View view) {
// Do something in response to button
if (isSettingsEntered() && isLocationEnabled(getApplicationContext())) {
// send OptOut to web service
...;
// update status text
String msg = "Connecting ...";
MyStatusHandler.setStatusText(msg);
}
}
public static void ...(boolean isOptIn, Location location, boolean sendOptIn){
if (sendOptIn)
{
// send opt in via async task
}
else{
// send location via async task
}
}
// Handle results returned to the FragmentActivity by Google Play services
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Decide what to do based on the original request code
switch (requestCode) {
case Constants.CONNECTION_FAILURE_RESOLUTION_REQUEST :
// log the error
MyStatusHandler.logDataToFile("Connection Failure Resolution Request - Result Code: "+String.valueOf(resultCode));
// If the result code is Activity.RESULT_OK, try to connect again
switch (resultCode) {
case Activity.RESULT_OK :
// Try the request again
MyStatusHandler.logDataToFile("Attempting to re-start service");
// start service
startService(new Intent(this, BackgroundLocationService.class));
break;
}
}
}
}
Here is the background service:
public class BackgroundLocationService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
public static final String TAG = BackgroundLocationService.class.getSimpleName();
private GoogleApiClient mGoogleApiClient;
private boolean mInProgress;
private LocationRequest mLocationRequest;
public void onCreate(){
super.onCreate();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
#Override
public int onStartCommand (Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
if(mGoogleApiClient.isConnected() || mInProgress)
return START_STICKY;
if(!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting() && !mInProgress) {
mInProgress = true;
mGoogleApiClient.connect();
}
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onConnected(Bundle bundle) {
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setFastestInterval(Constants.FASTEST_INTERVAL)
.setInterval(Constants.UPDATE_INTERVAL);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
new Intent(this, MyLocationHandler.class),
PendingIntent.FLAG_CANCEL_CURRENT);
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, pendingIntent);
}
else{
MyStatusHandler.setStatusText("Google Client Failed");
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
mInProgress = false;
if (connectionResult.hasResolution()) {
try {
// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(null, Constants.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.
Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
MyStatusHandler.setStatusText("Location services connection failed with code " + connectionResult.getErrorCode());
}
}
#Override
public void onDestroy(){
mInProgress = false;
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
super.onDestroy();
}
}
Here is the broadcast receiver:
public class MyLocationHandler extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Location location = intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED);
if (location != null && MyStatusHandler.getOptInStatus()) {
// debug messages
String msg = Double.toString(location.getLatitude()) + "," +
Double.toString(location.getLongitude());
Log.d("debug", msg);
// log location to file
MyStatusHandler.logDataToFile("Location: "+msg);
// send Location to web service
MainActivity....(MyStatusHandler.getOptInStatus(), location, false);
}
if (location == null){
MyStatusHandler.logDataToFile("Location == NULL!");
}
}
}
I have set the interval to 5minutes and Fast interval to 2minutes.
NOTE: i removed some function calls and code for the web service operations
Everything works and i get updates as expected but at some point in time, the broadcast receiver doesn't get anything. When i check the logs, OptInStatus doesn't change and the last location broadcast i received was NULL.
The other parts of my code to call the web service and handle the status messages doesn't touch the service or location requests.
I have the following logic:
Server side making Place Search web service call and gets valid unique cross Google maps API's PlaceId string. Check: Constructing manually URL for Place Details from him (returned PlaceId) returns the expected Place indicating that he has photos in Google's places DB (photos[] in the result Json is not empty...).
So now the server sends to Android client this PlaceId and in android I make API call to Places Photos to get at least one image. It should work because PlaceId is unique place identifier across all Google Maps products. The workflow is pretty much straight forward based on official Google sample, and as seen in the comments in the code the connection part is succeeding and all API set up is good (in the dev console, manifest with API KEY etc.).
The problem is that it's not working: In dev console I see usage count increasing and in the place in the code where I expect to fetch the image nothing happens - The result is that any PlaceId I try (and as mentioned above should have photos) don't have any photos in Google's DB. Also ain't exceptions or something like this to debug. Where is the problem? Thanks,
//Under Activity extends FragmentActivity implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks
private GoogleApiClient mGoogleApiClient = null;
private boolean isConnected = false;
private ImageView mImageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
/* Regular code... */
//Next 2 lines: I don't for what they are good - But in the official Google sample
//they appears - So probably it's right...
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
if (mGoogleApiClient == null) {
rebuildGoogleApiClient();
}
if (isConnected) {
/* This is printed! */
Log.e("TAG", "Start of API Call");
String placeId = /* Call to my server, the result is 100% valid PlaceId that has photos*/
placePhotosTask(placeId, 800, 400); //Height, Width
}
}
private void placePhotosTask(final String placeId, final int width, final int height) {
new PhotoTask(width, height) {
#Override
protected void onPreExecute() {
//TODO Display a temporary image to show while bitmap is loading.
//mImageView.setImageResource(R.drawable.empty_photo);
}
#Override
protected void onPostExecute(AttributedPhoto attributedPhoto) {
if (attributedPhoto != null) {
/* THIS IS NOT PRINTED */
Log.e("TAG", "Success of API Call");
mImageView.setImageBitmap(attributedPhoto.bitmap);
}
}
}.execute(placeId);
}
private class PhotoTask extends AsyncTask<String, Void, PhotoTask.AttributedPhoto> {
private int mHeight;
private int mWidth;
public PhotoTask(int width, int height) {
mHeight = height;
mWidth = width;
}
//Loads the first photo for a place id from the Geo Data API. The place id must be the first (and only) parameter.
#Override
protected AttributedPhoto doInBackground(String... params) {
if (params.length != 1) {
return null;
}
final String placeId = params[0];
AttributedPhoto attributedPhoto = null;
PlacePhotoMetadataResult result = Places.GeoDataApi.getPlacePhotos(mGoogleApiClient, placeId).await();
if (result.getStatus().isSuccess()) {
PlacePhotoMetadataBuffer photoMetadataBuffer = result.getPhotoMetadata();
//BUG!: photoMetadataBuffer.getCount() == 0 Always!
if (photoMetadataBuffer.getCount() > 0 && !isCancelled()) {
//Get the first bitmap and its attributions.
PlacePhotoMetadata photo = photoMetadataBuffer.get(0);
CharSequence attribution = photo.getAttributions();
//Load a scaled bitmap for this photo.
Bitmap image = photo.getScaledPhoto(mGoogleApiClient, mWidth, mHeight).await().getBitmap();
attributedPhoto = new AttributedPhoto(attribution, image);
}
//Release the PlacePhotoMetadataBuffer.
photoMetadataBuffer.release();
}
return attributedPhoto;
}
//Holder for an image and its attribution.
class AttributedPhoto {
public final CharSequence attribution;
public final Bitmap bitmap;
public AttributedPhoto(CharSequence attribution, Bitmap bitmap) {
this.attribution = attribution;
this.bitmap = bitmap;
}
}
}
protected synchronized void rebuildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, 0 /* clientId */, this)
.addConnectionCallbacks(this)
.addApi(Places.GEO_DATA_API)
.build();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
isConnected = false;
}
#Override
public void onConnected(Bundle bundle) {
isConnected = true;
}
#Override
public void onConnectionSuspended(int i) {
isConnected = false;
}
I disagree with the bug comment - photoMetadataBuffer.getCount() == 0 Always. Here is some code that shows loading photos successfully. Note, for context, this code was built inside the Android Studio Google Maps template app, to make it easier to get all the API Key configuration correctly inserted in the application, with the bonus of having a map for displaying results.
private GoogleMap mMap;
private GoogleApiClient mGoogleApiClient;
private final String placeId = "ChIJhSxoJzyuEmsR9gBDBR09ZrE";
private final static String TAG = "MapsActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
mGoogleApiClient = new GoogleApiClient
.Builder(this)
.addApi(Places.GEO_DATA_API)
.addApi(Places.PLACE_DETECTION_API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
protected void onStop() {
mGoogleApiClient.disconnect();
super.onStop();
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
Places.GeoDataApi.getPlaceById(mGoogleApiClient, placeId).setResultCallback(new ResultCallback<PlaceBuffer>() {
#Override
public void onResult(PlaceBuffer places) {
if (places.getStatus().isSuccess() && places.getCount() > 0) {
final Place myPlace = places.get(0);
Log.i(TAG, "Place found: " + myPlace.getName());
mMap.addMarker(new MarkerOptions()
.position(myPlace.getLatLng())
.title(myPlace.getName().toString())
.snippet(myPlace.getAddress().toString()));
mMap.moveCamera(CameraUpdateFactory.newLatLng(myPlace.getLatLng()));
}
places.release();
}
});
Places.GeoDataApi.getPlacePhotos(mGoogleApiClient, placeId).setResultCallback(new ResultCallback<PlacePhotoMetadataResult>() {
#Override
public void onResult(PlacePhotoMetadataResult placePhotoMetadataResult) {
if (placePhotoMetadataResult.getStatus().isSuccess()) {
PlacePhotoMetadataBuffer photoMetadata = placePhotoMetadataResult.getPhotoMetadata();
int photoCount = photoMetadata.getCount();
for (int i = 0; i<photoCount; i++) {
PlacePhotoMetadata placePhotoMetadata = photoMetadata.get(i);
final String photoDetail = placePhotoMetadata.toString();
placePhotoMetadata.getScaledPhoto(mGoogleApiClient, 500, 500).setResultCallback(new ResultCallback<PlacePhotoResult>() {
#Override
public void onResult(PlacePhotoResult placePhotoResult) {
if (placePhotoResult.getStatus().isSuccess()) {
Log.i(TAG, "Photo "+photoDetail+" loaded");
} else {
Log.e(TAG, "Photo "+photoDetail+" failed to load");
}
}
});
}
photoMetadata.release();
} else {
Log.e(TAG, "No photos returned");
}
}
});
}
I've been trying to implement v2 of android's MapView. I got it working just fine with the exception to this bug.
This is what it looks like when I load the app from scratch...
As you can see, no problems there.
Now, when I press the "Home" button and try to access the app from the "recent apps" window i get this:
and it stays that way until i dismiss the app and re-load it from scratch.
Here is some of my code.
Layout.xml
<LinearLayout
android:id="#+id/maps_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_marginBottom="100dip"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:layout_marginTop="100dip"/>
</LinearLayout>
Activity:
public class MyActivity extends BaseActivity {
private GoogleMap mMaps;
private LinearLayout mMapsContainer;
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout);
mMapsContainer = (LinearLayout) findViewById(R.id.maps_container);
mMaps =((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onResume() {
super.onResume();
if (mMaps == null) {
mMaps = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
}
getSupportFragmentManager().findFragmentById(R.id.map).onResume();
}
}
BaseActivity:
public abstract class BaseActivity 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;
// Handle to SharedPreferences for this app
SharedPreferences mPrefs;
// Handle to a SharedPreferences editor
SharedPreferences.Editor mEditor;
boolean mUpdatesRequested = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create a new global location parameters object
mLocationRequest = LocationRequest.create();
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);
}
#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();
}
#Override
public void onPause() {
// Save the current setting for updates
mEditor.putBoolean(LocationUtils.KEY_UPDATES_REQUESTED, mUpdatesRequested);
mEditor.commit();
super.onPause();
}
#Override
public void onStart() {
super.onStart();
/*
* Connect the client. Don't re-start any requests here;
* instead, wait for onResume()
*/
mLocationClient.connect();
}
#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();
}
}
#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:
break;
// If any other result was returned by Google Play services
default:
// Log the result
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;
}
}
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;
}
}
public void getAddress(View v) {
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();
// Start the background task
(new GetAddressTask(this)).execute(currentLocation);
}
}
public void startUpdates(View v) {
mUpdatesRequested = true;
if (servicesConnected()) {
startPeriodicUpdates();
}
}
public void stopUpdates(View v) {
mUpdatesRequested = false;
if (servicesConnected()) {
stopPeriodicUpdates();
}
}
#Override
public void onConnected(Bundle bundle) {
if (mUpdatesRequested) {
startPeriodicUpdates();
}
EventBus.getDefault().post(new EventMessage().new LocationServicesConnected());
}
#Override
public void onDisconnected() {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
try {
// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(
this,
LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
} else {
// If no resolution is available, display a dialog to the user with the error.
showErrorDialog(connectionResult.getErrorCode());
}
}
#Override
public void onLocationChanged(Location location) {
EventBus.getDefault().post(new EventMessage().new LocationChangedEvent(location));
}
private void startPeriodicUpdates() {
mLocationClient.requestLocationUpdates(mLocationRequest, this);
}
private void stopPeriodicUpdates() {
mLocationClient.removeLocationUpdates(this);
}
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;
}
#Override
protected String doInBackground(Location... params) {
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) {
}
}
/**
* 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;
}
}
}
I Disable hardware acceleration at file manifest.xml, and my application doesnt show black map again in second load. i try it in emulator.
<application android:hardwareAccelerated="false">
...
</application
from this article: http://developer.android.com/guide/topics/graphics/hardware-accel.html
A bit late but,I found out that WebViews (even on other fragments) sometime "crash" the GL engine or something which results in black screens in the MapView. I found in LogCat this:
09-30 10:58:17.765: E/libEGL(29805): call to OpenGL ES API with no current context (logged once per thread)
09-30 10:58:17.765: W/Adreno200-EGL(29805): <qeglDrvAPI_eglSwapBuffers:3421>: EGL_BAD_CONTEXT
09-30 10:58:17.765: W/HardwareRenderer(29805): EGL error: EGL_BAD_CONTEXT
09-30 10:58:17.775: W/HardwareRenderer(29805): Mountain View, we've had a problem here.
Switching back to software rendering.
To fix this when the WebView is detached I call the destroy function, in a Fragment so:
#Override
public void onDestroyView() {
if (webView != null) {
webView.destroy();
webView = null;
}
super.onDestroyView();
}
Maybe it'll give you a direction on solving this issue as well.