A problem about serialization and deserialization of board
Hi,
I got a problem while deserializing metawear board.
This is my downloadData function:
private void downloadData(ProgressBar progress) throws FileNotFoundException {
String datetime = DateFormat.getDateTimeInstance().format(new Date());
accelerometerWriter = new DataWriter(board.getMacAddress() + "_" + datetime + "_accelerometer" + ".csv");
gyroscopeWriter = new DataWriter(board.getMacAddress() + "_" + datetime + "_gyroscope" + ".csv");
stepWriter = new DataWriter(board.getMacAddress() + "_" + datetime + "_step" + ".csv");
stopAllSensors(false, false);
logging.downloadAsync(100, (nEntriesLeft, totalEntries) -> {
Log.i("MainActivity", "Progress Update = " + (totalEntries - nEntriesLeft) + "/" + totalEntries);
mainActivity.runOnUiThread(() -> {
progress.setMax((int) totalEntries);
progress.setProgress((int) totalEntries - (int) nEntriesLeft);
});
}).continueWithTask((Continuation<Void, Task<Void>>) task -> {
Log.i("MainActivity", "Download completed");
progress.setProgress(0);
board.tearDown();
disconnectBoard(true);
accelerometerWriter.closeStream();
gyroscopeWriter.closeStream();
stepWriter.closeStream();
return null;
});
}
I serialize board right after all sensors are started and right before starting logging, and deserialize the board after "stopAllSensors()" is called.
This is my stopAllSensors() function:
private void stopAllSensors(boolean teardown, boolean disconnect) {
Log.i(TAG, "Stop all sensors");
accelerometerBmi160.acceleration().stop();
accelerometerBmi160.stepDetector().stop();
accelerometerBmi160.stop();
gyroBmi160.angularVelocity().stop();
gyroBmi160.stop();
logging.stop();
led.stop(true);
if (teardown)
board.tearDown();
if (disconnect)
disconnectBoard(true);
deserializeBoard(); // Load current board state for data collection or clear all the serializeFiles
}
My subscribers are like below:
private static Subscriber ACCELEROMETER_HANDLER = (Data data, Object... env) -> {
String value = data.timestamp().getTimeInMillis() + "," +
data.formattedTimestamp() + "," +
"0" + "," +
data.value(Acceleration.class).x() + "," +
data.value(Acceleration.class).y() + "," +
data.value(Acceleration.class).z() + "\n";
getInstance().accelerometerWriter.write(value);
};
private static Subscriber GYROSCOPE_HANDLER = (Data data, Object... env) -> {
String value = data.timestamp().getTimeInMillis() + "," +
data.formattedTimestamp() + "," +
"0" + "," +
data.value(AngularVelocity.class).x() + "," +
data.value(AngularVelocity.class).y() + "," +
data.value(AngularVelocity.class).z() + "\n";
getInstance().gyroscopeWriter.write(value);
};
private static Subscriber STEP_COUNTING_HANDLER = (Data data, Object... env) -> {
String value = data.timestamp().getTimeInMillis() + "\n";
getInstance().stepWriter.write(value);
};
Since I'm using my own data writer object to write data to my mobile phone, I'm not passing any object into subcriber, so I guess I don't have to "setEvironment" before downloading data, right?
It works well if I don't call "deserializeBoard()".
Btw, these are my serialize and deserialize functions:
/**
* Serializes the current board into a file locally (identified using the mac address of the device)
* to be restored when getting data from the device
*/
public void serializeBoard() {
File fileDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "mobilityData");
if (!fileDir.exists()) {
if (!fileDir.mkdirs())// create root directory
Log.i(TAG, "serializeBoard: Failed to create data folder...");
}
try {
File serializeFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ File.separator
+ "mobilityData"
+ File.separator
+ board.getMacAddress());
if (!serializeFile.createNewFile())
Log.i(TAG, "serializeBoard: Failed to create serializeFile...");
OutputStream writer = new FileOutputStream(serializeFile, false);
board.serialize(writer);
writer.close();
Log.i(TAG, "Serialized: " + board.getMacAddress());
} catch (IOException e) {
Log.i(TAG, "Write failed for: " + board.getMacAddress() + " " + e.toString());
e.printStackTrace();
}
}
/**
* Deserializes a board that is already stored on the device
*/
public void deserializeBoard() {
try {
File serializeFile =
new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ File.separator
+ "mobilityData"
+ File.separator
+ board.getMacAddress());
if (serializeFile.exists()) {
InputStream reader = new FileInputStream(serializeFile);
board.deserialize(reader);
reader.close();
if (!serializeFile.delete())
Log.i(TAG, "deserializeBoard: Failed to delete serializedFile...");
Log.i(TAG, "Deserialized: " + board.getMacAddress());
}
else {
mainActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(mainActivity, "Cannot find serializedBoardFile for: " + board.getMacAddress(), Toast.LENGTH_LONG).show();
}
});
}
} catch (IOException | ClassNotFoundException e) {
Log.i(TAG, "Failed to read: " + board.getMacAddress() + " " + e.toString());
}
}
When I start collecting data, it doesn't show the progress as logs, seems like "receivedUpdate(long nEntriesLeft, long totalEntries)" is never called. And after a few seconds, this log will show up:
W/metawear: Log download finished but no Task object to complete
After that, I checked the storage of my phone, I found the data file (.csv) is right there, it means the data collection was successful. But it never disconnect with the board and my writer streams were not closed. So I think "continueWithTask()" function was not called.
Anyways, I just have two questions:
1. Why it doesn't update the downloading progress?
2. Why the continueWithTask() is not called?
I appreciate any help!
Thanks,
Tianyuan
Comments
Deserialize the boaed state first, then acquire references to the modules.
Your logging module, at the download part, is referring to the older object.
Hi Eric,
Thank you so much for your help, I had been stuck here for a few days, it works right now after following your instruction.