【问题标题】:getGeofenceTransition() returning -1 when passing a ResultReceiver as an intent extragetGeofenceTransition() 在将 ResultReceiver 作为 Intent 额外传递时返回 -1
【发布时间】:2018-11-02 17:56:06
【问题描述】:

我对 Android 开发非常陌生,并尝试构建一个显示 GoogleMap(显示一些 GeoJSON 图层)的基本应用程序,并在进入地理围栏时提醒用户。我已将其设置为在进入/退出时发送通知,但不幸的是,将运行的设备在 Android 4.4.2 上,因此无法显示任何提示通知。我已经能够通过在 MainActivity 中创建一个闪烁的 TextView 对象来复制一个提醒通知,但我希望它在进入地理围栏时变得可见并在退出时消失。

目前我正在添加一个 ResultReceiver 作为额外的意图发送到 IntentService,然后根据转换类型将代码发送回 MainActivity。不幸的是,将 ResultReceiver 添加为额外会导致 GeofencingEvent 将所有转换类型返回为 -1。 documention for GeofencingEvent objects 表示当没有为转换警报生成事件时会发生这种情况。如果我删除 ResultReceiver 并仅发送通知,则在进入/退出地理围栏时它会正确返回值 1/2。

我希望有人有一个解决方法来传递一个 ResultReceiver,或者朝着另一种方式基于 IntentService 中的值修改 UI 的方向。

以下是主要活动中的相关部分:

public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback,
        AdapterView.OnItemSelectedListener,
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        ResultCallback<Status> {

    ...
    private GeofencingClient mGeofencingClient;
    private GoogleApiClient mGoogleApiClient;
    private ArrayList<Geofence> mGeofenceList;
    private ResultReceiver resultReceiver;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);

        // Creates map fragment and sets to GoogleMap default
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);

        // Enables location services
        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
        mGeofencingClient = LocationServices.getGeofencingClient(this);

        // Populates a list of geofences and connects to the Google Maps API Client
        mGeofenceList = new ArrayList<>();
        populateGeofenceList();
        buildGoogleApiClient();

        createNotificationChannel();

        resultReceiver = new GeofenceTransitionResultReceiver(new Handler());

        ...
    }

    // Connects to the Google Maps API Client
    protected synchronized void buildGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    }

    ...

    // Creates a list object containing geofenced points
    public void populateGeofenceList() {
        for (Map.Entry<String, LatLng> entry : LANDMARKS.entrySet()) {
            mGeofenceList.add(new Geofence.Builder()
                    .setRequestId(entry.getKey())
                    .setCircularRegion(
                            entry.getValue().latitude,
                            entry.getValue().longitude,
                            Constants.GEOFENCE_RADIUS_IN_METERS
                    )
                    .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)
                    .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
                            Geofence.GEOFENCE_TRANSITION_EXIT)
                    .build());
        }
    }

    // When the "Add Geofences" button is clicked, will activate geofences, Toast whether or not
    // the geofences were successfully added, and if they were successfully added
    // will create the (hidden) flashing TextView object
    public void addGeofencesButtonHandler(View view) {
        if (!mGoogleApiClient.isConnected()) {
            Toast.makeText(this, "Google API Client not connected!", Toast.LENGTH_SHORT).show();
            return;
        }

        try {
            mGeofencingClient.addGeofences(getGeofencingRequest(), getGeofencePendingIntent())
                    .addOnSuccessListener(this, new OnSuccessListener<Void>() {
                        @Override
                        public void onSuccess(Void aVoid) {
                            // Geofences added
                            Toast.makeText(getApplicationContext(), "Geofence Connected", Toast.LENGTH_SHORT).show();
                            manageBlinkEffect();
                        }
                    })
                    .addOnFailureListener(this, new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            // Failed to add geofences
                            Toast.makeText(getApplicationContext(), "Geofence Not Connected", Toast.LENGTH_SHORT).show();
                        }
                    });
        } catch (SecurityException securityException) {
            // Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
        }
    }

    // Builds the geofences
    private GeofencingRequest getGeofencingRequest() {
        GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
        builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
        builder.addGeofences(mGeofenceList);
        return builder.build();
    }

    // Retrieves the intent from GeofenceTransitionsIntentService and creates a PendingIntent
    private PendingIntent getGeofencePendingIntent() {
        Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
        intent.putExtra("receiver", resultReceiver);
        // 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);
    }


    private class GeofenceTransitionResultReceiver extends ResultReceiver {

        public GeofenceTransitionResultReceiver(Handler handler) {
            super(handler);
        }

        protected void onReceiveResult(int resultCode, Bundle resultData) {
            String transition = "Test String";
            switch (resultCode) {
                case GeofenceTransitionsIntentService.GEOFENCE_ERROR:
                    transition = "Error in Geofence";
                    break;

                case GeofenceTransitionsIntentService.GEOFENCE_ENTER:
                    transition = resultData.getString("enter");
                    txt.setVisibility(View.VISIBLE);
                    break;

                case GeofenceTransitionsIntentService.GEOFENCE_EXIT:
                    transition = resultData.getString("exit");
                    txt.setVisibility(View.GONE);
                    break;
            }
            txt.setVisibility(View.VISIBLE);
            Toast.makeText(getApplicationContext(), transition, Toast.LENGTH_SHORT).show();
            super.onReceiveResult(resultCode, resultData);
        }
    }
}

这里是 IntentService 的代码:

public class GeofenceTransitionsIntentService extends IntentService {
    protected static final String TAG = "GeofenceTransitionsIS";
    public static final int GEOFENCE_ENTER = 2;
    public static final int GEOFENCE_EXIT = 3;
    public static final int GEOFENCE_ERROR = 4;

    public GeofenceTransitionsIntentService() {
        super(TAG);  // use TAG to name the IntentService worker thread
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        GeofencingEvent event = GeofencingEvent.fromIntent(intent);
        if (event.hasError()) {
            Log.e(TAG, "GeofencingEvent Error: " + event.getErrorCode());
            return;
        }

        // tests the geofence transition value
        String description = String.valueOf(event.getGeofenceTransition());
        sendNotification(description);

        final ResultReceiver receiver = intent.getParcelableExtra("receiver");
        Bundle bundle = new Bundle();
        try {
            switch (event.getGeofenceTransition()) {

                case Geofence.GEOFENCE_TRANSITION_ENTER:
                    bundle.putString("enter", "Entering");
                    receiver.send(GEOFENCE_ENTER, bundle);
                    break;

                case Geofence.GEOFENCE_TRANSITION_EXIT:
                    bundle.putString("exit", "Exiting");
                    receiver.send(GEOFENCE_EXIT, bundle);
                    break;
            }
        }
        catch (Exception e) {
            receiver.send(GEOFENCE_ERROR, Bundle.EMPTY);
            e.printStackTrace();
        }
    }

    private void sendNotification(String notificationDetails) {
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext(), "test")
                .setSmallIcon(R.drawable.ic_launcher_background)
                .setContentTitle("Test Notification")
                .setContentText(notificationDetails)
                .setPriority(NotificationCompat.PRIORITY_HIGH);
        mBuilder.setLights(Color.BLUE, 500, 500);
        mBuilder.setVibrate(new long[] { 0,500 });
        Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        mBuilder.setSound(alarmSound);
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(0, mBuilder.build());
    }
}

谢谢!

【问题讨论】:

    标签: android android-geofence android-intentservice


    【解决方案1】:

    更新:我将 ResultReceiver 声明为公共静态变量,而不是 MapsActivity 中的私有变量。然后,我只是在 IntentService 中将其引用为 MapsActivity.resultReceiver,而不是尝试将其作为额外内容添加到 Intent 中。到目前为止,它似乎工作正常。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-30
      • 1970-01-01
      • 1970-01-01
      • 2018-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多