Via GPS kontrollieren ob man in einem bestimmten Koordinatenbereich ist

P

prosk

Neues Mitglied
1
Hallo,

Ich arbeite gerade an einer App, wo ich überprüfen muss, ob man mit seinem Handy in einem bestimmten Koordinatenbereich (vorzugsweise Rechteck) ist.

Hat jemand schon so eine Funktion oder ähnliches entwickelt?

LG.
prosk
 
Gucke dir mal Geofence aus dem Google Play Services...

lg. Dagobert
 
Jo Geofense wäre ein Stichwort...
... oder was "Selbstgestricktes" :p

Als Pseudo-Code:
Code:
if ((latitude < latitudeMax && latitude > latitudeMin) &&
                        (longitude < longitudeMax && longitude > longitudeMin))
Erklärung.. latitude und longitude sind die Werte, die du als Position (an)nimmst und die prüfst du auf "obere und untere Grenze".

Etwas kniffliger (und leicht zu übersehen) ist, dass nicht überall auf der Erde die Abstände zwischen den Koordinaten gleich sind.
Wenn du dir den Globus ansiehst, siehst du, dass oben die Längengrade deutlich schmaler ausfallen, als an äquatornähe. :)


Globus_Europa_Afrika_268172.jpg
 
Hey ho,

vergiss bitte das was ui_3k1 vorgeschlagen hat :p

Mach es bloß nicht selbst... Google ist da wesentlich effektiver...
und warum jedes mal das Rat neu erfinden... und denk daran was da alles zu steuern ist was google dir schon abnimmt...
und und und

lg. Dagobert
 
DagobertDokate schrieb:
Google ist da wesentlich effektiver...
und warum jedes mal das Rat neu erfinden... und denk daran was da alles zu steuern ist was google dir schon abnimmt...
und und und

1. Warum sollte Google effektiver sein? Es werden Wertebereiche miteinander verglichen, ich weiß nicht wo hier der riesige Performance-Schub zu erwarten ist... Ich prüfe mit der Methode derzeit ca. 50000 Einträge* ab und es geht ohne kleinstes Delay. Auch auf einem S2 getestet, das heute bei weitem nicht mehr "State of the Art" ist
2. warum sich auf eine API verlassen, die unter einer neuen Android-Version ggf. angespasst werden muss? Hier ist meine Implementierung jedenfalls super "solide". (Derzeit bin gefühlt ca. 50% meiner Zeit daran zu Gange Methoden, die seitens der API veraltet sind, auszutauschen - ich umgehe daher jede API solange sich ein halbwegs praktikabler Weg abzeichnet, die Logik selbst zu implementieren - und den sehe ich hier definitiv...)
3. "und und und" hätte ich gerne genauer beschrieben :)

*um genau zu sein, läuft die Logik sogar 2x ab... Ich treffe eine Vorsortierung (in der Datenbank) und letztlich werden "intern" im Programm nur noch weniger als 5 Bereiche genauer geprüft.

Vielleicht hast du recht, wenn die Daten aus dem Netz kommen und man erst jede Geolocation laden müsste, aber im "offline" Betrieb ist die Verwendung von Google Geofense garantiert nicht notwendig... Ich weiß ehrlich gesagt auch gar nicht wie Geofense funktioniert, braucht man dafür Internet? Dann wäre der Dienst im Ausland ja schon wieder ungünstig abrufbar. :razz:
 
Danke für die sehr hilfreichen Antworten. Hab mich über jede sehr gefreut :)

Werde jetzt mit Geofence Traninig beginnen :biggrin:
 
Habe jetzt das Training von Creating and Monitoring Geofences | Android Developers gemacht. Leider bekomme ich es einfach nicht hin, dass ich in einen bestimmten Bereich komme und ein ENTER Event aufgerufen wird. Vielleicht ist das Tutorial auch einfach zu schwer für mich. Bin noch ein Anfänger Entwickler.

Hätte vielleicht jemand ein leichteres Tutorial, oder einen Code-Ausschnitt aus einer funktionierendem App.
 
Jo, was brauchst du genau? Bzw. welche Daten greifst du momentan wie ab? Je genauer du das beschreibst, desto besser kann dir geholfen werden.

Hab mir die Geo-Fencing Doku auch mal angesehen, finde es auch ziemlich "umfangreich". Bin mir fast sicher, dass meine derzeitige Lösung performanter und weniger fehleranfällig ist, als eine halbherzig implementierte Geofancing-API - ich hab jedenfalls keine Ahnung für was man jetzt unbedingt onRemoveGeofencesByRequestIdsResult(List<String>, LocationClient.OnRemoveGeofencesResultListener) bräuchte. Was die Benennung von Methoden angeht ist Google auch ziemlich kreativ, da komme ich nicht immer mit^^
 
Zuletzt bearbeitet:
Bevor ich meine BA jetzt vom Stick löschen :D

Bitte schön^^ (Package-Name und Anfangs-Kommentar entfernt)
Code:
public class GeofenceBootReceiver extends BroadcastReceiver {

	public static final String TAG = GeofenceBootReceiver.class.getSimpleName();

	@Override
	public void onReceive(Context context, Intent intent) {
		Log.v(TAG, "onReceive()");
		GeofenceHelper helper = new GeofenceHelper(context);
		helper.initGeofencesFromDB();
	}

}
Code:
public class GeofenceHelper implements ConnectionCallbacks,
		OnConnectionFailedListener, OnAddGeofencesResultListener,
		OnRemoveGeofencesResultListener {

	private static final String TAG = GeofenceHelper.class.getSimpleName();

	private static final String ENTER_SUFFIX = "_enter";

	private static final String EXIT_SUFFIX = "_exit";

	private final Context context;
	private final LocationClient locationClient;
	private final List<Geofence> geofencesToAdd;
	private final List<String> geofencesToRemove;
	private Action action;

	private enum Action {
		ADD, REMOVE
	}

	public GeofenceHelper(Context context) {
		this.context = context;
		locationClient = new LocationClient(context, this, this);
		geofencesToAdd = new LinkedList<Geofence>();
		geofencesToRemove = new LinkedList<String>();
	}

	public void initGeofencesFromDB() {
		Log.v(TAG, "initGeofencesFromDb()");
		action = Action.ADD;
		Cursor cursor = context.getContentResolver().query(
				LocationContentProvider.CONTENT_URI, null, null, null, null);
		Geofence.Builder builder = new Geofence.Builder();
		String id;
		double latitude, longitude;
		float radius;
		while (cursor.moveToNext()) {
			// FIXME Util benutzen
			id = cursor.getString(cursor
					.getColumnIndex(LocationTable.ID))
					+ ENTER_SUFFIX;
			latitude = cursor.getDouble(cursor
					.getColumnIndex(LocationTable.LATITUDE));
			longitude = cursor.getDouble(cursor
					.getColumnIndex(LocationTable.LONGITUDE));
			radius = cursor.getFloat(cursor
					.getColumnIndex(LocationTable.RADIUS));
			builder.setRequestId(id)
					.setCircularRegion(latitude, longitude, radius)
					.setExpirationDuration(Geofence.NEVER_EXPIRE)
					.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER);
			geofencesToAdd.add(builder.build());
			id = cursor.getString(cursor
					.getColumnIndex(LocationTable.ID))
					+ EXIT_SUFFIX;
			builder.setRequestId(id).setTransitionTypes(
					Geofence.GEOFENCE_TRANSITION_EXIT);
			geofencesToAdd.add(builder.build());
		}
		locationClient.connect();
	}

	public void addGeofences(SimpleGeofence geofence) {
		Geofence newGeofence = GeofenceUtil.convertToGeofenec(geofence);
		geofencesToAdd.add(newGeofence);
		locationClient.connect();
	}

	@Override
	public void onConnectionFailed(ConnectionResult result) {
		// TODO Auto-generated method stub
	}

	@Override
	public void onConnected(Bundle connectionHint) {
		switch (action) {
		case ADD:
			locationClient.addGeofences(geofencesToAdd, getPendingIntent(),
					this);
			geofencesToAdd.clear();
			break;
		case REMOVE:
			locationClient.removeGeofences(geofencesToRemove, this);
			geofencesToRemove.clear();
			break;
		}
	}

	private PendingIntent getPendingIntent() {
		Intent intent = new Intent(context,
				ReceiveTransitionsIntentService.class);
		return PendingIntent.getService(context, 0, intent,
				PendingIntent.FLAG_UPDATE_CURRENT);
	}

	@Override
	public void onDisconnected() {
		Log.v(TAG, "onDiscconected()");
	}

	@Override
	public void onAddGeofencesResult(int statuscode, String[] geofenceRequestIds) {
		locationClient.disconnect();
	}

	public void removeGeofencesFromDb() {
		action = Action.REMOVE;
		Cursor cursor = context.getContentResolver().query(
				LocationContentProvider.CONTENT_URI, null, null, null, null);
		while (cursor.moveToNext()) {
			String enterId = cursor.getString(cursor
					.getColumnIndex(LocationTable.ID))
					+ ENTER_SUFFIX;
			String exitId = cursor.getString(cursor
					.getColumnIndex(LocationTable.ID))
					+ EXIT_SUFFIX;
			geofencesToRemove.add(enterId);
			geofencesToRemove.add(exitId);
		}

		if (!geofencesToRemove.isEmpty()) {
			locationClient.connect();
		}
	}

	@Override
	public void onRemoveGeofencesByPendingIntentResult(int statusCode,
			PendingIntent pendingIntent) {
		locationClient.disconnect();
	}

	@Override
	public void onRemoveGeofencesByRequestIdsResult(int statusCode,
			String[] geofenceRequestIds) {
		locationClient.disconnect();
	}
}
Code:
public class ReceiveTransitionsIntentService extends IntentService {

	private static final String TAG = ReceiveTransitionsIntentService.class
			.getSimpleName();

	public ReceiveTransitionsIntentService() {
		super(ReceiveTransitionsIntentService.class.getSimpleName());
		Log.v(TAG, "ReceiverTransitionsIntetSerivce()");
	}

	@Override
	protected void onHandleIntent(Intent intent) {
		Log.v(TAG, "onHandleIntent()");
		if (LocationClient.hasError(intent)) {
			int errorCode = LocationClient.getErrorCode(intent);
			Log.e(TAG, "errorCode: " + errorCode);
			return;
		}

		int transitionType = LocationClient.getGeofenceTransition(intent);
		switch (transitionType) {
		case Geofence.GEOFENCE_TRANSITION_ENTER:
			showNotification(intent);
			break;
		case Geofence.GEOFENCE_TRANSITION_EXIT:
			hideNotification(intent);
		}
	}

	private void showNotification(final Intent intent) {
		Log.v(TAG, "showNotification()");
		NotificationManager nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
		NotificationCompat.Builder nBuilder = new NotificationCompat.Builder(
				this);
		for (Geofence geofence : LocationClient.getTriggeringGeofences(intent)) {
			long id = Long.parseLong(geofence.getRequestId().split("_")[0]);
			Uri uri = ContentUris.withAppendedId(
					LocationContentProvider.CONTENT_URI, id);
			Cursor cursor = getContentResolver().query(uri, null, null, null,
					null);
			cursor.moveToFirst();
			SimpleGeofence location = SimpleGeofenceBuilder.fromCursor(cursor);
			cursor.close();

			Intent newIntent = new Intent(this, MainActivity.class);
			newIntent.putExtra(MainActivity.ARG_ID, id);
			PendingIntent pIntent = PendingIntent.getActivity(this, (int) id,
					newIntent, PendingIntent.FLAG_CANCEL_CURRENT
							| PendingIntent.FLAG_UPDATE_CURRENT);

			nBuilder.setContentTitle(location.getTitle())
					.setContentText(location.getDescription())
					.setTicker(location.getTitle()).setContentIntent(pIntent)
					.setSmallIcon(R.drawable.ic_launcher).setAutoCancel(true);
			nManager.notify((int) id, nBuilder.build());
		}
	}

	private void hideNotification(Intent intent) {
		Log.v(TAG, "hideNotification()");
		NotificationManager nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
		for (Geofence geofence : LocationClient.getTriggeringGeofences(intent)) {
			long id = Long.parseLong(geofence.getRequestId().split("_")[0]);
			nManager.cancel((int) id);
		}
	}
}

fragen kannst du ruhig dazu stellen :D

lg. Dagobert
 
  • Danke
Reaktionen: prosk und ui_3k1
Hui, ich frage mich gerade wie man es schafft so sauberen Code zu schreiben :)
 
Wie registrierst du den BroadcastReceiver?
 
Zuletzt bearbeitet:
Via Manifest:
Code:
 <!-- Boot receiver -->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
und
Code:
<!-- Boot receiver -->
        <receiver android:name=".geofence.GeofenceBootReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
        <!-- Geofence Service -->
        <service
            android:name=".geofence.ReceiveTransitionsIntentService"
            android:exported="false"
            android:label="@string/app_name" />

lg. Dagobert
 
  • Danke
Reaktionen: prosk
ist es richtig das
<receiver android:name=".geofence.GeofenceBootReceiver" > <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter>

das onResume auslöst? Hab noch nie mit BroadcastReceiver gearbeitet^^, wenn ja, warum bei BOOT_COMPLETED?

lg
 
Zuletzt bearbeitet:

Ähnliche Themen

U
  • unerfahrenerAppEntwickler
Antworten
3
Aufrufe
740
swa00
swa00
S
Antworten
7
Aufrufe
1.198
swa00
swa00
Zurück
Oben Unten