Adroid - Я получаю местоположение только в режиме экономии заряда батареи GPS (и почему я получаю его дважды?) - PullRequest
0 голосов
/ 15 октября 2018

Я хочу, чтобы мое приложение при получении данных с устройства Bluetooth LE добавляло дату и время и префикс местоположения к входящим данным.Что действительно странно, так это то, что местоположение рассчитывается только в том случае, если я использую опцию GPS для экономии заряда батареи (которая рассчитывается только по WiFi и сетевому сигналу).Если я использую только GPS или параметр высокой точности (GPS и сеть), он не показывает местоположение.

В файле манифеста я использую разрешение:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
<uses-feature android:name="android.hardware.location.gps" />
<uses-feature android:name="android.hardware.location.network" />

Более тогоВ этом режиме экономии заряда батареи всегда также печатаются широта и долгота по неизвестной причине после сообщения Bluetooth (что я не подразумевал)!Если кто-то также может помочь мне понять, почему это происходит, я был бы признателен.

Соответствующий код следующий:

public class Chat extends Activity {
private final static String TAG = Chat.class.getSimpleName();

public static final String EXTRAS_DEVICE = "EXTRAS_DEVICE";
private TextView tv = null;
private EditText et = null;
private Button btn = null;
private String mDeviceName;
private String mDeviceAddress;
private RBLService mBluetoothLeService;
private Map<UUID, BluetoothGattCharacteristic> map = new HashMap<UUID, BluetoothGattCharacteristic>();
private FusedLocationProviderClient mFusedLocationClient;

private final ServiceConnection mServiceConnection = new ServiceConnection() {

    @Override
    public void onServiceConnected(ComponentName componentName,
            IBinder service) {
        mBluetoothLeService = ((RBLService.LocalBinder) service)
                .getService();
        if (!mBluetoothLeService.initialize()) {
            Log.e(TAG, "Unable to initialize Bluetooth");
            finish();
        }
        // Automatically connects to the device upon successful start-up
        // initialization.
        mBluetoothLeService.connect(mDeviceAddress);
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        mBluetoothLeService = null;
    }
};

private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();

        if (RBLService.ACTION_GATT_DISCONNECTED.equals(action)) {
        } else if (RBLService.ACTION_GATT_SERVICES_DISCOVERED
                .equals(action)) {
            getGattService(mBluetoothLeService.getSupportedGattService());
        } else if (RBLService.ACTION_DATA_AVAILABLE.equals(action)) {
            displayData(intent.getByteArrayExtra(RBLService.EXTRA_DATA));
        }
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.second);
    mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

    tv = (TextView) findViewById(R.id.textView);
    tv.setMovementMethod(ScrollingMovementMethod.getInstance());
    et = (EditText) findViewById(R.id.editText);
    btn = (Button) findViewById(R.id.send);
    btn.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            BluetoothGattCharacteristic characteristic = map
                    .get(RBLService.UUID_BLE_SHIELD_TX);

            String str = et.getText().toString();
            byte b = 0x00;
            byte[] tmp = str.getBytes();
            byte[] tx = new byte[tmp.length + 1];
            tx[0] = b;
            for (int i = 1; i < tmp.length + 1; i++) {
                tx[i] = tmp[i - 1];
            }

            characteristic.setValue(tx);
            mBluetoothLeService.writeCharacteristic(characteristic);

            et.setText("");
        }
    });

    Intent intent = getIntent();

    mDeviceAddress = intent.getStringExtra(Device.EXTRA_DEVICE_ADDRESS);
    mDeviceName = intent.getStringExtra(Device.EXTRA_DEVICE_NAME);

    getActionBar().setTitle(mDeviceName);
    getActionBar().setDisplayHomeAsUpEnabled(true);

    Intent gattServiceIntent = new Intent(this, RBLService.class);
    bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);

    AlertDialog.Builder builder1 = new AlertDialog.Builder(this);
    builder1.setMessage("Παρακαλώ ενεργοποιήστε το gps σε υψηλή ακρίβεια για καταγραφή της τοποθεσίας των μετρήσεων.");
    builder1.setCancelable(true);

    builder1.setPositiveButton(
            "Οκ, έγινε",
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    dialog.cancel();
                }
            });

    AlertDialog alert11 = builder1.create();
    alert11.show();

}


@Override
protected void onResume() {
    super.onResume();

    registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == android.R.id.home) {
        mBluetoothLeService.disconnect();
        mBluetoothLeService.close();

        System.exit(0);
    }

    return super.onOptionsItemSelected(item);
}

@Override
protected void onStop() {
    super.onStop();

    unregisterReceiver(mGattUpdateReceiver);
}

@Override
protected void onDestroy() {
    super.onDestroy();

    mBluetoothLeService.disconnect();
    mBluetoothLeService.close();

    System.exit(0);
}

private void displayData(byte[] byteArray) {
    if (byteArray != null) {
        getLocation();
        getDate();
        tv.append("\n");
        String data = new String(byteArray);
        tv.append(data);
        tv.append("\n");
        // find the amount we need to scroll. This works by
        // asking the TextView's internal layout for the position
        // of the final line and then subtracting the TextView's height
        final int scrollAmount = tv.getLayout().getLineTop(
                tv.getLineCount())
                - tv.getHeight();
        // if there is no need to scroll, scrollAmount will be <=0
        if (scrollAmount > 0)
            tv.scrollTo(0, scrollAmount);
        else
            tv.scrollTo(0, 0);
    }
}

private void getDate() {
    Calendar c = Calendar.getInstance();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd-HH:mm:ss");
    String strDate = sdf.format(c.getTime());
    tv.append(strDate);
}

private void getLocation() {
    try {

        mFusedLocationClient.getLastLocation()
                .addOnSuccessListener(this, new OnSuccessListener<Location>() {
                    @Override
                    public void onSuccess(Location location) {
                        // Got last known location. In some rare situations this can be null.
                        if (location != null) {
                            double lat = location.getLatitude();
                            double lng = location.getLongitude();
                            String latitude = String.valueOf(lat);
                            String longitude = String.valueOf(lng);
                            tv.append(latitude);
                            tv.append(",");
                            tv.append(longitude);
                            tv.append("/");
                        }
                    }
                });

    } catch (SecurityException e) {
        // lets the user know there is a problem with the gps
    }
}

private void getGattService(BluetoothGattService gattService) {
    if (gattService == null)
        return;

    BluetoothGattCharacteristic characteristic = gattService
            .getCharacteristic(RBLService.UUID_BLE_SHIELD_TX);
    map.put(characteristic.getUuid(), characteristic);

    BluetoothGattCharacteristic characteristicRx = gattService
            .getCharacteristic(RBLService.UUID_BLE_SHIELD_RX);
    mBluetoothLeService.setCharacteristicNotification(characteristicRx,
            true);
    mBluetoothLeService.readCharacteristic(characteristicRx);
    }

private static IntentFilter makeGattUpdateIntentFilter() {
    final IntentFilter intentFilter = new IntentFilter();

    intentFilter.addAction(RBLService.ACTION_GATT_CONNECTED);
    intentFilter.addAction(RBLService.ACTION_GATT_DISCONNECTED);
    intentFilter.addAction(RBLService.ACTION_GATT_SERVICES_DISCOVERED);
    intentFilter.addAction(RBLService.ACTION_DATA_AVAILABLE);

    return intentFilter;
    }
}

, а RBLservice.java:

/**
* Service for managing connection and data communication with a GATT server
* hosted on a given Bluetooth LE device.
*/
public class RBLService extends Service {
private final static String TAG = RBLService.class.getSimpleName();
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;

public final static String ACTION_GATT_CONNECTED = "ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED = "ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED = "ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_GATT_RSSI = "ACTION_GATT_RSSI";
public final static String ACTION_DATA_AVAILABLE = "ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA = "EXTRA_DATA";

public final static UUID UUID_BLE_SHIELD_TX = UUID
        .fromString(RBLGattAttributes.BLE_SHIELD_TX);
public final static UUID UUID_BLE_SHIELD_RX = UUID
        .fromString(RBLGattAttributes.BLE_SHIELD_RX);
public final static UUID UUID_BLE_SHIELD_SERVICE = UUID
        .fromString(RBLGattAttributes.BLE_SHIELD_SERVICE);

private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status,
                                        int newState) {
        String intentAction;

        if (newState == BluetoothProfile.STATE_CONNECTED) {
            intentAction = ACTION_GATT_CONNECTED;
            broadcastUpdate(intentAction);
            Log.i(TAG, "Connected to GATT server.");
            // Attempts to discover services after successful connection.
            Log.i(TAG, "Attempting to start service discovery:"
                    + mBluetoothGatt.discoverServices());
        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
            intentAction = ACTION_GATT_DISCONNECTED;
            Log.i(TAG, "Disconnected from GATT server.");
            broadcastUpdate(intentAction);
        }
    }

    public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            broadcastUpdate(ACTION_GATT_RSSI, rssi);
        } else {
            Log.w(TAG, "onReadRemoteRssi received: " + status);
        }
    }

    ;

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
        } else {
            Log.w(TAG, "onServicesDiscovered received: " + status);
        }
    }

    @Override
    public void onCharacteristicRead(BluetoothGatt gatt,
                                     BluetoothGattCharacteristic characteristic, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
        }
    }

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt,
                                        BluetoothGattCharacteristic characteristic) {
        broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
    }
};

private void broadcastUpdate(final String action) {
    final Intent intent = new Intent(action);
    sendBroadcast(intent);
}

private void broadcastUpdate(final String action, int rssi) {
    final Intent intent = new Intent(action);
    intent.putExtra(EXTRA_DATA, String.valueOf(rssi));
    sendBroadcast(intent);
}

private void broadcastUpdate(final String action,
                             final BluetoothGattCharacteristic characteristic) {
    final Intent intent = new Intent(action);

    // This is special handling for the Heart Rate Measurement profile. Data
    // parsing is
    // carried out as per profile specifications:
    // http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
    if (UUID_BLE_SHIELD_RX.equals(characteristic.getUuid())) {
        final byte[] rx = characteristic.getValue();
        intent.putExtra(EXTRA_DATA, rx);
    }

    sendBroadcast(intent);
}

public class LocalBinder extends Binder {
    RBLService getService() {
        return RBLService.this;
    }
}

@Override
public IBinder onBind(Intent intent) {
    return mBinder;
}

@Override
public boolean onUnbind(Intent intent) {
    // After using a given device, you should make sure that
    // BluetoothGatt.close() is called
    // such that resources are cleaned up properly. In this particular
    // example, close() is
    // invoked when the UI is disconnected from the Service.
    close();
    return super.onUnbind(intent);
}

private final IBinder mBinder = new LocalBinder();

/**
 * Initializes a reference to the local Bluetooth adapter.
 *
 * @return Return true if the initialization is successful.
 */
public boolean initialize() {
    // For API level 18 and above, get a reference to BluetoothAdapter
    // through
    // BluetoothManager.
    if (mBluetoothManager == null) {
        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        if (mBluetoothManager == null) {
            Log.e(TAG, "Unable to initialize BluetoothManager.");
            return false;
        }
    }

    mBluetoothAdapter = mBluetoothManager.getAdapter();
    if (mBluetoothAdapter == null) {
        Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
        return false;
    }

    return true;
}

/**
 * Connects to the GATT server hosted on the Bluetooth LE device.
 *
 * @param address The device address of the destination device.
 * @return Return true if the connection is initiated successfully. The
 * connection result is reported asynchronously through the
 * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
 * callback.
 */
public boolean connect(final String address) {
    if (mBluetoothAdapter == null || address == null) {
        Log.w(TAG,
                "BluetoothAdapter not initialized or unspecified address.");
        return false;
    }

    // Previously connected device. Try to reconnect.
    if (mBluetoothDeviceAddress != null
            && address.equals(mBluetoothDeviceAddress)
            && mBluetoothGatt != null) {
        Log.d(TAG,
                "Trying to use an existing mBluetoothGatt for connection.");
        if (mBluetoothGatt.connect()) {
            return true;
        } else {
            return false;
        }
    }

    final BluetoothDevice device = mBluetoothAdapter
            .getRemoteDevice(address);
    if (device == null) {
        Log.w(TAG, "Device not found.  Unable to connect.");
        return false;
    }
    // We want to directly connect to the device, so we are setting the
    // autoConnect
    // parameter to false.
    mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
    Log.d(TAG, "Trying to create a new connection.");
    mBluetoothDeviceAddress = address;

    return true;
}

/**
 * Disconnects an existing connection or cancel a pending connection. The
 * disconnection result is reported asynchronously through the
 * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
 * callback.
 */
public void disconnect() {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        Log.w(TAG, "BluetoothAdapter not initialized");
        return;
    }
    mBluetoothGatt.disconnect();
}

/**
 * After using a given BLE device, the app must call this method to ensure
 * resources are released properly.
 */
public void close() {
    if (mBluetoothGatt == null) {
        return;
    }
    mBluetoothGatt.close();
    mBluetoothGatt = null;
}

/**
 * Request a read on a given {@code BluetoothGattCharacteristic}. The read
 * result is reported asynchronously through the
 * {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
 * callback.
 *
 * @param characteristic The characteristic to read from.
 */
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        Log.w(TAG, "BluetoothAdapter not initialized");
        return;
    }

    mBluetoothGatt.readCharacteristic(characteristic);
}

public void readRssi() {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        Log.w(TAG, "BluetoothAdapter not initialized");
        return;
    }

    mBluetoothGatt.readRemoteRssi();
}

public void writeCharacteristic(BluetoothGattCharacteristic characteristic) {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        Log.w(TAG, "BluetoothAdapter not initialized");
        return;
    }

    mBluetoothGatt.writeCharacteristic(characteristic);
}

/**
 * Enables or disables notification on a give characteristic.
 *
 * @param characteristic Characteristic to act on.
 * @param enabled        If true, enable notification. False otherwise.
 */
public void setCharacteristicNotification(
        BluetoothGattCharacteristic characteristic, boolean enabled) {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        Log.w(TAG, "BluetoothAdapter not initialized");
        return;
    }
    mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);

    if (UUID_BLE_SHIELD_RX.equals(characteristic.getUuid())) {
        BluetoothGattDescriptor descriptor = characteristic
                .getDescriptor(UUID
                        .fromString(RBLGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
        descriptor
                .setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        mBluetoothGatt.writeDescriptor(descriptor);
    }
}

/**
 * Retrieves a list of supported GATT services on the connected device. This
 * should be invoked only after {@code BluetoothGatt#discoverServices()}
 * completes successfully.
 *
 * @return A {@code List} of supported services.
 */
public BluetoothGattService getSupportedGattService() {
    if (mBluetoothGatt == null)
        return null;

    return mBluetoothGatt.getService(UUID_BLE_SHIELD_SERVICE);
}

}


обновленный вопрос следует здесь:

С помощью (высоко ценимого) помощи greeble31 и следующего кода мне удалось взять последнее известное местоположение только один раз, как я хотел, когда вызывается displayData.Теперь я хочу взять текущее местоположение (я думаю, с помощью requestLocationUpdate), но не запускать действие каждый раз, когда местоположение меняется.Как я могу обновить в течение нескольких секунд, чтобы получить правильное исправление GPS и после получения широты и долготы, остановить обновление местоположения, чтобы сохранить батарею, пока не поступит следующий вызов displayData?

Вот часть кодаэто работает сейчас, и мне нужно изменить, но я не могу понять, какой слушатель поставить, и я всегда получаю ошибки, поэтому, пожалуйста, помогите мне:

private void displayData(final byte[] byteArray) {
    try {

        mFusedLocationClient.getLastLocation()
                .addOnSuccessListener(this, new OnSuccessListener<Location>() {
                    @Override
                    public void onSuccess(Location location) {
                        // Got last known location. In some rare situations this can be null.

                        if (byteArray != null) {
                            String data = new String(byteArray);
                            tv.setText(n/2 + " measurements since startup...");
                            n += 1;

                            if (location != null) {
                                double lat = location.getLatitude();
                                double lng = location.getLongitude();
                                latitude = String.valueOf(lat);
                                longitude = String.valueOf(lng);
                            }

                            try
                            {
                                FileWriter fw = new FileWriter(textfile,true); //the true will append the new data
                                if (writeDate()) {
                                    fw.write("\n");
                                    fw.write(stringDate);
                                    fw.write(data); //appends the string to the file
                                }
                                else {
                                    fw.write(data); //appends the string to the file
                                    fw.write(" - ");
                                    fw.write(latitude);
                                    fw.write(",");
                                    fw.write(longitude);
                                }
                                fw.close();
                            }
                            catch(IOException ioe)
                            {
                                System.err.println("IOException: " + ioe.getMessage());
                            }


                            // find the amount we need to scroll. This works by
                            // asking the TextView's internal layout for the position
                            // of the final line and then subtracting the TextView's height
                            final int scrollAmount = tv.getLayout().getLineTop(
                                    tv.getLineCount())
                                    - tv.getHeight();
                            // if there is no need to scroll, scrollAmount will be <=0
                            if (scrollAmount > 0)
                                tv.scrollTo(0, scrollAmount);
                            else
                                tv.scrollTo(0, 0);
                        }
                    }
                });

    } catch (SecurityException e) {
        // lets the user know there is a problem with the gps
    }
}

1 Ответ

0 голосов
/ 16 октября 2018

Итак, пара вещей здесь:

  1. Простой запрос разрешения ACCESS_FINE_LOCATION не гарантирует, что FusedLocationProvider использует GPS.Поскольку вы звоните только по номеру getLastLocation(), он даст вам последнее исправление местоположения, как бы давно это ни было.Это действие само по себе не включает GPS или что-то еще.Даже если это произойдет, GPS может прогреться несколько секунд, прежде чем он получит исправление.Я не уверен, как долго он кэширует последнее исправление GPS или почему он не дает вам хотя бы сетевое исправление, когда у вас есть ACCESS_FINE_LOCATION.Вы пробовали это с ACCESS_FINE_LOCATION и ACCESS_COARSE_LOCATION?
  2. Обратите внимание, что getLastLocation() возвращает Task.Это признак того, что операция является асинхронной.Другими словами, onSuccess() фактически выполняет после getLocation(), и на самом деле displayData(), уже вернули на практике.Зачем?Потому что getLastLocation() должен получить ответ от службы Google Play (в которой находится FusedLocationProvider) через IPC .Это занимает время, хотя и всего несколько мс.Таким образом, вместо блокировки до тех пор, пока он не получит ответ, он дает вам Task и обещает позвонить onSuccess() в будущем.Вот почему ваш лат / лонг показывается в конце, а не в начале.

Я подозреваю, что вы получите лучшие результаты, если будете поддерживать постоянную работу GPS - например, когда ваша активность включена.экран - с помощью requestLocationUpdates() или другого API, который включает GPS.

Ваша проблема Task может быть решена путем перемещения большей части вашей логики displayData() в onSuccess().Другими словами, вы ждете, пока после у вас не появится широта / долгота, прежде чем вы начнете добавлять данные ByteArray к TextView.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...