Я хочу, чтобы мое приложение при получении данных с устройства 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
}
}