Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/181.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 当用户靠近特定位置时向其发送警报_Android_Google Maps Api 2_Android Geofence - Fatal编程技术网

Android 当用户靠近特定位置时向其发送警报

Android 当用户靠近特定位置时向其发送警报,android,google-maps-api-2,android-geofence,Android,Google Maps Api 2,Android Geofence,我正在开发一个应用程序,当用户在某个特定位置200米范围内时,它必须向用户发送通知 我的用户是汽车司机。当我在开车时使用Google GeoFenging API并对其进行测试时,有时会出现很大的延迟,因为它会在我通过靶场后向我发送通知 我考虑每3秒添加一个位置跟踪器,计算从用户当前位置到目标位置的距离,如果距离小于200米,我会发送通知 有人知道可能处理它的其他解决方案或API吗 以下是地理围栏代码 public class MapsActivity extends FragmentActiv

我正在开发一个应用程序,当用户在某个特定位置200米范围内时,它必须向用户发送通知

我的用户是汽车司机。当我在开车时使用Google GeoFenging API并对其进行测试时,有时会出现很大的延迟,因为它会在我通过靶场后向我发送通知

我考虑每3秒添加一个位置跟踪器,计算从用户当前位置到目标位置的距离,如果距离小于200米,我会发送通知

有人知道可能处理它的其他解决方案或API吗

以下是
地理围栏
代码

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        ResultCallback<Status>{   
    @BindView(R.id.tvLocation)
    MatabTextView tvLocation;
    ProgressBar progressBar;
    WaveFormView waveFormView;
    protected ArrayList<Geofence> mGeofenceList;
    protected GoogleApiClient mGoogleApiClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
        ButterKnife.bind(this);
        waveFormView = (WaveFormView) findViewById(R.id.Wave);
        waveFormView.updateAmplitude(0.05f, true);
        waveFormView.updateAmplitude(0.1f, true);
        waveFormView.updateAmplitude(0.2f, true);
        waveFormView.updateAmplitude(0.5f, true);
        StrictMode.ThreadPolicy old = StrictMode.getThreadPolicy();
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(old)
                .permitDiskWrites()
                .build());

        StrictMode.setThreadPolicy(old);
        progressBar = (ProgressBar) findViewById(R.id.progress);
        progressBar.setVisibility(View.VISIBLE);

        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);

        mGeofenceList = new ArrayList<Geofence>();
        populateGeofenceList();
        buildGoogleApiClient();
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (!mGoogleApiClient.isConnecting() || !mGoogleApiClient.isConnected()) {
            mGoogleApiClient.connect();
        }
    }

    public void addGeofencesButtonHandler(View view) {
        if (!mGoogleApiClient.isConnected()) {
            Toast.makeText(this, "Google API Client not connected!", Toast.LENGTH_SHORT).show();
            return;
        }

        try {
            LocationServices.GeofencingApi.addGeofences(
                    mGoogleApiClient,
                    getGeofencingRequest(),
                    getGeofencePendingIntent()
            ).setResultCallback(this); // Result processed in onResult().
        } catch (SecurityException securityException) {
            // Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
        }

    }

    private GeofencingRequest getGeofencingRequest() {
        GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
        builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER | GeofencingRequest.INITIAL_TRIGGER_EXIT);
        builder.addGeofences(mGeofenceList);
        return builder.build();
    }

    private PendingIntent getGeofencePendingIntent() {
        Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
        // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling addgeoFences()
        return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }

    public void onResult(Status status) {
        if (status.isSuccess()) {
            Toast.makeText(
                    this,
                    "Geofences Added",
                    Toast.LENGTH_SHORT
            ).show();
        } else {
                  String errorMessage = GeofenceErrorMessages.getErrorString(this,
                  status.getStatusCode());
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mGoogleApiClient.isConnecting() || mGoogleApiClient.isConnected()) {
            mGoogleApiClient.disconnect();
        }
    }

    @Override
    public void onConnected(Bundle connectionHint) {

    }

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        // Do something with result.getErrorCode());
        Log.d("Geofencing", String.valueOf(result.getErrorCode()));
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {

    }

    @Override
    public void onConnectionSuspended(int cause) {
        mGoogleApiClient.connect();
    }

    protected synchronized void buildGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    }

    public void populateGeofenceList() {

        FirebaseDatabase database = FirebaseDatabase.getInstance();
        DatabaseReference myRef = database.getReference("roads").child("Name").child("locations");
        myRef.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                progressBar.setVisibility(View.GONE);
                mGeofenceList.add(new Geofence.Builder()
                        .setRequestId(dataSnapshot.getKey())
                        .setCircularRegion(
                                (Double) dataSnapshot.child("lat").getValue(),
                                (Double) dataSnapshot.child("lang").getValue(),
                                Constants.GEOFENCE_RADIUS_IN_METERS
                        )
                        .setExpirationDuration(Geofence.NEVER_EXPIRE)
                        .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER
                        )
                        .build());
            }

            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {

            }

            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {

            }

            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {

            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        });

        for (Map.Entry<String, LatLng> entry : Constants.LANDMARKS.entrySet()) {

        }
    }

}

首先,除非你愿意向谷歌支付使用API的费用,否则我强烈建议你改用OSMDroid库进行开发

如果你想要线性距离(半径),而不是多边形位置检测,那么地理围栏是一种过火的技术,这将使你在电池使用和设备温度方面付出巨大代价

确定从目标位置到所需位置的线性距离很容易。您可以使用此代码,例如:

public double distanceGeoPoints (GeoPoint geoPoint01, GeoPoint geoPoint02) {
    double lat1 = geoPoint01.getLatitudeE6()/1E6;
    double lng1 = geoPoint01.getLongitudeE6()/1E6;
    double lat2 = geoPoint02.getLatitudeE6()/1E6;
    double lng2 = geoPoint02.getLongitudeE6()/1E6;
    double earthRadius = 3958.75;
    double dLat = Math.toRadians(lat2-lat1);
    double dLng = Math.toRadians(lng2-lng1);
    double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
               Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
               Math.sin(dLng/2) * Math.sin(dLng/2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    double dist = earthRadius * c;

    int meterConversion = 1609;
    double geopointDistance = dist * meterConversion;

    return geopointDistance;
}
这是哈弗森公式,被普遍认为“对于大多数意图和目的来说足够精确”。你必须明白,地球并不是一个完美的球体,它更像是一个棒球,在大帕皮反复使用它进行击球练习之后


从我在你的应用程序中看到的情况来看,这应该会给你必要的精确度。但如果你好奇,可以这样做。

尝试Firebase数据库进行实时回调,并在应用程序中按需生成通知。你读过android文档中的部分吗?这确实是一个完美的答案,当我提出一个问题时,我实现了使用方法Location1.distanceTo(location2)获取两个位置之间的距离;它工作得很好,但我想知道哪一个在获得精确的距离(半径)方面更好?我刚才做了什么或者你推荐的方法?我不知道API是如何计算地质点之间的距离的,但我想谷歌的API至少会给你同样的精度,如果不是更高的话。但我要强调的是,在不与客户讨论成本的情况下,我建议不要使用谷歌的MappingAPI。他们对专业应用程序的收费非常严格。你所做的直接与他们的摇钱树竞争:广告(他们向企业出售广告,以吸引路人成为当地潜在客户)。非常感谢你的回答,我会尝试你的方法,看看结果,并尝试放弃谷歌地图如果你需要任何关于OSMDroid的东西,不要害羞。我有大量的代码可以使用。我编写跟踪应用程序,移动与基于Web的集成(我在两者上都使用OSM——是的,GoogleAPI更容易,但它们是专有的,代码会被弃用,这意味着你可能需要在未来几年内维护你的软件),如果你想进行地理编码和反向地理编码(从坐标和viceversa获取地址)一定要考虑名列前茅。我已经用了好几年了。你甚至可以下载和缓存完整的数据库(顺便说一句,他们推荐的数据库),很多很多Gig。
public double distanceGeoPoints (GeoPoint geoPoint01, GeoPoint geoPoint02) {
    double lat1 = geoPoint01.getLatitudeE6()/1E6;
    double lng1 = geoPoint01.getLongitudeE6()/1E6;
    double lat2 = geoPoint02.getLatitudeE6()/1E6;
    double lng2 = geoPoint02.getLongitudeE6()/1E6;
    double earthRadius = 3958.75;
    double dLat = Math.toRadians(lat2-lat1);
    double dLng = Math.toRadians(lng2-lng1);
    double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
               Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
               Math.sin(dLng/2) * Math.sin(dLng/2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    double dist = earthRadius * c;

    int meterConversion = 1609;
    double geopointDistance = dist * meterConversion;

    return geopointDistance;
}