问题描述
我知道类似的问题已经被问过,但答案是不完美的。
I know similar questions have been asked before but answers were not perfect.
我在使用来自Android开发者网站上的样品code geofences的应用程序。我没有使用任何共享preferences存储geofences因为我不删除geofences。我从地理栅栏内测试应用程序,但我的智能手机收到通知每次当应用程序被杀害的应用程序运行并且没有通知观测时间。为什么会出现这种情况?我想我应该收到通知甚至当应用程序被杀害。
I created an app with geofences using the sample code from android developer website. I did not use any shared preferences to store geofences as I am not removing the geofences. I am testing the app from within the geofence, but my smartphone receives notifications every time the app runs and no notifications are observed when the app is killed. Why does this happen? I think I am supposed to receive notifications even when the app is killed.
MainActivity
MainActivity
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.drawer_layout);
.....
GeofencingTask myTask = new GeofencingTask();
myTask.execute();
}
private class GeofencingTask extends AsyncTask<String,Void,String> implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
@Override
protected void onPreExecute() {
}
@Override
protected String doInBackground(String... params) {
mGoogleApiClient = new GoogleApiClient.Builder(MainActivity.this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
mGeofenceList = new ArrayList<Geofence>();
mGeofenceList.add(new Geofence.Builder()
.setRequestId("1")
.setCircularRegion(
Constants.MyAPP_LOCATION_LATITUDE,
Constants.MyAPP_LOCATION_LONGITUDE,
Constants.MyAPP_RADIUS
)
.setExpirationDuration(Constants.GEOFENCE_EXPIRATION_TIME)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
Geofence.GEOFENCE_TRANSITION_EXIT)
.build());
return null;
}
protected void onPostExecute(String s) {
if (s == null) {
return;
}
}
@Override
public void onConnected(Bundle bundle) {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
);
Toast.makeText(MainActivity.this, "Starting gps", Toast.LENGTH_SHORT).show();
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(MainActivity.this,
Constants.CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Exception while resolving connection error.", e);
}
} else {
int errorCode = connectionResult.getErrorCode();
Log.e(TAG, "Connection to Google Play services failed with error code " + errorCode);
}
}
}
GeofenceTransitionsIntentService.java
GeofenceTransitionsIntentService.java
public class GeofenceTransitionsIntentService extends IntentService{
String TAG = "GeofenceTransitionsIntentService";
int geofenceTransition;
public GeofenceTransitionsIntentService() {
super("name");
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
protected void onHandleIntent(Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
int errorCode = geofencingEvent.getErrorCode();
Log.e(TAG, "Location Services error: " + errorCode);
}
geofenceTransition = geofencingEvent.getGeofenceTransition();
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
// Get the geofences that were triggered. A single event can trigger
// multiple geofences.
List triggeringGeofences = geofencingEvent.getTriggeringGeofences();
// Get the transition details as a String.
String geofenceTransitionDetails = getGeofenceTransitionDetails(
this,
geofenceTransition,
triggeringGeofences
);
Log.i("GeofenceTransitionDetails",geofenceTransitionDetails);
// Send notification and log the transition details.
sendNotification(geofenceTransitionDetails);
sendInOutsTask myTask = new sendInOutsTask();
myTask.execute();
Log.i(TAG, geofenceTransitionDetails);
} else {
// Log the error.
Log.e(TAG, getString(R.string.geofence_transition_invalid_type,
geofenceTransition));
}
}
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;
}
/**
* Posts a notification in the notification bar when a transition is detected.
* If the user clicks the notification, control goes to the MainActivity.
*/
private void sendNotification(String notificationDetails) {
Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(notificationIntent);
PendingIntent notificationPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setSmallIcon(R.mipmap.zemoso_logo)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),
R.mipmap.zemoso_logo))
.setColor(Color.RED)
.setContentTitle(notificationDetails)
.setContentText(getString(R.string.geofence_transition_notification_text))
.setContentIntent(notificationPendingIntent);
builder.setAutoCancel(true);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(0, builder.build());
}
private String getTransitionString(int transitionType) {
switch (transitionType) {
case Geofence.GEOFENCE_TRANSITION_ENTER:
return Constants.WELCOME_NOTIFICATION;
case Geofence.GEOFENCE_TRANSITION_EXIT:
return Constants.EXIT_NOTIFICATION;
default:
return null;
}
}
}
推荐答案
好了,可能有点晚了,但我会后我如何修复这个问题我自己的答案。两件事情:
Ok, May be a bit late but I'll post the answer on how I fixed this issue myself. Two things:
1)我将我每次运行MainActivity和geofences API时触发地理围栏事件geofences,如果添加geofences当你已经指定的地理围栏内(即启动地理围栏应用程序当你已经地理栅栏内)。所以我改变了我的code在onConnected方法只添加,如果他们不加previously的geofences。 (实现使用共享preferences支票)
1) I was adding the geofences every time I run the MainActivity and geofences API triggers the geofencing event, if you add the geofences when you are already inside the specified geofence (i.e. starting the geofence app when you are already inside the geofence).So I changed my code in the onConnected method to add the geofences only if they are not added previously. (Implemented a check using Shared preferences)
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected to GoogleApiClient");
SharedPreferences sharedPrefs = MainActivity.this.getSharedPreferences("GEO_PREFS", Context.MODE_PRIVATE);
String geofencesExist = sharedPrefs.getString("Geofences added", null);
if (geofencesExist == null) {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent(this)
).setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
if (status.isSuccess()) {
SharedPreferences sharedPrefs = MainActivity.this.getSharedPreferences("GEO_PREFS", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putString("Geofences added", "1");
editor.commit();
}
}
});
}
}
2)原来的原因,没有收到通知时,应用程序无法使用均
2) Turns out the reasons for not receiving notifications when the app is not available were
我)无论我在设备切换位置服务(开/关/省电/设备只/高精确度)至少一次后,我加入了geofences或
i) Either I toggled location services in the device(on/off/battery saving/device only/high accuracy) at least once after I added the geofences or,
二)设备进行了重新引导。
ii) The device was rebooted.
要解决这个问题,我添加了一个广播接收器收听到设备重新启动和位置服务切换。在接收机中,我再次加入geofences如果设备要么重新引导或定位服务切换。
To overcome this, I have added a broadcast receiver to listen to device reboots and location services toggling. In the receiver, I am adding the geofences again if the device either rebooted or location services toggled.
public class BootReceiver extends BroadcastReceiver implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<Status> {
private static GoogleApiClient mGoogleApiClient;
private static List<Geofence> mGeofenceList;
private static PendingIntent mGeofencePendingIntent;
private static final String TAG = "BootReceiver";
Context contextBootReceiver;
@Override
public void onReceive(final Context context, Intent intent) {
contextBootReceiver = context;
SharedPreferences sharedPrefs;
SharedPreferences.Editor editor;
if ((intent.getAction().equals("android.location.MODE_CHANGED") && isLocationModeAvailable(contextBootReceiver)) || (intent.getAction().equals("android.location.PROVIDERS_CHANGED") && isLocationServciesAvailable(contextBootReceiver))) {
// isLocationModeAvailable for API >=19, isLocationServciesAvailable for API <19
sharedPrefs = context.getSharedPreferences("GEO_PREFS", Context.MODE_PRIVATE);
editor = sharedPrefs.edit();
editor.remove("Geofences added");
editor.commit();
if (!isGooglePlayServicesAvailable()) {
Log.i(TAG, "Google Play services unavailable.");
return;
}
mGeofencePendingIntent = null;
mGeofenceList = new ArrayList<Geofence>();
mGeofenceList.add(new Geofence.Builder()
.setRequestId("1")
.setCircularRegion(
Constants.MyAPP_LOCATION_LATITUDE,
Constants.MyAPP_LOCATION_LONGITUDE,
Constants.MyAPP_LOCATION_RADIUS
)
.setExpirationDuration(Constants.GEOFENCE_EXPIRATION_TIME)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_DWELL |
Geofence.GEOFENCE_TRANSITION_EXIT)
.setLoiteringDelay(30000)
.build());
mGoogleApiClient = new GoogleApiClient.Builder(contextBootReceiver)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
}
private boolean isLocationModeAvailable(Context context) {
if (Build.VERSION.SDK_INT >= 19 && getLocationMode(context) != Settings.Secure.LOCATION_MODE_OFF) {
return true;
}
else return false;
}
public boolean isLocationServciesAvailable(Context context) {
if (Build.VERSION.SDK_INT < 19) {
LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
return (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) || lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER));
}
else return false;
}
public int getLocationMode(Context context) {
try {
return Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
return 0;
}
@Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected to GoogleApiClient");
SharedPreferences sharedPrefs = contextBootReceiver.getSharedPreferences("GEO_PREFS", Context.MODE_PRIVATE);
String geofencesExist = sharedPrefs.getString("Geofences added", null);
if (geofencesExist == null) {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent(contextBootReceiver)
).setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
if (status.isSuccess()) {
SharedPreferences sharedPrefs = contextBootReceiver.getSharedPreferences("GEO_PREFS", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putString("Geofences added", "1");
editor.commit();
}
}
});
}
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult((android.app.Activity) contextBootReceiver,
Constants.CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
Log.i(TAG, "Exception while resolving connection error.", e);
}
} else {
int errorCode = connectionResult.getErrorCode();
Log.i(TAG, "Connection to Google Play services failed with error code " + errorCode);
}
}
@Override
public void onResult(Status status) {
}
private boolean isGooglePlayServicesAvailable() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(contextBootReceiver);
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
GooglePlayServicesUtil.getErrorDialog(resultCode, (android.app.Activity) contextBootReceiver,
Constants.PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
Log.i(TAG, "This device is not supported.");
}
return false;
}
return true;
}
static GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_DWELL);
builder.addGeofences(mGeofenceList);
return builder.build();
}
static PendingIntent getGeofencePendingIntent(Context context) {
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
Intent intent = new Intent(context, GeofenceTransitionsIntentService.class);
return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
}
Android清单
.
.
.
<receiver
android:name=".BootReceiver"
android:enabled="true"
android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.location.MODE_CHANGED" />
<action android:name="android.location.PROVIDERS_CHANGED" />
</intent-filter>
</receiver>
.
.
这篇关于当应用程序被杀害Geofences不工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!