简体   繁体   中英

Android Bluetooth periodic calls to inputStream and outputStream: inconsistent timestamps

Two bluetooth enabled devices are connected. One sends a periodic timestamp (writeTime) through outputStream to the other, which retrieves the writeTimes via inputStream and attaches its own timestamps (readTime) for comparison. My goal is to make the readTime equal to the writeTime for each loop. The code below causes the writeTimes to increment with a predetermined delay (3 seconds), but the readTimes do not increment. The readTimes are fixed at the moment when the two devices connect to one another. Here are snippets of the outputStream.write and inputStream.read along with sample results.

For the sending device: Loop within a timer having three-second delays between writes to the outputStream: There is a CountDownTimer driving the onTick

    public void onTick(long millisUntilFinished) {
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat mdformat = new SimpleDateFormat("HH:mm:ss");
        String thisTime = mdformat.format(calendar.getTime());
        tV.setText("Current Time: " + thisTime);  // thisTime  increments on the display in real time.
        try {
            thisTime=thisTime+ "^";  // "^" added as the end of a line
            outputStream.write(thisTime.getBytes(Charset.forName("UTF-8")));
        } catch (IOException e) {}

For the receiving device: A read loop (iloop) that iterates the same number of times as the write loop from the sender:

        for (iloop =1;iloop<6;iloop++) {
            inputStream = socket.getInputStream();
            byte[] inbyte = new byte[1];
            int inbuffer;
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
            writeTime = "";
            eol = false;   
            do {
                inbuffer = br.read();
                if (inbuffer != 94) { // character "^" (byte 94) triggers an end-of-line for each read.

                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    DataOutputStream dos = new DataOutputStream(bos);
                    dos.writeInt(inbuffer);
                    inbyte = bos.toByteArray();
                    next = new String(inbyte, "UTF-8");
                    writeTime = writeTime + next;
                } else {eol = true;}

            } while (!eol);
            readTime = mdformat.format(calendar.getTime());
            readarray[iloop] = "\r\n" + writeTime + "  " + readTime ;
        }
    }

Screenshot of readarray after it is written: (a loop of five rows with 3 second delay between writes):

14:44:12  14:44:02
14:44:15  14:44:02
14:44:18  14:44:02
14:44:21  14:44:02
14:44:24  14:44:02

Conclusion: The inputStream is being read with a timestamp equal to the beginning of the socket connection. (In the example output, I waited ten seconds after connecting before intitiating the write to the outputStream). How do I get readTime to reflect the writeTime? My ultimate goal is to read from an inputStream at a periodic rate rather than batch processing a large number of small reads within a single batch. I want to access each read in real time and know when the read took place.

Update on this post: I took the insight from Ole VV and simply moved the following three lines of code from OUTSIDE the read loop (iloop) to INSIDE the iloop just above readTime

  Calendar calendar = Calendar.getInstance();
  SimpleDateFormat mdformat = new SimpleDateFormat("HH:mm:ss");
  String strDate;

This solved the problem. I should have understood that calendar is an instance of Calendar whose characteristic, calendar.getTime(), does not change with the ticking of the clock. The outdated SimpeDateFormat was not at fault although Ole VVs suggestion to replace it might be useful in other applications.

java.time

To put the current time, eg, the time of a read from your stream, into a string:

    DateTimeFormatter timeFormatter
            = DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM);
    String readTime = LocalTime.now(ZoneId.of("America/Dawson"))
            .format(timeFormatter);

The DateTimeFormatter may be created outside your loop, but you must call LocalTime.now inside the loop to get the time of the current iteration.

Example result in my locale is a string of 11.57.13 . Please substitute your desired time zone where I put America/Dawson.

I am using java.time, the modern java date and time API, because the date and time classes that you were using, Calendar and SimpleDateFormat , always had design problems and now are long outdated. Consider not using them anymore.

What went wrong in your code?

You haven't provided a complete example, so the snippets from the question cannot be compiled and run as they stand, and I have not been able to veryfy. It seems , however, that you have created a Calendar object outside the loop and that you don't modify the time of that Calendar object later. Therefore it keeps its time, and that time is the time you get every time through your loop. (By contrast, on your writing side you are creating a new Calendar object in every invocation of onTick , which is why you get the current time each time.)

Question: Can I use java.time on Android?

Yes, java.time works nicely on older and newer Android devices. It just requires at least Java 6 .

  • In Java 8 and later and on new Android devices (from API level 26) the new API comes built-in.
  • In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310, where the modern API was first described).
  • On (older) Android, use the Android edition of ThreeTen Backport. It's called ThreeTenABP. Make sure you import the date and time classes from package org.threeten.bp and subpackages.

Links

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM