英文:
how to start some method when you come within 10 meters to the marker?
问题
我需要制作一个带有地图和一些标记的安卓应用。当我靠近标记时,距离标记不到10米时,它会变得可点击,点击后会播放音轨,然后更改标记图标并显示另一个标记。
我尝试使用地理围栏,但是我无法在BroadcastReciever或其他活动或服务中更改图标或调用MediaPlayer。
标记 - 地理围栏的中心。
问题:
当地理围栏触发时,如何更改标记的图标并开始音轨?
在MapsActivity中添加地理围栏
private void createGeofences(){
if (Build.VERSION.SDK_INT >= 29) {
// 需要后台权限
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)) {
// 显示对话框并请求权限
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: 地理围栏已添加...");
}
})
.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();
}
}
GeofenceBroadcastReceiver.class
public class GeofenceBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "GeofenceBroadcastReceiv";
@Override
public void onReceive(Context context, Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
Log.d(TAG, "onReceive: 接收地理围栏事件时出错...");
return;
}
List<Geofence> geofenceList = geofencingEvent.getTriggeringGeofences();
String id = geofenceList.get(0).getRequestId();
switch (id){
case "0":
Toast.makeText(context, "地理围栏 " + id + " 触发。", Toast.LENGTH_SHORT).show();
case "1":
Toast.makeText(context, "地理围栏 " + id + " 触发。", Toast.LENGTH_SHORT).show();
case "2":
Toast.makeText(context, "地理围栏 " + id + " 触发。", Toast.LENGTH_SHORT).show();
case "3":
Toast.makeText(context, "地理围栏 " + id + " 触发。", Toast.LENGTH_SHORT).show();
case "4":
Toast.makeText(context, "地理围栏 " + id + " 触发。", Toast.LENGTH_SHORT).show();
case "5":
Toast.makeText(context, "地理围栏 " + id + " 触发。", Toast.LENGTH_SHORT).show();
}
}
}
英文:
I need to make android app with map and some markers. When i'm come within 10 meters to the marker, it becomes clickable, and on click plays audiotrack, then changes marker icon and shows another marker.
I tried to use geofences, but i can't change icon or call MediaPlayer from BroadcastReciever or from other activity or service.
marker - center of geofence.
The Question:
How can I change marker's icon and start audiotrack, when geofence triggers?
adding geofences in 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();
}
}
}
答案1
得分: 0
> MediaPlayer 需要上下文
好的,你可以将上下文传递给广播接收器。我假设(因为你没有展示出来)你在活动或应用中注册了广播接收器,而这些都是上下文。
多种解决方案:
- 你的广播接收器可以是活动的内部类或匿名类,在这两种情况下,广播接收器会有一个对包装类的引用(
MapsActivity.this
)。 - 将上下文作为构造函数参数传递给广播接收器。当你希望它是一个顶层类并且在多个地方重用时,这个方法很有用。
- 在广播接收器的构造函数中传递一个回调(某个 FunctionalInterface,例如
Consumer<Integer> onCheckpointReached
)。
关于动态访问特定轨道,你不应该使用 switch,而是要动态获取资源,甚至可以在这里找到确切的解决方案(包括声音!):https://stackoverflow.com/a/7182576/9274948
顺便提一下:你的 switch (apiException.getStatusCode()) {
没有太多意义,直接使用 apiException.getStatusCode().name()
或 apiException.getStatusCode().toString()
即可。
英文:
> 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:
- Your broadcast receiver can be an inner class of your activity or an anonymous class, in both cases the broadcast receiver would have a reference to the wrapping class (
MapsActivity.this
). - Pass the Context as a constructor parameter to your broadcast receiver. Useful when you want it to be a top-class and reuse it on multiple places.
- Pass a callback (some FunctionalInterface, f.e.
Consumer<Integer> onCheckpointReached
) in the constructor of the broadcast receiver.
As per accessing the specific track dynamically, you should not use such a switch but get a resource dynamically, the exact solution (with sounds even!) is here: https://stackoverflow.com/a/7182576/9274948
Side note: your switch (apiException.getStatusCode()) {
does not make much sense, just use apiException.getStatusCode().name()
or apiException.getStatusCode().toString()
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论