使用广播接收器未触发Geofences。它与IntentService一起使用,但是当应用程序为后台时却无法使用。.我已更改为广播接收器,以使其无论应用程序是在前台还是在后台运行都可以工作。通过查看以下示例将其更改为“广播接收器”后,即使对于Entry和Dwell,它也停止工作...
主要活动
public class MainActivity extends AppCompatActivity implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<Status> {
private static final String TAG = "Geofence example";
private static final int MULTIPLE_PERMISSIONS = 1;
private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;
private static final String ADDRESS_REQUESTED_KEY = "address-request-pending";
private static final String LOCATION_ADDRESS_KEY = "location-address";
String[] permissions = new String[]{
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.READ_SMS,
Manifest.permission.RECEIVE_SMS,
Manifest.permission.SEND_SMS};
private GeofencingClient mGeofencingClient;
private PendingIntent mGeofencePendingIntent;
private Context mContext;
/**
* Provides access to the Fused Location Provider API.
*/
private FusedLocationProviderClient mFusedLocationClient;
/**
* Represents a geographical location.
*/
private Location mLastLocation;
/**
* Tracks whether the user has requested an address. Becomes true when the user requests an
* address and false when the address (or an error message) is delivered.
*/
private boolean mAddressRequested;
/**
* The formatted location address.
*/
private String mAddressOutput;
/**
* Receiver registered with this activity to get the response from FetchAddressIntentService.
*/
private AddressResultReceiver mResultReceiver;
/**
* Displays the location address.
*/
private TextView mLocationAddressTextView;
/**
* Visible while the address is being fetched.
*/
private ProgressBar mProgressBar;
/**
* Kicks off the request to fetch an address when pressed.
*/
private Button mFetchAddressButton;
private List<Geofence> mGeofenceList;
private GoogleApiClient mGoogleApiClient;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
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 = "";
mContext = this;
updateValuesFromBundle(savedInstanceState);
mGeofencingClient = LocationServices.getGeofencingClient(this);
//LatLng latLng = getLocationFromAddress(mContext, "517 Carrville Rd, Richmond Hill, ON L4C 6E5");
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
SmsReceiver.bindListener(new SMSListener() {
@Override
public void messageReceived(String messageText) {
//From the received text string you may do string operations to get the required OTP
//It depends on your SMS format
Log.d("Message", messageText);
Toast.makeText(MainActivity.this, "Message: " + messageText, Toast.LENGTH_LONG).show();
//startIntentService();
}
});
Log.d(GeofenceTransitionsIntentService.TAG, "OnCreate - Building google API client");
buildGoogleApiClient();
Log.d(GeofenceTransitionsIntentService.TAG, "OnCreate - Before permission check");
if (checkPermissions()) {
Log.d(GeofenceTransitionsIntentService.TAG, "OnCreate - inside Permission ");
getAddress();
}
Log.d(GeofenceTransitionsIntentService.TAG, "mGoogleApiClient = " + mGoogleApiClient);
//test_sendNotification("testing");
updateUIWidgets();
}
@Override
public void onStart() {
super.onStart();
Log.d(GeofenceTransitionsIntentService.TAG, "onStart - before Permission ");
if (!mGoogleApiClient.isConnecting() || !mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
}
}
@Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnecting() || mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
private PendingIntent getGeofencePendingIntent() {
// Reuse the PendingIntent if we already have it.
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
Intent intent = new Intent(this, GeofenceBroadcastReceiver.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
// calling addGeofences() and removeGeofences().
mGeofencePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.
FLAG_UPDATE_CURRENT);
Log.d(GeofenceTransitionsIntentService.TAG, "getGeofencePendingIntent " + mGeofencePendingIntent);
return mGeofencePendingIntent;
}
/**
* 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();
}
}
}
/**
* Runs when user clicks the Fetch Address button.
*/
@SuppressWarnings("unused")
public void fetchAddressButtonHandler(View view) {
if (mLastLocation != null) {
Log.d(GeofenceTransitionsIntentService.TAG, "fetchAddressButtonHandler - mLastLocation " + mLastLocation);
startIntentService();
return;
}
// If we have not yet retrieved the user location, we process the user's request by setting
// mAddressRequested to true. As far as the user is concerned, pressing the Fetch Address button
// immediately kicks off the process of getting the address.
mAddressRequested = true;
updateUIWidgets();
}
/**
* Creates an intent, adds location data to it as an extra, and starts the intent service for
* fetching an address.
*/
private 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);
// Start the service. If the service isn't already running, it is instantiated and started
// (creating a process for it if needed); if it is running then it remains running. The
// service kills itself automatically once all intents are processed.
startService(intent);
Log.d(GeofenceTransitionsIntentService.TAG, "startIntentService - addGeoFenceList " + (mGeofenceList != null));
addGeoFence();
}
/**
* Gets the address for the last known location.
*/
@SuppressWarnings("MissingPermission")
private void getAddress() {
Log.d(GeofenceTransitionsIntentService.TAG, "MainActivity - getAddress () ");
mFusedLocationClient.getLastLocation()
.addOnSuccessListener(this, new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
if (location == null) {
Log.w(GeofenceTransitionsIntentService.TAG, "onSuccess:null");
return;
}
mLastLocation = location;
// Determine whether a Geocoder is available.
if (!Geocoder.isPresent()) {
showSnackbar(getString(R.string.no_geocoder_available));
return;
}
// If the user pressed the fetch address button before we had the location,
// this will be set to true indicating that we should kick off the intent
// service after fetching the location.
if (mAddressRequested) {
startIntentService();
}
}
})
.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.w(TAG, "getLastLocation:onFailure", e);
}
});
}
private GeofencingRequest getGeofencingRequest() {
Log.d(GeofenceTransitionsIntentService.TAG, "MainActivity - getGeofencingRequest ");
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER | GeofencingRequest.INITIAL_TRIGGER_DWELL | GeofencingRequest.INITIAL_TRIGGER_EXIT);
builder.addGeofences(mGeofenceList);
return builder.build();
}
private void addGeoFence() {
Log.d(GeofenceTransitionsIntentService.TAG, "MainActivity - mGeofenceList () ");
mGeofenceList = new ArrayList<Geofence>();
for (Map.Entry<String, LatLng> entry : Constants.GEO_FENCE_LIST.entrySet()) {
mGeofenceList.add(new Geofence.Builder()
// Set the request ID of the geofence. This is a string to identify this
// geofence.
.setRequestId(entry.getKey())
// Set the circular region of this geofence.
.setCircularRegion(
entry.getValue().latitude,
entry.getValue().longitude,
Constants.GEOFENCE_RADIUS_IN_METERS
)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setLoiteringDelay(6000)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
Geofence.GEOFENCE_TRANSITION_EXIT | Geofence.GEOFENCE_TRANSITION_DWELL)
// Create the geofence.
.build());
}
Log.d(GeofenceTransitionsIntentService.TAG, "addGeoFenceList - mGeofenceList " + mGeofenceList);
//getGeofencingRequest();
if (!mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
Toast.makeText(this, "not connected", Toast.LENGTH_SHORT).show();
return;
}
Log.d(GeofenceTransitionsIntentService.TAG, "addGeoFenceList - mGoogleApiClient " + mGoogleApiClient.isConnected());
try {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
// The GeofenceRequest object.
getGeofencingRequest(),
// A pending intent that that is reused when calling removeGeofences(). This
// pending intent is used to generate an intent when a matched geofence
// transition is observed.
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult().
} catch (SecurityException securityException) {
// Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
Log.d(GeofenceTransitionsIntentService.TAG, "addGeoFenceList - error " + securityException.getLocalizedMessage());
}
}
/**
* Updates the address in the UI.
*/
private 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.
*/
private 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);
}
@Override
public void onConnected(@Nullable Bundle bundle) {
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
@Override
public void onResult(Status status) {
if (status.isSuccess()) {
Toast.makeText(
this,
"Geofences Added",
Toast.LENGTH_SHORT
).show();
} else {
// Get the status code for the error and log it using a user-friendly message.
Toast.makeText(
this,
"Geofences error - onResult",
Toast.LENGTH_SHORT
).show();
}
}
/**
* Shows a {@link Snackbar} using {@code text}.
*
* @param text The Snackbar text.
*/
private void showSnackbar(final String text) {
View container = findViewById(android.R.id.content);
if (container != null) {
Snackbar.make(container, text, Snackbar.LENGTH_LONG).show();
}
}
private void showSnackbar(final int mainTextStringId, final int actionStringId,
View.OnClickListener listener) {
Snackbar.make(findViewById(android.R.id.content),
getString(mainTextStringId),
Snackbar.LENGTH_INDEFINITE)
.setAction(getString(actionStringId), listener).show();
}
/**
* Return the current state of the permissions needed.
*/
private boolean checkPermissions() {
int result;
List<String> listPermissionsNeeded = new ArrayList<>();
for (String p : permissions) {
result = ContextCompat.checkSelfPermission(getApplicationContext(), p);
if (result != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(p);
}
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), MULTIPLE_PERMISSIONS);
return false;
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case MULTIPLE_PERMISSIONS: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permissions granted.
getAddress();
} else {
String perStr = "";
for (String per : permissions) {
perStr += "\n" + per;
}
// permissions list of don't granted permission
}
return;
}
}
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
if (!mGoogleApiClient.isConnecting() || !mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
}
Log.d(GeofenceTransitionsIntentService.TAG, "buildGoogleApiClient - mGoogleApiClient " + mGoogleApiClient);
}
private class AddressResultReceiver extends ResultReceiver {
AddressResultReceiver(Handler handler) {
super(handler);
}
@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));
}
Log.d(GeofenceTransitionsIntentService.TAG, "onReceiveResult - onReceiveResult ");
// Reset. Enable the Fetch Address button and stop showing the progress bar.
mAddressRequested = false;
updateUIWidgets();
}
}
}
JobIntentService:
public class GeofenceTransitionsIntentService extends JobIntentService {
protected static final String TAG = "geofence-transitions";
private static final int JOB_ID = 573;
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "GeofenceTransitionsIntentService onCreate ");
}
@Override
protected void onHandleWork(@NonNull Intent intent) {
Log.e(TAG, "GeofenceTransitionsIntentService intent " + intent);
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
String errorMessage = "error";
Log.e(TAG, errorMessage);
return;
}
// Get the transition type.
int geofenceTransition = geofencingEvent.getGeofenceTransition();
String geofenceTransitionString = getTransitionString(geofenceTransition);
Log.e(TAG, "geofence_transition_geofenceTransition " + geofenceTransition);
// Test that the reported transition was of interest.
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
geofenceTransition == Geofence.GEOFENCE_TRANSITION_DWELL || geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
// Get the geofences that were triggered. A single event can trigger multiple geofences.
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
// Get the transition details as a String.
String geofenceTransitionDetails = getGeofenceTransitionDetails(
this,
geofenceTransition,
triggeringGeofences
);
// Send notification and log the transition details.
sendNotification(geofenceTransitionDetails, geofenceTransitionString);
Log.i(TAG, geofenceTransitionDetails);
} else {
// Log the error.
Log.e(TAG, "geofence_transition_invalid_type" + geofenceTransition);
}
}
/**
* Convenience method for enqueuing work in to this service.
*/
public static void enqueueWork(Context context, Intent intent) {
enqueueWork(context, GeofenceTransitionsIntentService.class, JOB_ID, intent);
}
private String getGeofenceTransitionDetails(
Context context,
int geofenceTransition,
List<Geofence> triggeringGeofences) {
String geofenceTransitionString = getTransitionString(geofenceTransition);
// Get the Ids of each geofence that was triggered.
ArrayList triggeringGeofencesIdsList = new ArrayList();
for (Geofence geofence : triggeringGeofences) {
triggeringGeofencesIdsList.add(geofence.getRequestId());
}
String triggeringGeofencesIdsString = TextUtils.join(", ", triggeringGeofencesIdsList);
return geofenceTransitionString + ": " + triggeringGeofencesIdsString;
}
private String getTransitionString(int transitionType) {
switch (transitionType) {
case Geofence.GEOFENCE_TRANSITION_ENTER:
return "Entered";
case Geofence.GEOFENCE_TRANSITION_EXIT:
return "Exited";
case Geofence.GEOFENCE_TRANSITION_DWELL:
return "Dwell";
default:
return "unkwn";
}
}
private void sendNotification(String notificationDetails, String geofenceTransitionString) {
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(getApplicationContext(), "notify_geofence");
Intent ii = new Intent(getApplicationContext(), MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, ii, 0);
//Assign BigText style notification
NotificationCompat.BigTextStyle bigText = new NotificationCompat.BigTextStyle();
bigText.bigText(notificationDetails);
bigText.setSummaryText(geofenceTransitionString);
mBuilder.setContentIntent(pendingIntent);
mBuilder.setSmallIcon(R.mipmap.ic_launcher_round);
mBuilder.setContentTitle("Geofence notification");
mBuilder.setContentText(notificationDetails);
mBuilder.setPriority(Notification.PRIORITY_MAX);
mBuilder.setStyle(bigText);
NotificationManager mNotificationManager =
(NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("notify_001",
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT);
mNotificationManager.createNotificationChannel(channel);
}
mNotificationManager.notify(new Random().nextInt(61) + 20, mBuilder.build());
}
}
广播接收器:
public class GeofenceBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// Enqueues a JobIntentService passing the context and intent as parameters
GeofenceTransitionsIntentService.enqueueWork(context, intent);
}
}
日志:
2018-10-30 12:40:02.850 24811-24811/com.lakshmiapps.findme D/geofence-transitions: fetchAddressButtonHandler - mLastLocation Location[fused 43.849304,-79.449305 hAcc=14 et=+2d21h3m43s23ms alt=161.3000030517578 vAcc=2 sAcc=??? bAcc=??? {Bundle[mParcelledData.dataSize=52]}]
2018-10-30 12:40:02.857 24811-24811/com.lakshmiapps.findme D/geofence-transitions: startIntentService - addGeoFenceList false
2018-10-30 12:40:02.857 24811-24811/com.lakshmiapps.findme D/geofence-transitions: MainActivity - mGeofenceList ()
2018-10-30 12:40:07.819 24811-24811/com.lakshmiapps.findme D/geofence-transitions: addGeoFenceList - mGeofenceList [Geofence[CIRCLE id:Ross Doan transitions:7 43.857670, -79.443370 1000m, resp=0s, dwell=6000ms, @-1], Geofence[CIRCLE id:Niagara falls transitions:7 43.078350, -79.081910 1000m, resp=0s, dwell=6000ms, @-1], Geofence[CIRCLE id:Taste of Malayalees transitions:7 43.635190, -79.622830 1000m, resp=0s, dwell=6000ms, @-1], Geofence[CIRCLE id:Home transitions:7 43.849301, -79.449306 1000m, resp=0s, dwell=6000ms, @-1], Geofence[CIRCLE id:Luv2Play transitions:7 43.855660, -79.430200 1000m, resp=0s, dwell=6000ms, @-1]]
2018-10-30 12:40:09.534 24811-24811/com.lakshmiapps.findme D/geofence-transitions: addGeoFenceList - mGoogleApiClient true
2018-10-30 12:40:09.534 24811-24811/com.lakshmiapps.findme D/geofence-transitions: MainActivity - getGeofencingRequest
2018-10-30 12:40:13.598 24811-24811/com.lakshmiapps.findme D/geofence-transitions: getGeofencePendingIntent PendingIntent{5fddab6: android.os.BinderProxy@47dc3b7}
2018-10-30 12:40:13.631 4938-5579/? I/GeofencerStateMachine: addGeofences called by com.lakshmiapps.findme
2018-10-30 12:40:13.631 4726-4773/? E/GmsLocationManagerService_FLP: [GeofencingApi] AddGeofence from com.lakshmiapps.findme and size = 5
2018-10-30 12:40:13.632 4726-4773/? D/GeofenceRequestInfo_FLP: removeExpiredGeofences - com.lakshmiapps.findme: 0 fences
2018-10-30 12:40:13.632 4726-4773/? E/GeofenceRequestManager_FLP: [GeofencingApi] AddGeofence 5 fences from com.lakshmiapps.findme
2018-10-30 12:40:13.632 4726-4773/? D/GeofenceRequestManager_FLP: 1540668973552 gpslastknowntime: 243443714 / nlplastknowntime: 248290794
2018-10-30 12:40:16.290 24811-24811/com.lakshmiapps.findme D/geofence-transitions: onReceiveResult - onReceiveResult
2018-10-30 12:44:08.692 4938-24505/? I/GeofencerStateMachine: removeGeofences: removeRequest=RemoveGeofencingRequest[REMOVE_BY_PENDING_INTENT pendingIntent=PendingIntent[creatorPackage=com.marriott.mrt], packageName=null]
谢谢, 拉梅什
答案 0 :(得分:-1)
添加
<uses-permission android:name="android.permission.WAKE_LOCK" />
AndroidManifest.xml似乎可以解决我的问题