android - 在android中通过BLE传输图像
问题描述
我正在使用以下代码传输 1 mb 的图像。如果在每个数据包之间实现了线程延迟,则图像将成功传输。如果未设置线程延迟,则所有数据包都是从 BluetoothGattServer 发送的,但 BluetoothGattCallback 不会收到所有数据包。
任何人都可以指导在没有线程延迟的情况下发送数据包
在每个数据包之间实现线程
private void sendingContinuePacket(BluetoothGattCharacteristic characteristic,
byte[] CHARACTERS) {
boolean isComplete = false;
runOnUiThread(() -> {
tv_status.setText("Sending Data...!!");
startTime = SystemClock.uptimeMillis();
customHandler.postDelayed(updateTimerThread, 0);
});
// Check the data length is large how many times with Default Data (BLE)
int times = CHARACTERS.length / DEFAULT_BYTES_IN_CONTINUE_PACKET;
totalPackets = times;
Log.i("", "CHARACTERS.length() " + CHARACTERS.length);
byte[] packetNoByte;
byte[] sending_continue_hex = new byte[DEFAULT_BYTES_IN_CONTINUE_PACKET];
for (int time = 0; time <= times; time++) {
final int remainingTime = time;
if (!hasDisconnected) {
this.runOnUiThread(new Runnable() {
@Override
public void run() {
mRelativeLayout.setVisibility(View.VISIBLE);
if (totalPackets != 0) {
showProgress(totalPackets, remainingTime);
}
}
});
} else {
runOnUiThread(() -> {
mProgressBar.setProgress(0);
tv_progress.setText(0 + "%");
tv_timer.setText("00:00:00");
tv_imageSize.setText("");
tv_status.setText("");
Toast.makeText(PeripheralRoleActivity.this, "Something went wrong, Please Try again", Toast.LENGTH_SHORT).show();
customHandler.removeCallbacks(updateTimerThread);
});
return;
}
int a;
int b;
/**
* @param THREAD_SLEEP_TIME_FOR_NOTIFICATION
* this delay is placed to give a small pause while sending the data packe
* */
try {
Thread.sleep(Constants.THREAD_SLEEP_TIME_FOR_NOTIFICATION);
} catch (InterruptedException e) {
e.printStackTrace();
}
sentPacket = sentPacket + 1;
byte[] packetArray = Utils.getUtilsClass().toByteArray(sentPacket);
packetNoByte = Arrays.copyOf(packetArray, packetArray.length);
if (time == times) {
Log.i("", "LAST PACKET ");
int character_length = CHARACTERS.length
- DEFAULT_BYTES_IN_CONTINUE_PACKET * times;
byte[] sending_last_hex = new byte[character_length];
a = (sending_continue_hex.length) * time;
b = a + character_length;
if(b-a ==0){
return;
}
sending_last_hex = Arrays.copyOfRange(CHARACTERS, a, b);
byte[] last_packet =
new byte[packetNoByte.length + character_length];
System.arraycopy(packetNoByte, 0, last_packet,
0, packetNoByte.length);
System.arraycopy(sending_last_hex, 0, last_packet,
packetNoByte.length, sending_last_hex.length);
Log.d("Sending packets", Arrays.toString(last_packet));
// Set value for characteristic
characteristic.setValue(last_packet);
notifyCharacteristicChanged();
isComplete = true;
customHandler.removeCallbacks(updateTimerThread);
currentDateTimeString = DateFormat.getDateTimeInstance().format(new Date());
Log.d("Collection", "End Time: " + currentDateTimeString);
Utils.getUtilsClass().sendNotification(getApplicationContext(), "Data Transfer", "Transfer Complete");
} else {
Log.i("", "CONTINUE PACKET ");
a = ((sending_continue_hex.length) * time);
b = a + DEFAULT_BYTES_IN_CONTINUE_PACKET;
sending_continue_hex = Arrays.copyOfRange(CHARACTERS, a, b);
byte[] sending_continue_packet =
new byte[packetNoByte.length + sending_continue_hex.length];
System.arraycopy(packetNoByte, 0, sending_continue_packet,
0, packetNoByte.length);
System.arraycopy(sending_continue_hex, 0, sending_continue_packet,
packetNoByte.length, sending_continue_hex.length);
Log.d("data transfer a", String.valueOf(a));
Log.d("data transfer b", String.valueOf(b));
Log.d("data trans bytes", String.valueOf(sending_continue_hex.length));
if(output == null){
output = new ByteArrayOutputStream();
}
try {
if {
characteristic.setValue(sending_continue_packet);
Log.d("Sending packets", Arrays.toString(sending_continue_packet));
notifyCharacteristicChanged();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Log.d("Data byte", "times " + time);
if (isComplete) {
characteristic.setValue("Completed");
notifyCharacteristicChanged();
}
runOnUiThread(() -> tv_status.setText("Data sent!!"));
}
}
更新代码
//以下函数用于将图像字节[]分成数据包并将其存储在arraylist中
private void breakPackets(byte[] CHARACTERS) {
// Check the data length is large how many times with Default Data (BLE)
int times = CHARACTERS.length / DEFAULT_BYTES_IN_CONTINUE_PACKET;
totalPackets = times;
packetList = new ArrayList<>();
sendingPacket = 0;
Log.i("", "CHARACTERS.length() " + CHARACTERS.length);
byte[] sending_continue_hex = new byte[DEFAULT_BYTES_IN_CONTINUE_PACKET];
for (int time = 0; time <= times; time++) {
int a;
int b;
if (time == times) {
Log.i("", "LAST PACKET ");
int character_length = CHARACTERS.length
- DEFAULT_BYTES_IN_CONTINUE_PACKET * times;
byte[] sending_last_hex = new byte[character_length];
a = (sending_continue_hex.length) * time;
b = a + character_length;
sending_last_hex = Arrays.copyOfRange(CHARACTERS, a, b);
//packetList is an ArrayList<byte[]>
packetList.add(sending_last_hex);
startSendingPackets(sendingPacket);
} else {
a = (sending_continue_hex.length) * time;
b = a + DEFAULT_BYTES_IN_CONTINUE_PACKET;
sending_continue_hex = Arrays.copyOfRange(CHARACTERS, a, b);
packetList.add(sending_continue_hex);
}
Log.d("Data byte", "times " + time);
}
}
//the following function is used to set the byte[] from the arraylist to the characteristics and then notify the characteristics
private void startSendingPackets(int packet) {
isCommand = false;
mSampleCharacteristic.setValue(packetList.get(packet));
notifyCharacteristicChanged();
Log.i("packeting", "Sending ------------> " + packet);
}
/*************************************************/
@Override
public void onNotificationSent(BluetoothDevice device, int status) {
super.onNotificationSent(device, status);
//check if status is success
if (status == BluetoothGatt.GATT_SUCCESS) {
//if status is not successful isExecutable is false and the else loop is executed to resend the same packet that has failed
if (isExecutable) {
// Log.i("packeting", "Sent ------------> " + sendingPacket);
sendingPacket = sendingPacket + 1;
int size = packetList.size();
if (sendingPacket <= size-1) {
startSendingPackets(sendingPacket);
Log.d(MainActivity.TAG, "Notification sent. Status: " + status + " sending packet no --" + sendingPacket);
} else {
sendCommand("Completed");
}
} else {
startSendingPackets(sendingPacket);
isExecutable = true;
Log.d(MainActivity.TAG, "Notification sent. Status: " + status + " sending packet no --" + sendingPacket);
}
}else{
//if status is not successful
isExecutable = false;
Log.d(MainActivity.TAG, "Notification sent. fail Status: " + status );
}
}
解决方案
当要发送多个通知时,应用程序必须等待收到此回调,然后才能发送其他通知。
这意味着在您调用后,在收到回调之前notifyCharacteristicChanged
您不能再次调用。因此,您需要删除-loop 并重构代码以遵循 API 规则。notifyCharacteristicChanged
onNotificationSent
for
这样做的原因是为了获得流量控制。如果您只是以比 BLE 链路的吞吐量更快的速度推送新数据包,则内部缓冲区会变满并且会发生数据包丢失。这就是为什么延迟似乎有效,但它不是一个强大的解决方案,因此您应该等待onNotificationSent
回调,因为这意味着 BLE 堆栈已准备好接受新数据包。
推荐阅读
- android - 应用 apk 大小超过 100mb。如何将其上传到 PlayStore?
- angular - Angular 6:如何使用 Angular Material 隐藏无线电圈并使用 NgStyle 进行检查答案?
- firefox - Firefox 上的 Phaser3 静音
- node.js - 使用 Mariasql 客户端和 JawsDB Maria 插件在 Heroku 上部署应用程序
- c# - Unity,视觉效果图 - 我如何以编程方式播放+停止效果?
- java - 如果单击不同的单选按钮,则仅保存最后一个的值
- java - 我想知道使用 Sonar 的最佳方法是什么?
- karate - 如何在空手道中使用 js EXPR 和 XML
- python - python:无法使用 eval() 运行对象方法
- android - 未检测到 CurrentUser 时无法将用户发送到登录活动