简体   繁体   English

Android - 当应用程序被杀时Geofence消失

[英]Android - Geofence disappearing when app is killed

At the risk of being marked as duplicate, I ask this question once more. 冒被标记为重复的风险,我再次提出这个问题。 I've tried every proposed solution here in stackoverflow (except using a third party library because I want to use GoogleAPIClient instead) and still, I cannot make it work. 我已经在stackoverflow中尝试了所有提出的解决方案(除了使用第三方库,因为我想使用GoogleAPIClient ),但我仍然无法使其工作。 I used IntentService and BroadcastReceiver ; 我使用了IntentServiceBroadcastReceiver ; geofences still keep disappearing after I close the app. 关闭应用程序后,地理围栏仍然在消失。 If it's in foreground or background, it works perfectly but completely killing the app also completely kills the geofences. 如果它在前景或背景中,它可以完美地工作,但完全杀死应用程序也完全杀死了地理围栏。

I've only tested it in Nougat and Marshmallow. 我只在Nougat和Marshmallow测试过它。 Does the new Doze function of Android affect it? Android的新Doze功能会影响它吗? My GPS is always on, my device doesn't restart, although I've turned off my wifi/data because I want the geofencing to depend purely on the GPS. 我的GPS始终打开,我的设备没有重启,虽然我已经关闭了我的wifi /数据,因为我希望地理围栏完全依赖于GPS。 Oh, and I'm using a fake gps app to test it. 哦,我正在使用假的gps应用程序来测试它。

Below are the relevant parts of my code: 以下是我的代码的相关部分:

Home.java Home.java

public class Home extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_home);

    if (db.isEmpty()) {
        getData(); //get geofences from the server. at this point, the wifi is still on
    } else {
        startGeofencing();
    }


}

 private void startGeofencing(){
    //Set up geofence
    GeofencingMethods gM = new GeofencingMethods(getApplicationContext(), prefs);
    RealmResults<ServerGeofence> geofenceList = realm.where(ServerGeofence.class).findAll();
    for (ServerGeofence g : geofenceList) {
        Geofence geofence = gM.createGeofence(g.getGeof_name(), g.getGeof_lat(), g.getGeof_long(), g.getGeof_rad()*1000);
        gM.addToGeofencingRequest(geofence);
    }

    //Build googleApiClient and connect to service
    gM.buildGoogleApiClient();
}

GeofencingMethods.java GeofencingMethods.java

public class GeofencingMethods {
private GeofencingRequest.Builder geofencingRequestBuilder;
private PendingIntent geofencePendingIntent;
private Context c;
private GoogleApiClient googleApiClient;
private SharedPreferences prefs;

public GeofencingMethods(Context c, SharedPreferences prefs) {
    this.c = c;
    this.prefs = prefs;
    geofencingRequestBuilder = new GeofencingRequest.Builder()
            .setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER | GeofencingRequest.INITIAL_TRIGGER_DWELL);
}

public Geofence createGeofence(String name, double lat, double lng, float radius) {
    return new Geofence.Builder()
            .setRequestId(name)
            .setCircularRegion(lat, lng, radius)
            .setExpirationDuration(Geofence.NEVER_EXPIRE)
            .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER
                    | Geofence.GEOFENCE_TRANSITION_DWELL
                    | Geofence.GEOFENCE_TRANSITION_EXIT)
            .setLoiteringDelay(Constants.LOITERING_DELAY) //10 minutes dwelling
            .build();
}

public void addToGeofencingRequest(Geofence g) {
           prefs.edit().putInt(Constants.GEOFENCE_NUM, prefs.getInt(Constants.GEOFENCE_NUM, 0)+1).commit();
    geofencingRequestBuilder.addGeofence(g);
}

public PendingIntent createPendingIntent() {
    if (geofencePendingIntent != null) return geofencePendingIntent;

 //   Intent intent = new Intent(c, GeofenceTriggeredService.class);
 //   geofencePendingIntent = PendingIntent.getService(c, Constants.PENDING_INTENT_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);


    Intent intent = new Intent(Constants.ACTION_GEOFENCE_RECEIVED);
    geofencePendingIntent = PendingIntent.getBroadcast(c, Constants.PENDING_INTENT_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);

    return geofencePendingIntent;
}

public void addToGeofencingApi(){
    if (ActivityCompat.checkSelfPermission(c, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

    }

    LocationServices.GeofencingApi.addGeofences(
            googleApiClient, geofencingRequestBuilder.build(), createPendingIntent())
            .setResultCallback(new ResultCallback<Status>() {
                @Override
                public void onResult(Status status) {
                    if (status.isSuccess()) {
                        Toast.makeText(
                                c,
                                "Geofences added",
                                Toast.LENGTH_SHORT
                        ).show();

                    } else if (status.getStatusCode() == 1000) {
                        Toast.makeText(
                                c,
                                "Please turn on Google Location services in Settings. Switch to \"High Accuracy\" mode",
                                Toast.LENGTH_LONG
                        ).show();


                        prefs.edit().putInt(Constants.GEOFENCE_NUM, 0).commit();
                    }


                }
            });
}
//Building googleAPI client
public synchronized void buildGoogleApiClient() {
    if (googleApiClient == null) {
        googleApiClient = new GoogleApiClient.Builder(c)
                .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
                    @Override
                    public void onConnected(@Nullable Bundle bundle) {
                        System.out.println("GOOGLE API CLIENT CONNECTED");
                        addToGeofencingApi();
                        //Go to service when triggered

                    }
                    @Override
                    public void onConnectionSuspended(int i) {
                        if(googleApiClient!=null){
                            googleApiClient.connect();
                        }
                    }
                })
                .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
                    @Override
                    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
                        Toast.makeText(c, "Failed to connect to GoogleApiClient. Please restart application.", Toast.LENGTH_LONG).show();
                    }
                })
                .addApi(LocationServices.API).build();

    }
    if(!googleApiClient.isConnected() && !googleApiClient.isConnecting()){
        googleApiClient.connect();
    }
}

GeofenceReceiver.java GeofenceReceiver.java

public class GeofenceReceiver extends BroadcastReceiver {
private Context c;
private SharedPreferences prefs;


@Override
public void onReceive(Context context, Intent intent) {
    this.c = context;
    prefs = c.getSharedPreferences(Constants.PREFS_NAME, Context.MODE_PRIVATE);

    LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
    if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
        if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            context.registerReceiver(this, new IntentFilter(LocationManager.PROVIDERS_CHANGED_ACTION));

        }
    }

    if ("android.location.PROVIDERS_CHANGED".equals(intent.getAction())) {
        if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            if (realm.where(ServerGeofence.class).count() <= 0) {
                getData();
            } else {
                startGeofencing();
            }
        } else {
            // go to settings and do it!!
        }
    }

    if(Constants.ACTION_GEOFENCE_RECEIVED.equals(intent.getAction())) {
        Toast.makeText(context, "Geofence Spotted", Toast.LENGTH_LONG).show();
        new NotificationMaker(context).geofenceEvent(intent);
    }
}

NotificationMaker.java NotificationMaker.java

public class NotificationMaker {
private Context c;
private int s;

public NotificationMaker(Context c){
    this.c = c;
}

public void geofenceEvent(Intent intent) {
    GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);

    if (geofencingEvent.hasError()) {
        Toast.makeText(c, "ERROR: " + getErrorString(geofencingEvent.getErrorCode()), Toast.LENGTH_LONG).show();
        return;
    }

    int geoFenceTransition = geofencingEvent.getGeofenceTransition();

    if (geoFenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || geoFenceTransition == Geofence.GEOFENCE_TRANSITION_DWELL
            || geoFenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
        List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
        String geofenceTransitionDetails = getGeofenceTransitionDetails(geoFenceTransition, triggeringGeofences);

        sendNotification(geofenceTransitionDetails);

    }
}

private String getGeofenceTransitionDetails(int geoFenceTransition, List<Geofence> triggeringGeofences) {
    ArrayList<String> triggeringGeofencesList = new ArrayList<>();
    for (Geofence geofence : triggeringGeofences) {
        triggeringGeofencesList.add(geofence.getRequestId());
    }
    String status = null;
    s = 0;
    if (geoFenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER) {
        status = "Entering ";
        s = 0;
    } else if (geoFenceTransition == Geofence.GEOFENCE_TRANSITION_DWELL) {
        status = "Dwelling ";
        s = 1;
    } else if (geoFenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
        status = "Exiting ";
        s = 2;
    }

    //log event

    return status + TextUtils.join(", ", triggeringGeofencesList);
}

private String getErrorString(int errorCode) {
    switch (errorCode) {
        case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE:
            return "GeoFence not available";
        case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
            return "Too many GeoFences";
        case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
            return "Too many pending intents";
        default:
            return "Unknown error.";
    }
}

private Notification createNotification(String msg, PendingIntent notificationPendingIntent) {

    System.out.println("Creating notification");
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(c);
    notificationBuilder
            .setSmallIcon(com.google.android.gms.R.drawable.common_full_open_on_phone)
            .setColor(ContextCompat.getColor(c, R.color.colorPrimary))
            .setContentTitle(msg)
            .setContentText("Geofence Spotted")
            .setContentIntent(notificationPendingIntent)
            .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE)
            .setAutoCancel(true);
    return notificationBuilder.build();


}

private void sendNotification(String msg) {

    System.out.println("Sending notification");
    Intent notificationIntent = new Intent(c, Home.class);
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(c);
    stackBuilder.addParentStack(Home.class);
    stackBuilder.addNextIntent(notificationIntent);

    int id = (int) System.currentTimeMillis();
    PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(id, PendingIntent.FLAG_UPDATE_CURRENT);

    NotificationManager notificationManager = (NotificationManager) c.getSystemService(Context.NOTIFICATION_SERVICE);
    notificationManager.notify(id, createNotification(msg, notificationPendingIntent));
}

} }

AndroidManifest AndroidManifest

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

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".SplashScreen">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity android:name=".Home"/>


    <service android:name="com.example.GeofenceTriggeredService"
        android:enabled="true"
        android:directBootAware="true"
        android:exported="false"/>

    <receiver android:name="com.example.GeofenceReceiver"
        android:enabled="true"
        android:exported="false"
        android:permission="android.permission.RECEIVE_BOOT_COMPLETED" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
            <action android:name="android.location.PROVIDERS_CHANGED" />
            <action android:name="android.location.MODE_CHANGED" />
            <action android:name="com.example.ACTION_GEOFENCE_RECEIVED"/>
        </intent-filter>
    </receiver>

</application>

Any help would be appreciated! 任何帮助,将不胜感激! :D :d

Upon boot and starting the app I would start an IntentService that then registers a Geofence: 在启动并启动应用程序后,我将启动一个IntentService,然后注册Geofence:

public class RegisterGeoIntentService extends IntentService {
...
    Intent intent = new Intent("com.xyz.app.ACTION_RECEIVE_GEOFENCE");
    return PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
...

And then in the registered Intent: 然后在注册的意图中:

public class GeofenceReceiver extends BroadcastReceiver {
...

   @Override
   public void onReceive(Context context, Intent intent) {
    this.context = context;

    GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
    if(geofencingEvent.hasError()) {
        String errorMessage = GeoErrorMessages.getErrorString(context, geofencingEvent.getErrorCode());
        Log.e(TAG, errorMessage);
        return;
    }

    int geofenceTransition = geofencingEvent.getGeofenceTransition();

    if(geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM