当你距离标记 10 米以内时如何开始一些方法?
how to start some method when you come within 10 meters to the marker?
我需要制作带有地图和一些标记的 android 应用程序。当我距离标记 10 米以内时,它变为可点击,点击播放音轨,然后更改标记图标并显示另一个标记。
我尝试使用地理围栏,但我无法更改图标或从 BroadcastReciever 或其他 activity 或服务调用 MediaPlayer。
标记 - 地理围栏中心。
问题:
当地理围栏触发时,如何更改标记的图标并启动音轨?
在 MapsActivity 中添加地理围栏
private void createGeofences(){
if (Build.VERSION.SDK_INT >= 29) {
//We need background permission
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {
for (int i=0; i < ARRAY_SIZE; i++){
addGeofence(latLngArray[i], GEOFENCE_RADIUS, Integer.toString(i));
}
}
} else {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION)) {
//We show a dialog and ask for permission
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_BACKGROUND_LOCATION}, BACKGROUND_LOCATION_ACCESS_REQUEST_CODE);
} else {
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_BACKGROUND_LOCATION}, BACKGROUND_LOCATION_ACCESS_REQUEST_CODE);
}
}
}
private void addGeofence(LatLng latLng, float radius, String id){
Geofence geofence = GeofenceHelper.getGeofence(id, latLng, radius, Geofence.GEOFENCE_TRANSITION_ENTER);
GeofencingRequest geofencingRequest = geofenceHelper.getGeofencingRequest(geofence);
PendingIntent pendingIntent = geofenceHelper.getPendingIntent();
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
geofencingClient.addGeofences(geofencingRequest, pendingIntent)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "onSuccess: Geofence Added...");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
String errorMessage = GeofenceHelper.getErrorString(e);
Log.d(TAG, "onFailure: " + errorMessage);
}
});
}
}
GeofenceHelper.class
public class GeofenceHelper extends ContextWrapper {
private static final int loiteringDelay = 0;
private static final String TAG = "GeofenceHelper";
PendingIntent pendingIntent;
public GeofenceHelper(Context base) {
super(base);
}
public GeofencingRequest getGeofencingRequest(Geofence geofence){
return new GeofencingRequest.Builder()
.addGeofence(geofence)
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.build();
}
public static Geofence getGeofence(String ID, LatLng latLng, float radius, int transitionTypes){
return new Geofence.Builder()
.setCircularRegion(latLng.latitude, latLng.longitude, radius)
.setRequestId(ID)
.setTransitionTypes(transitionTypes)
.setLoiteringDelay(loiteringDelay)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build();
}
public PendingIntent getPendingIntent(){
if(pendingIntent != null){
return pendingIntent;
}
Intent intent = new Intent(this, GeofenceBroadcastReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 956, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
public static String getErrorString(Exception e) {
if (e instanceof ApiException) {
ApiException apiException = (ApiException) e;
switch (apiException.getStatusCode()) {
case GeofenceStatusCodes
.GEOFENCE_NOT_AVAILABLE:
return "GEOFENCE_NOT_AVAILABLE";
case GeofenceStatusCodes
.GEOFENCE_TOO_MANY_GEOFENCES:
return "GEOFENCE_TOO_MANY_GEOFENCES";
case GeofenceStatusCodes
.GEOFENCE_TOO_MANY_PENDING_INTENTS:
return "GEOFENCE_TOO_MANY_PENDING_INTENTS";
}
}
return e.getLocalizedMessage();
}
}
GeofenceBroadcastReciever.class
public class GeofenceBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "GeofenceBroadcastReceiv";
//MediaPlayer mediaPlayer;
@Override
public void onReceive(Context context, Intent intent) {
// an Intent broadcast.
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
Log.d(TAG, "onReceive: Error receiving geofence event...");
return;
};
List<Geofence> geofenceList = geofencingEvent.getTriggeringGeofences();
String id = geofenceList.get(0).getRequestId();
switch (id){
case "0":
Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
case "1":
Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
case "2":
Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
case "3":
Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
case "4":
Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
case "5":
Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
}
}
}
MediaPlayer need context
Well you can pass a context to the broadcast receiver. I assume (because you have not shown it) that you register your broadcast receiver in an Activity or App which are contexts.
Multiple solutions:
- 您的广播接收器可以是您的 activity 的内部 class 或匿名 class,在这两种情况下,广播接收器都会引用包装 class (
MapsActivity.this
).
- 将上下文作为构造函数参数传递给您的广播接收器。当您希望它成为 top-class 并在多个地方重复使用时很有用。
- 在广播接收器的构造函数中传递一个回调(一些FunctionalInterface,f.e。
Consumer<Integer> onCheckpointReached
)。
按照动态访问特定轨道,你不应该使用这样的开关,而是动态获取资源,确切的解决方案(声音均匀!)在这里:
旁注:您的 switch (apiException.getStatusCode()) {
没有多大意义,只需使用 apiException.getStatusCode().name()
或 apiException.getStatusCode().toString()
。
我需要制作带有地图和一些标记的 android 应用程序。当我距离标记 10 米以内时,它变为可点击,点击播放音轨,然后更改标记图标并显示另一个标记。 我尝试使用地理围栏,但我无法更改图标或从 BroadcastReciever 或其他 activity 或服务调用 MediaPlayer。
标记 - 地理围栏中心。
问题:
当地理围栏触发时,如何更改标记的图标并启动音轨?
在 MapsActivity 中添加地理围栏
private void createGeofences(){
if (Build.VERSION.SDK_INT >= 29) {
//We need background permission
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {
for (int i=0; i < ARRAY_SIZE; i++){
addGeofence(latLngArray[i], GEOFENCE_RADIUS, Integer.toString(i));
}
}
} else {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION)) {
//We show a dialog and ask for permission
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_BACKGROUND_LOCATION}, BACKGROUND_LOCATION_ACCESS_REQUEST_CODE);
} else {
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_BACKGROUND_LOCATION}, BACKGROUND_LOCATION_ACCESS_REQUEST_CODE);
}
}
}
private void addGeofence(LatLng latLng, float radius, String id){
Geofence geofence = GeofenceHelper.getGeofence(id, latLng, radius, Geofence.GEOFENCE_TRANSITION_ENTER);
GeofencingRequest geofencingRequest = geofenceHelper.getGeofencingRequest(geofence);
PendingIntent pendingIntent = geofenceHelper.getPendingIntent();
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
geofencingClient.addGeofences(geofencingRequest, pendingIntent)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "onSuccess: Geofence Added...");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
String errorMessage = GeofenceHelper.getErrorString(e);
Log.d(TAG, "onFailure: " + errorMessage);
}
});
}
}
GeofenceHelper.class
public class GeofenceHelper extends ContextWrapper {
private static final int loiteringDelay = 0;
private static final String TAG = "GeofenceHelper";
PendingIntent pendingIntent;
public GeofenceHelper(Context base) {
super(base);
}
public GeofencingRequest getGeofencingRequest(Geofence geofence){
return new GeofencingRequest.Builder()
.addGeofence(geofence)
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.build();
}
public static Geofence getGeofence(String ID, LatLng latLng, float radius, int transitionTypes){
return new Geofence.Builder()
.setCircularRegion(latLng.latitude, latLng.longitude, radius)
.setRequestId(ID)
.setTransitionTypes(transitionTypes)
.setLoiteringDelay(loiteringDelay)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build();
}
public PendingIntent getPendingIntent(){
if(pendingIntent != null){
return pendingIntent;
}
Intent intent = new Intent(this, GeofenceBroadcastReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 956, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
public static String getErrorString(Exception e) {
if (e instanceof ApiException) {
ApiException apiException = (ApiException) e;
switch (apiException.getStatusCode()) {
case GeofenceStatusCodes
.GEOFENCE_NOT_AVAILABLE:
return "GEOFENCE_NOT_AVAILABLE";
case GeofenceStatusCodes
.GEOFENCE_TOO_MANY_GEOFENCES:
return "GEOFENCE_TOO_MANY_GEOFENCES";
case GeofenceStatusCodes
.GEOFENCE_TOO_MANY_PENDING_INTENTS:
return "GEOFENCE_TOO_MANY_PENDING_INTENTS";
}
}
return e.getLocalizedMessage();
}
}
GeofenceBroadcastReciever.class
public class GeofenceBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "GeofenceBroadcastReceiv";
//MediaPlayer mediaPlayer;
@Override
public void onReceive(Context context, Intent intent) {
// an Intent broadcast.
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
Log.d(TAG, "onReceive: Error receiving geofence event...");
return;
};
List<Geofence> geofenceList = geofencingEvent.getTriggeringGeofences();
String id = geofenceList.get(0).getRequestId();
switch (id){
case "0":
Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
case "1":
Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
case "2":
Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
case "3":
Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
case "4":
Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
case "5":
Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
}
}
}
MediaPlayer need context Well you can pass a context to the broadcast receiver. I assume (because you have not shown it) that you register your broadcast receiver in an Activity or App which are contexts. Multiple solutions:
- 您的广播接收器可以是您的 activity 的内部 class 或匿名 class,在这两种情况下,广播接收器都会引用包装 class (
MapsActivity.this
). - 将上下文作为构造函数参数传递给您的广播接收器。当您希望它成为 top-class 并在多个地方重复使用时很有用。
- 在广播接收器的构造函数中传递一个回调(一些FunctionalInterface,f.e。
Consumer<Integer> onCheckpointReached
)。
按照动态访问特定轨道,你不应该使用这样的开关,而是动态获取资源,确切的解决方案(声音均匀!)在这里:
旁注:您的 switch (apiException.getStatusCode()) {
没有多大意义,只需使用 apiException.getStatusCode().name()
或 apiException.getStatusCode().toString()
。