How to read sensor data in android bluetooth not single byte - java

I've read data from sensor in android app via bluetooth using following code
try {
int byteCount = inputStream.available();
if (byteCount > 0) {
count++;
byte[] rawBytes = new byte[byteCount];
inputStream.read(rawBytes);
final String string = new String(rawBytes, "UTF-8");
handler.post(new Runnable() {
public void run() {
textView.append(string);
textView.append("\n");
}
});
}
} catch (IOException ex) {
stopThread = true;
}
This code read 10 as 1 and 0, So I want to read whole string . What will be required code for it?

Related

How do I show data in Textview for a 2 second (android Studio)?

I want to show data in Textview for 2 second time.So I recieved data from arduino that not have a delay between I use serialwrite.I use InputStream and DatainputStream for recieved data.It's still have a problem when data show in textview.It will chance to the next data suddenly.Is there any method for hold it for 2 sec and chance it to next ? I write code in android Studio .
.
private void receive(byte[] data) {
InputStream is = null;
DataInputStream dis = null;
try {
is = new ByteArrayInputStream(data);
dis = new DataInputStream(is);
while (dis.available() > 0) {
byte[] b = new byte[data.length];
dis.read(b, 0, 8);
count++;
String part = HexDump.dumpHexString(b).substring(HexDump.dumpHexString(b).indexOf("E7 0"), HexDump.dumpHexString(b).indexOf("0A"));
if (part.contains("E7 01")) {
//receive_text2.setText((part));
show_text(receive_text2,part);
}
if (part.contains("E7 02")) {
receive_text3.setText(String.valueOf(1000*unsiged(b[5])+100*unsiged(b[6])));
}
if (part.contains("E7 03")) {
receive_text4.setText((part));
}
if (part.contains("E7 05")) {
receive_text5.setText((part));
}
receive_text6.setText(String.valueOf(count));
}
}catch (Exception e){
receive_text2.append("");
receive_text3.append("");
receive_text4.append("");
receive_text5.append("");
receive_text6.append("");
}
}
You could try to post a delay of 2 seconds (2000 millisec) with a Handler each time you attempt to set the text value.
TextView textView = ...;
textView.postDelayed(new Runnable() {
#Override
public void run() {
textView.setText("some text");
}
}, 2000); // delay of 2 seconds before setting a text to textView
Add all the strings you want to display into an Arraylist
ArrayList<String> strings = new ArrayList<>();
then do:
Runnable job = new Runnable() {
#Override
public void run() {
if (!strings.isEmpty()) {
textView.setText(strings.get(0));
strings.remove(0);
textView.postDelayed(this, 2000);
} else {
textView.removeCallbacks(this);
}
}
};
textView.postDelayed(job, 2000); // delay of 2 seconds before setting a text to textView

bluetooth handler Data missing while communicating string sentance. android studio

I was trying to transfer sensor data to string sentence to sentence
Arduino send a sentence which is to 'btSerial.read()'
And An app received the sentence with Bluetooth handler.
when I send "<123,456>" the app received sometimes <23,456>" or "<123,456>"
when I send "<10,10>" the app received sometimes "<0,10>>>"...
I don't understand why it happens. Could someone tell me? why?
Arduino Code
include <SoftwareSerial.h>
SoftwareSerial btSerial(5,6); //RX, TX
void setup() {
Serial.begin(9600);
btSerial.begin(9600);
}
void loop() {
if(Serial.available()) {
btSerial.write(Serial.read());
}
if(btSerial.available()) {
Serial.write(btSerial.read());
}
}
And send "<123,456>" with Serial monitor
Android Studio - Received data (Handler part)
public Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == handlerState) {
String readMessage = (String) msg.obj;
recDataString.append(readMessage);
int endOflineIndex = recDataString.indexOf(">");
if (endOflineIndex > 0) {
if (flag == 1) { //Wait until flag=1,after this flag=0.
Log.d(Tag, String.valueOf(recDataString));
textview.setText("received data : " + readMessage);
}
recDataString.delete(0, recDataString.length());
flag = 0;
}
}
}
}
...
Android Studio - send sensor data part
#Override
public void onSensorChanged(SensorEvent event) {
x = ((int) event.values[0] + 10) * 13;
y = ((int) event.values[1] + 10) * 13 / 3;
if (connect) {
if ( flag ==0) {
xx = Integer.toString(x);
yy = Integer.toString(y);
connectedThread.send("<" + xx + "," + yy + ">");
flag = 1;
}
else {
}}
Android Studio - Bluetooth Thread part
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private final OutputStream mmOutStream;
ConnectedThread(BluetoothSocket socket) {
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException ignored) {
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024];
int bytes; // bytes returned from read()
// keep listening to the InputStream untill an exception occurs
while (true) {
try {
// Read from the Inputstream
bytes = mmInStream.read(buffer);
final String readingMessage = new String(buffer, "US-ASCII");
mHandler.obtainMessage(handlerState, bytes, -1,readingMessage).sendToTarget();
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
...
I found the same issue while receiving data from an STM micro controller. For me, if I slow the data from the mcu down and shorten the length of data received its not as bad.
The best thing to do is to put and end of message delimiter in your arduino code then check for the delimiter in android. Something like "\n".

Execute multiple Asynctask

I would like to implement a image processing Asynctask in Android. There is a condition - if the previous asyntask is processing locally, the current task should process on the server.
I tried 4 images, and set the Thread.sleep(1000) in side the local process section, expected the first one process locally and others on server. However, they are all processed locally. Am I wrong?
private class ProcessImageTask extends AsyncTask<ImageItem, Void, ImageItem>{
#Override
protected ImageItem doInBackground(ImageItem... params) {
if(localProcessing==false){
//**************processing locally*****************
localProcessing = true;
try {
Bitmap bm = BitmapFactory.decodeFile(params[0].getBitmap());
Bitmap croppedBitmap = getBitmap(getApplicationContext(), INPUT_SIZE, bm);
final List<Classifier.Recognition> results = classifier.recognizeImage(croppedBitmap);
String resultStr = results.toString();
String trimResult = resultStr.substring(resultStr.indexOf("[")+1,resultStr.indexOf("]")).trim();
String localId = params[0].getId();
trimResult = trimResult.substring(0,trimResult.indexOf(")")) + " likely)";
Bitmap thumbnail = getBitmap(getApplicationContext(), 50, bm);
ImageItem tmp = new ImageItem(localId, imgToString(thumbnail), trimResult);
Thread.currentThread();
Thread.sleep(1000);
localProcessing = false;
return tmp;
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
//****************processing on server*************************
try {
String ip = "192.168.1.3";
int port = 8195;
Bitmap bm = BitmapFactory.decodeFile(params[0].getBitmap());
Bitmap croppedBitmap = getBitmap(getApplicationContext(), INPUT_SIZE, bm);
String encodedImage = "/ID-BEGIN/" + ID + "/ID-END" + imgToString(croppedBitmap);
try {
//**********Send request to server*********
Socket socket = new Socket(ip,port);
DataInputStream dis = new DataInputStream(socket.getInputStream());
DataOutputStream dout = new DataOutputStream(socket.getOutputStream());
byte [] messageToServer = encodedImage.getBytes();
dout.writeInt(messageToServer.length);
dout.write(messageToServer);
//Receive response from server
int length = dis.readInt();
if(length>0) {
byte [] message = new byte[length];
dis.readFully(message, 0, message.length);
String response = new String(message);
//Handler updateHandler.post(new updateUIThread(response));
Bitmap thumbnail = getBitmap(getApplicationContext(), 50, bm);
ImageItem tmp = new ImageItem(params[0].getId(),imgToString(thumbnail), extractServerMessage(response)+"##");
return tmp;
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPostExecute(ImageItem imageItem) {
super.onPostExecute(imageItem);
}
}
and I executes in a for loop
ImageItem it = pit.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, tmp).get();
Should I need to set the core pool size? Thanks a lot.
Your call to AsyncTask.get() waits for the task to finish before returning, so you're not actually running these in parallel, despite using the THREAD_POOL_EXECUTOR. You shouldn't call get here, but instead rely on onPostExecute to communicate results back to your program.

Wrong messages sequence with socket DataInputStream BufferedInputStream in Android app

I have a problem with receiving irregular sequence of the byte messages I send from another device.
The setup is the following: I have an Android app (client) and Real-Time system (server) with Ethernet both connected in a LAN through router, which talk with raw bytes communication.
From the Android app I send request, which causes the server to respond with several messages - the first one with 8 bytes, the following messages have 27 bytes. I have debugged the server and I am sure the first message it sends is the 8th-byte one, followed by the others.
About the app - I use the Main Activity to handle transmission of data through the socket, and additional thread to handle reception of data.
The thread makes post through Handler to the Main Activity, when new data has been received. In this post is called a process to parse the received data.
TbProtocolProcessor is a class I use to handle my custom protocol. It can create a byte array for me to send as request for specific function, and it has a state-machine to process expected response from the server. InetHandler is nested class I use to handle my connectivity only.
My question is - why would my Android app return me the first message having size 8, but contents like the next messages? Interesting effect is that if I send ONLY the 8-byte message, without any others, it is received and passed to my app correctly.
Here is the code:
public class MainActivity extends AppCompatActivity
{
private TbProtocolProcessor tbProtPrcs = null;
private InetHandler inetHandler = new InetHandler(this);
private static Handler msgHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tbProtPrcs = new TbProtocolProcessor(this);
}
// Implementation of InetControl interface
public void ConnectToIP(String strIP, int port)
{
inetHandler.AttachToIP(strIP, port);
}
public void Disconnect()
{
inetHandler.DetachFromIP();
}
public void GetFilesList()
{
byte[] data = TbProtocolProcessor.buildFilesGetList();
inetHandler.SendData(data, data.length);
TbProtocolProcessor.setExpectedResult(
TbProtocolProcessor.TB_STATE_WAIT_MUL_FILESLIST,
data[1],
1);
}
private class InetHandler
{
protected static final int cTARGET_PORT_UNASSIGNED = 0xFFFF;
protected String targetIP = null;
protected int targetPort = cTARGET_PORT_UNASSIGNED;
protected boolean isConnected = false;
protected Socket socket = null;
protected DataOutputStream sockStrmOut = null;
protected DataInputStream sockStrmIn = null;
protected Context context = null;
public InetHandler(Context ctx) {
if (ctx != null)
{
context = ctx;
}
}
class ClientThread implements Runnable {
byte[] indata = new byte[100];
int inCntr;
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(targetIP);
socket = new Socket(serverAddr, targetPort);
socket.setKeepAlive(true);
// DataOutputStream is used to write primitive data types to stream
sockStrmOut = new DataOutputStream(socket.getOutputStream());
sockStrmIn = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
if (socket.isConnected()) {
isConnected = true;
//Toast.makeText(context, "CONNECTED", Toast.LENGTH_SHORT).show();
//findViewById(R.id.action_connect).setBackgroundColor(0xFF60FF60);
}
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
// TODO:
while (isConnected) {
try {
inCntr = sockStrmIn.read(indata);
}
catch (IOException e) {
e.printStackTrace();
}
if (inCntr > 0) {
msgHandler.post(new Runnable() {
#Override
public void run() {
if ( tbProtPrcs.Process(indata, inCntr) ) {
Toast.makeText(context, "Operation Success", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(context, "Operation ERROR", Toast.LENGTH_SHORT).show();
}
}
});
}
}
}
}
public void AttachToIP(String sIP, int iPort)
{
if ( (isIPValid(sIP)) && (iPort < cTARGET_PORT_UNASSIGNED) )
{
targetIP = sIP;
targetPort = iPort;
// Start the connection thread
new Thread(new ClientThread()).start();
}
}
public void DetachFromIP()
{
try {
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
public boolean SendData(byte[] data, int size)
{
boolean bResult = false;
try
{
if ( (data != null) && (size > 0) && (sockStrmOut != null) ) {
Toast.makeText(context, "Sending...", Toast.LENGTH_SHORT).show();
sockStrmOut.write(data, 0, size);
bResult = true;
}
} catch (Exception e) {
e.printStackTrace();
}
return bResult;
}
public boolean isIPValid (String ip) {
try {
if (ip == null || ip.isEmpty()) {
return false;
}
String[] parts = ip.split( "\\." );
if ( parts.length != 4 ) {
return false;
}
for ( String s : parts ) {
int i = Integer.parseInt( s );
if ( (i < 0) || (i > 255) ) {
return false;
}
}
return true;
} catch (NumberFormatException nfe) {
return false;
}
}
}
}
You're assuming that read() fills the buffer. It isn't specified to do that. See the Javadoc. If you want to fill the buffer you must use readFully().
NB isConnected() cannot possibly be false at the point you're testing it.

Download a large file in background only on WiFi

So what I'm trying to achieve is creating a service that downloads a large (~200 MB) file to the app's internal directory. It should resume (not restart) when it got canceled and automatically resume after a system reboot. It should sometimes (as written in a propeties file) only download using WiFi connection.
To do so I created an IntentService (is that a suitable solution?) that gets started by an Frgament's UI or by a BroadcastReceiver (after boot-up):
#Override
public void onHandleIntent(final Intent intent) {
c.registerReceiver(receiver, new IntentFilter(
ConnectivityManager.CONNECTIVITY_ACTION));
c.registerReceiver(receiver, new IntentFilter(
WifiManager.NETWORK_STATE_CHANGED_ACTION));
receiver.onReceive(null, null); // To start the download the first time
}
The last line calls a BroadcastReceiver that handles the download process. This is the way I tried to make sure that there is only one ongoing download at a time:
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
boolean allowed = isConnectionAllowed();
if (allowed && !thread.isAlive()) {
thread.start();
} else if (allowed && thread.isAlive()) {
thread.notify(); // Can this cause any problems in this case?
} else if (!allowed && thread.isAlive()) {
try {
thread.wait();
} catch (InterruptedException e) {
if (StartActivity.DEV_MODE)
Log.i(StartActivity.LOG_TAG, Log.getStackTraceString(e));
}
}
}
};
And the download itselv runs in a seperate Thread.
private Thread thread = new Thread() {
#SuppressWarnings("resource")
#Override
public void run() {
HttpURLConnection connection = null;
BufferedInputStream input = null;
RandomAccessFile output = null;
try {
long already_downloaded = 0;
URL url = new URL(getSource());
File outputFileCache = new File(getDestination());
connection = (HttpURLConnection) url.openConnection();
if (outputFileCache.exists()) {
connection.setAllowUserInteraction(true);
connection.setRequestProperty("Range", "bytes="
+ outputFileCache.length() + "-");
}
connection.setConnectTimeout(14000);
connection.setReadTimeout(20000);
connection.connect();
if (connection.getResponseCode() / 100 != 2)
throw new Exception("Invalid response code!");
else {
String connectionField = connection
.getHeaderField("content-range");
if (connectionField != null) {
String[] connectionRanges = connectionField.substring(
"bytes=".length()).split("-");
already_downloaded = Long.valueOf(connectionRanges[0]);
}
if (connectionField == null && outputFileCache.exists())
outputFileCache.delete();
long fileLength = connection.getContentLength()
+ already_downloaded;
input = new BufferedInputStream(connection.getInputStream());
output = new RandomAccessFile(outputFileCache, "rw");
output.seek(already_downloaded);
byte data[] = new byte[1024];
int count = 0;
int progress = 0;
int progress_last_value = 0;
while ((count = input.read(data, 0, 1024)) != -1
&& progress != 100) {
already_downloaded += count;
output.write(data, 0, count);
progress = (int) ((already_downloaded * 100) / fileLength);
if (progress != progress_last_value) {
// Update notification
}
}
}
} catch (MalformedURLException e) {
if (StartActivity.DEV_MODE)
Log.i(StartActivity.LOG_TAG, Log.getStackTraceString(e));
} catch (IOException e) {
if (StartActivity.DEV_MODE)
Log.i(StartActivity.LOG_TAG, Log.getStackTraceString(e));
} catch (Exception e) {
if (StartActivity.DEV_MODE)
Log.i(StartActivity.LOG_TAG, Log.getStackTraceString(e));
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
if (connection != null)
connection.disconnect();
} catch (IOException e) {
if (StartActivity.DEV_MODE)
Log.i(StartActivity.LOG_TAG, Log.getStackTraceString(e));
}
}
// notify the Fragment using a `LocalBroadcast`.
}
};
And to make sure that the WiFi connection ist kept alive, I use the WifiLock class.
Note: I shortened the code in a few cases but I already managed to write that code.
So I'm not sure whether this is a good solution for my problem:
Should I use an IntentService or a normal Service for that?
Is that solution using a Thread a good one and will it work?
Won't the HttpURLConnection expire?
Can I access the Thread that way? (referres to wait() and notify())
I know this is a lot of code but it was the closest I could get. I hope someone knows a solution for that becuase I couldn't find anything usful on that topic ("only download while WiFi in ON") using Google and StackOverflow.
Thanks in advance,
Felix
(Comment if you need the whole Class)

Categories