Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
698 views
in Technique[技术] by (71.8m points)

google play services - How to make Geo Fencing alert more accurate in Android

Hello I am trying to add feature of Geo Fence in Android. I am using the http://developer.android.com/training/location/geofencing.html for creating and monitoring Geo Fences. I am using the IntentService for the alert (Entered/Exited) but for me it is not working.

But When I went away and come back into region to test it then it didn't work for me. I have turned ON the GPS of the device but device is not connected with internet.

Anyone can you please help me to make it more accurate and perfectly without any issue.

public class MainActivity extends Activity implements GooglePlayServicesClient.ConnectionCallbacks,
        GooglePlayServicesClient.OnConnectionFailedListener,
        LocationClient.OnAddGeofencesResultListener {

    private LocationClient locationClient;

    private String TAG = "MainActivity";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        int resp = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
        if (resp == ConnectionResult.SUCCESS) {
            locationClient = new LocationClient(this, this, this);
            locationClient.connect();
        }
    }

    @Override
    public void onConnected(Bundle bundle) {
        ArrayList<Store> storeList = getStoreList();
        if (null != storeList && storeList.size() > 0) {
            ArrayList<Geofence> geofenceList = new ArrayList<Geofence>();
            for (Store store : storeList) {
                float radius = (float) store.radius;
                Geofence geofence = new Geofence.Builder()
                        .setRequestId(store.id)
                        .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
                        .setCircularRegion(store.latitude, store.longitude, radius)
                        .setExpirationDuration(Geofence.NEVER_EXPIRE)
                        .build();

                geofenceList.add(geofence);
            }

            PendingIntent geoFencePendingIntent = PendingIntent.getService(this, 0,
                    new Intent(this, GeofenceIntentService.class), PendingIntent.FLAG_UPDATE_CURRENT);
            locationClient.addGeofences(geofenceList, geoFencePendingIntent, this);
        }
    }

    @Override
    public void onDisconnected() {
        Log.e(TAG, "Disconnected !");
    }

    @Override
    public void onAddGeofencesResult(int i, String[] strings) {
        if (LocationStatusCodes.SUCCESS == i) {
            //todo check geofence status
        } else {

        }
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.e(TAG, connectionResult.getErrorCode() + "");
    }

    private ArrayList<Store> getStoreList() {
        ArrayList<Store> storeList = new ArrayList<Store>();
        for (int i = 0; i < 1; i++) {
            Store store = new Store();
            store.id = String.valueOf(i);
            store.address = "India";
            store.latitude = 26.7802187;
            store.longitude = 75.860322;
            store.radius = 100.0;

            storeList.add(store);
        }

        return storeList;
    }

    public class Store {
        String id;
        String address;
        double latitude;
        double longitude;
        double radius;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (null != locationClient) {
            locationClient.disconnect();
        }
    }
}

GeofenceIntentService.java

public static final String TRANSITION_INTENT_SERVICE = "ReceiveTransitionsIntentService";

public GeofenceIntentService() {
    super(TRANSITION_INTENT_SERVICE);
}

@Override
protected void onHandleIntent(Intent intent) {
    if (LocationClient.hasError(intent)) {
        //todo error process
    } else {
        int transitionType = LocationClient.getGeofenceTransition(intent);
        if (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER ||
                transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) {
            List<Geofence> triggerList = LocationClient.getTriggeringGeofences(intent);

            for (Geofence geofence : triggerList) {
                generateNotification(geofence.getRequestId(), "address you defined");
            }
        }
    }
}

private void generateNotification(String locationId, String address) {
    long when = System.currentTimeMillis();
    Intent notifyIntent = new Intent(this, MainActivity.class);
    notifyIntent.putExtra("id", locationId);
    notifyIntent.putExtra("address", address);
    notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    NotificationCompat.Builder builder =
            new NotificationCompat.Builder(this)
                    .setSmallIcon(R.drawable.dac_logo)
                    .setContentTitle(locationId)
                    .setContentText(address)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(true)
                    .setDefaults(Notification.DEFAULT_SOUND)
                    .setWhen(when);    

    NotificationManager notificationManager =   
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    notificationManager.notify((int) when, builder.build());   
 }
 }

AndroidManifest.xml

  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.demo"
android:versionCode="1"    
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="17" />

<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" />
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />

<application
    android:allowBackup="true"
    android:icon="@drawable/dac_logo"
    android:label="@string/app_name" >
    <activity
        android:name=".MainActivity"
        android:excludeFromRecents="true"
        android:label="@string/app_name"
        android:launchMode="singleTask"
        android:taskAffinity="" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

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

    <service
        android:name=".GeofenceIntentService"
        android:exported="false" />

    <receiver android:name="com.location.demo.receivers.BootCompleteReceiver" >    
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />    
        </intent-filter>
    </receiver>

    <meta-data
        android:name="com.google.android.gms.version"    
        android:value="@integer/google_play_services_version" />    
</application>

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I've found that the GeoFencing never intelligently retrieves locations from the GPS hardware. The GeoFence API will observe the most accurate location available from the OS or if no recent location reading is available, it will cause a location to be calculated from Wifi / Cellular. (which sucks because cellular is wildly inaccurate and wifi is often unavailable)

So to get at all responsive or accurate results out of the Geofencing API you have to set up your Geofences and then poll the GPS hardware on an interval, not even doing anything with the result received, so that under the surface you are providing worthwhile data to the OS.

This is probably at the core of why your results are inaccurate. The geofence exit won't trigger until the OS is sure you're 100% outside the fence - so if a location reading has an accuracy of 500 meters (not improbable when using cell geolocation) and your fence has a radius of 50m you'd have to be at least 550m from your fence point to produce an exit event.

TLDR; Poll the GPS hardware on an interval without doing anything with the result and you'll start getting more accurate geofences.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...