In my Android application I am reading brain data values from an EEG headset. These values are then being written to a Text File.
The problem with this is that the values are being produced 500 times a seconds. As a result they are also being written to the text file 500 times a second, which I don't want.
I only want the values to be displayed in the text file once a second. I was reading about buffering to do so.
How could I use buffering in my case to solve the problem?
Below is my current android code, and also rough pseudo code for what i'm trying to achieve.
Current Android code:
Method used to save the data to file:
public void writeToFileRawData(String data) {
// creating the file where the contents will be written to
File file = new File(dir, fileNameRaw + ".txt");
FileOutputStream os;
try {
boolean append = true;
os = new FileOutputStream(file, append);
String writeMe = data + "\n";
os.write(writeMe.getBytes());
os.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Calling the above method within the handler for the Headset Values:
Note: in code below "order" is irrelevant, it is just a method used for formatting the txt.
final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
// msg.what determines the type of each message
switch (msg.what) {
case TGDevice.MSG_RAW_DATA:
// creating the string to be written to file
String line2 = order(seconds2 + "") + order("" + msg.arg1)
+ "\n";
// write the string to file
writeToFileRawData(line2);
break;
Rough Pseudo code for what I am trying to achieve:
brainWaveRaw
time voltage
xxx yyyy
xxx yyyy
[and there should be 500 of these per second]
(buffer these to minimize number of disk writes)
// initialize
timeOfLastRawWrite = timeNow
rawWriteStringBuffer = ''
rawEvent(raw (list of last one or few raw samples))
eventTime = timeNow
for every entry r in raw
rawWriteStringBuffer.append(printf("%d %d\n", eventTime, r))
if timeNow-timeOfLastRawWrite > one second
write rawWriteStringBuffer to file
rawWriteStringBuffer = ''
timeOfLastRawWrite = timeNow
// e.g. if last set of raw values was [123, 456, 678], arrived at time
9876
9876 123
9876 456
9876 678
Don't open the file every time.
Use BufferedOutputStream.
You might want to flush the stream every several times.
Handler mHandler; // member of your Activity class
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final String dir = ...;
final String fileNameRaw = ...;
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// msg.what determines the type of each message
switch (msg.what) {
case TGDevice.MSG_RAW_DATA:
// creating the string to be written to file
String line2 = order(seconds2 + "") + order("" + msg.arg1)
+ "\n";
// write the string to file
writeToFileRawData(line2);
break;
}
}
// members of your custom Handler class
private File mFile = new File(dir, fileNameRaw + ".txt");
private BufferedOutputStream mOs = new BufferedOutputStream(new FileOutputStream(mFile, true));
private int mWriteCnt = 0;
// moved this function from Activity to your custom Handler class as well
private void writeToFileRawData(String data) {
try {
mOs.write(data.getBytes());
mOs.write("\n".getBytes());
if (++mWriteCnt == 500) {
mOs.flush();
mWriteCnt = 0;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Related
I'm aware that that
All background work is given a maximum of ten minutes to finish its execution
and that it may take it's time depending on certain things
My code belows creates 8 OneTimeWorkRequests then puts them what im hoping is a chain then is enqueued;
workManager.beginWith(deleteCurrent)
.then(deleteCurrentImages)
.then(insertData)
.then(insertImage)
.then(insertAutoNames)
.then(insertAutoCondition)
.then(checkComplete)
.enqueue();
The last request is to finish the current activity (if it reaches this request, it's assumed all tasks ran successfully) see below.
public class CheckComplete extends Worker {
#NonNull
#Override
public Result doWork() {
MyApplication myApplication = null;
boolean run = true;
Context context = getActivity();
myApplication = (MyApplication) context.getApplicationContext();
SQLiteConnection mybdc = myApplication.getData();
String jobNo = getInputData().getString("jobNo", "");
String section = getInputData().getString("section", "");
int viewSize = getInputData().getInt("viewSize", 0);
int result = checkLastEntry(jobNo, section,viewSize, mybdc);
if (1 == result) {
getActivity().finish();
return Result.SUCCESS;
} else {
Message.message(context, "Error occurred, please try and save again");
return Result.FAILURE;
}
}
public int checkLastEntry(String jobNo, String section, int viewSize, SQLiteConnection mydbc) {
ArrayList<String> values = new ArrayList<>();
try {
SQLiteStatement mystatement = null;
mystatement = mydbc.prepareStatement("SELECT value FROM documentTable WHERE jobNo = '" + jobNo + "' AND section = '" + section + "'");
while (mystatement.step()) {
values.add(mystatement.getColumnTextNativeString(0));
}
} catch (SQLException ex) {
try {
File path = new File("/sdcard/exports/logs");
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
String currentDateTime = dateFormat.format(new Date()) + " ";
File myFile = new File(path, "DBCrashes.txt");
FileOutputStream fOut = new FileOutputStream(myFile, true);
OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
myOutWriter.append("\n" +
"\r");
myOutWriter.append(currentDateTime + " Error reading values: " + ex);
myOutWriter.close();
fOut.close();
return 0;
} catch (java.io.IOException e) {
return 0;
}
}
if(values.size()==viewSize) {
return 1;
}else{
return 0;
}
}
}
There is a class for each OneTimeWorkRequests (besides insertAutoNames/Condition)
I put a break point on each return line in doWork().
For some reason when I run it sometimes it just hangs and would not reach the next tasks return line what could be causing this?
Edit: The workers begin when a "save" button is pressed, if it hangs this should allow the user to push save again, this will run the line below then run the commands above, however it doesn't seem to cancel the threads at work.
workManager.cancelAllWork();
Should I even be using WorkManager to query the database?
Previously I had it on a main thread but had some problems.
You cannot assume that there will be an Activity running when your Worker is being run. This is because JobScheduler may run your Worker alone in the background. You should be using getWorkInfoById() instead.
I am using android's thread pool executor framework (initialized as below).
BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>();
ExecutorService executorService = new ThreadPoolExecutor(totalCores, totalCores * 3, 10, TimeUnit.SECONDS, taskQueue);
Now, consider the following function onFrameProcessed -
public void onFrameProcessed(RenderedImage renderedImage) {
String timeNow = new SimpleDateFormat("d-M-Y_HH_mm_ss_SSS").format(new Date()).toString();
CustomRunnable3 customRunnable3 = new CustomRunnable3(renderedImage, timeNow);
executorService.execute(customRunnable3);
}
Definition of CustomRunnable3 is as follows:
class CustomRunnable3 implements Runnable {
RenderedImage renderedImageLocal;
String basePath, timeNowCopy;
int hashCode;
CustomRunnable3(RenderedImage renderedImage, String timeNow) {
renderedImageLocal = renderedImage;
this.basePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString();
this.timeNowCopy = timeNow;
hashCode = renderedImageLocal.hashCode();
}
#Override
public void run() {
if (renderedImageLocal.imageType() == RenderedImage.ImageType.ThermalRadiometricKelvinImage) {
int[] thermalData = renderedImageLocal.thermalPixelValues();
String dataPath = basePath + "/" + this.timeNowCopy + ".csv";
try {
PrintWriter printWriter = new PrintWriter(dataPath);
int dataLen = thermalData.length;
for (int i = 0; i < dataLen; i++) {
printWriter.println(thermalData[i]);
}
printWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
String imgPath = basePath + "/" + this.timeNowCopy + ".jpg";
try {
if (hashCode != renderedImageLocal.hashCode()) {
Log.e("Checking", "Hash code changed..");
}
renderedImageLocal.getFrame().save(new File(imgPath), frameProcessor);
if (hashCode != renderedImageLocal.hashCode()) {
Log.e("Checking", "Hash code changed after writing..");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Usage Scenario : onFrameReceived is being called multiple times per second(like 4-5 times). In each call to onFrameReceived, I am saving two files from renderedImage object (1 csv file, 1 jpg file). Both of these files must be related to each other because both are created from one parent and have same name(except the extension).
Problem : But that is not happening and somehow I am ending up with jpg file content from 1 renderedImage and csv content from another renderedImage object.
What are the possible reasons for this problem, please share your opinion.
https://cloud.githubusercontent.com/assets/228704/23704199/b79d14ba-03d1-11e7-85e4-350c48be11f6.png
I want to take out all of the things in the picture that are crossed out, here is my code below, thank you.
package pkc.trafficquest.sccapstone.trafficquest;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.Toast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
public class LogActivity extends AppCompatActivity {
private ArrayList<String> accidentList; // used for the String version of the accident list
private ArrayList<Accidents> accidents; // used for the list of type Accidents
private ListView listView;
private String csvString;
public static final int REQUEST_CODE_MAIN = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_log);
Intent logIntent = getIntent();
Bundle data = logIntent.getExtras();
// checks to see if there is data from the intent, if there is, instantiate list of names and set up the list view
if (logIntent.getExtras() != null){
accidentList = logIntent.getStringArrayListExtra("accidentList");
accidents = data.getParcelableArrayList("logAccidentList");
ListAdapter accAdapter = new ArrayAdapter<String>(this, R.layout.accident_list, accidentList);
listView = (ListView) findViewById(R.id.aListview);
listView.setAdapter(accAdapter);
csvString = createCSV(accidents); // makes a csv out of the list of accidents
}
/* // ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();*/
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.log_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) { // menu to select between downloading or emailing a csv of requested accidents
int id = item.getItemId();
if (id == R.id.action_download){ // downloads csv of requested accidents if selected
saveCSV(csvString);
}
else if (id == R.id.action_email){ // downloads and emails csv of requested accidents if selected
sendEmail(csvString);
}
return super.onOptionsItemSelected(item);
}
/*
Creates a csv file for the list of requested accidents
#param A list of accidents to create a csv for
#return the csv of requested accidents
*/
public String createCSV(ArrayList<Accidents> accList){
String csv = "";
for (int i=0; i<accList.size(); i++){ // loop through all accidents and add each detail to the csv
Accidents accident = accList.get(i); // get individual accident
csv += "\"" + accident.getPoint().getCoordinates().get(0) + ", " + accident.getPoint().getCoordinates().get(1) + "\"," + // add latitude and longitude, separated by a space to the list
"\"" + accident.getToPoint().getCoordinates().get(0) + ", " + accident.getToPoint().getCoordinates().get(1) + "\"," + // add the toPoint(where the accident ends) to the list, latitude and longitude separated with a space
accident.getDescription() + "," + // add the accident description to the list
accident.getRoadClosed() + "," + // add if road is closed (boolean value)
interpretSeverity(accident) + "," + // add severity of accident to list
interpretTime(accident.getStart()) + "," + // add the start time of accident to list
interpretTime(accident.getEnd()) + "," + // add the end time of accident to list
interpretType2(accident) + "\n"; // add the type of the accident to the list (accident, weather, hazard, etc.) and go to next line
String startTime = "Start Time: 03/08/2017";//interpretTime(accident.getStart());
String startTimeWithoutTitle= startTime.substring(startTime.indexOf(":")+1,startTime.length());
String severity = "Severity: Minor";
String severityWithoutTitle= severity.substring(severity.indexOf(":")+1,severity.length());
String cvs=startTimeWithoutTitle+","+severityWithoutTitle;
System.out.println(cvs); //just for testing
}
return csv; // return the String in csv format
}
/*
Write the file to internal storage
#param data String data to write
*/
public void saveCSV(String data) {
File file = null;
File root = Environment.getExternalStorageDirectory(); // path of root directory
if (root.canWrite()) { // checks if the application can modify the path
File dir = new File(root.getAbsolutePath() + "/AccidentData"); // new directory
dir.mkdirs();
file = new File(dir, "data.csv"); // file to be wrote to
FileOutputStream out = null;
try {
out = new FileOutputStream(file); // output stream to file location
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
out.write(data.getBytes()); // write encoded string to file
}
catch (IOException e) {
e.printStackTrace();
}
try {
out.close(); // close output stream
}
catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(getApplicationContext(), "Downloaded.", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(getApplicationContext(), "File failed to write.", Toast.LENGTH_SHORT).show(); // prints message if file does not write to file
}
}
/*
Interprets the time into a human readable format
#param t the string from the accident list to interpret
#return the converted time
*/
public String interpretTime (String t) {
String timeString = t.substring(6, t.length()-2); // gets rid of the leading and trailing slashes and parenthesis
String date; // value to return
long time = Long.parseLong(timeString); // parse the string as a long
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy 'at' HH:mm z"); // sets the format
date = sdf.format(new Date(time)); // sets the entered string as the SimpleDateFormat
return date; // return the date
}
/*
Interprets the severity codes received from the request
#param acc the accident to get the severity data from
#return the interpreted severity code
*/
public String interpretSeverity (Accidents acc) {
int severity = acc.getSeverity(); // the type code from the accident
String sevString; // the value to return
switch (severity) {
case 1: sevString = "Low Impact";
break;
case 2: sevString = "Minor";
break;
case 3: sevString = "Moderate";
break;
case 4: sevString = "Serious";
break;
default: sevString = "Incorrect value";
break;
}
return sevString; // return the severity code
}
/*
interprets what each type code means
#param acc The Accidents object to get the type code from
#return the interpreted type of accident
*/
public String interpretType2(Accidents acc){
int type = acc.getType2(); // the type code from the accident
String typeString; // the value to return
switch (type) {
case 1: typeString = "Accident";
break;
case 2: typeString = "Congestion";
break;
case 3: typeString = "Disabled Vehicle";
break;
case 4: typeString = "Mass Transit";
break;
case 5: typeString = "Miscellaneous";
break;
case 6: typeString = "Other News";
break;
case 7: typeString = "Planned Event";
break;
case 8: typeString = "Road Hazard";
break;
case 9: typeString = "Construction";
break;
case 10: typeString = "Alert";
break;
case 11: typeString = "Weather";
break;
default: typeString = "Incorrect value";
break;
}
return typeString;
}
/*
Will create an email intent, and send the requested csv file after it creates it, to the email intent.
#param data String data to send as csv
*/
public void sendEmail(String data) {
File file = null;
File root = Environment.getExternalStorageDirectory(); // path of root directory
if (root.canWrite()) { // checks if the application can modify the path
File dir = new File(root.getAbsolutePath() + "/AccidentData"); // new directory
dir.mkdirs();
file = new File(dir, "data.csv"); // file to be wrote to
FileOutputStream out = null;
try {
out = new FileOutputStream(file); // output stream to file location
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
out.write(data.getBytes()); // write encoded string to file
}
catch (IOException e) {
e.printStackTrace();
}
try {
out.close(); // close output stream
}
catch (IOException e) {
e.printStackTrace();
}
}
else {
Toast.makeText(getApplicationContext(), "File failed to write.", Toast.LENGTH_SHORT).show(); // prints message if file does not write to file
}
Uri u = null;
u = Uri.fromFile(file); // get contents of file
Intent emailIntent = new Intent(Intent.ACTION_SEND); // create an intent to send the csv
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "TrafficQuest: CSV"); // subject of email
emailIntent.putExtra(Intent.EXTRA_TEXT, "Here is a csv, as you requested."); // body of email
emailIntent.putExtra(Intent.EXTRA_STREAM, u); // add the attachment csv
emailIntent.setType("text/plain"); // sets type to plain, supports csv files
startActivity(Intent.createChooser(emailIntent, "Send email with:"));
}
public void toastMaker(String toast) {
Toast.makeText(getApplicationContext(), toast, Toast.LENGTH_SHORT).show();
}
}
I would try something like this:
String data=interpretTime(accident.getStart());
String[] parts = data.split(":");
String part1 = parts[0]; //contains the title
String part2 = parts[1]; //your data
The idea is to split the string using ":" as separator and somehow save the parts that you need.
Other way using part of your code assuming that interpretTime(accident.getStart()) is returning a string:
String startTime = interpretTime(accident.getStart());
String startTimeWithoutTitle= startTime.substring(startTime.indexOf(":")+1,startTime.length);
here you can read how substring method works substring(int,int)
I think we are missing something, all I see in the code you posted is a concatenation of the data you are getting from your accidents list. As I understand you want to take out titles from you LogActiviry that for me it means you want to display just the data without a label, if this is the case then we need the code where you set the textto the TextViews in your activity.
In other hand if you want to build a csv concatenating just the data it would be something like this:
String startTime = "Sart Time: 03/08/2017";//interpretTime(accident.getStart());
String startTimeWithoutTitle= startTime.substring(startTime.indexOf(":")+1,startTime.length());
String severity = "Severity: Minor";
String severityWithoutTitle= severity.substring(severity.indexOf(":")+1,severity.length());
String cvs=startTimeWithoutTitle+","+severityWithoutTitle;
System.out.println(cvs); //just for testing
In both cases this aproach can work
I have made Android application that download zip file from server using Android Download Manager class and then uncompress the file and store that into SD card on pictures folder. On some of the phones.
The zip file is not downloading and download manager progress bar never show progress even if I keep it for hours. Whereas on other phones this works perfectly.
The file size is 40 MB. Is there any known limitation of Android Download Manager or in case of .zip files?
I have been using a variation of (using another class for unzipping, but since the issue here is related to downloading, i am suggesting it) this class for purposes of downloading (the file name retains specific implementation, but it is just a matter of renaming accordingly...). The work() method of this class can be called from within the run method of a Runnable object for parallel threading as inferred from the initial comment:
package com.package;
/*
This class is intended to download file filtering purpose and suffix from the server.
IMPORTANT:This is intended to be instantiated within a separate thread (i.e., != UI Thread)
*/
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
final class FileDownloader
{
// Declaring a the maximum buffer size
private static final int MAXIMUM_BUFFER_SIZE = 1024;
// Declaring static final byte fields for coding the status
protected static final byte ISDOWNLOADING = 0;
protected static final byte ERROROCCURRED = 1;
protected static final byte DOWNLOADISCOMPLETE = 2;
// Declaring a private URL field for storing the file for downloading
private java.net.URL url = null;
// Declaring a private int field for storing the file size in bytes
private int filesize;
// Declaring a private int field for storing the amount of downloaded bytes
private int bytesDownloaded;
// Declaring a private byte field for storing the current status of the download
private byte currentStatus;
// A private static final string for storing the server contents location
private static final String SERVER = "https://server.com/zipfiles/";
// Declaring a private field for storing the caller context, used for defining
// the path for saving files
private android.content.Context callerContext = null;
// The following rule is going to be applied for distributing purpose and their contents:
// 'purpose.x.zip' zip file to store the folders of the the x purpose_id and its inherent
// structure
private static final String PURPOSE= "purpose";
private String x = null;
private static final String SUFFIX = "zip";
// The remote file to be downloaded is going to be [stringed as]:
// SERVER + PURPOSE + "." + ((String.valueOf(x)).trim()) + "." + suffix
private String remoteFile = null;
// Defining a private static final File field for storing the purposes' contents within it.
// Specifically, this is being designed to be:
// java.io.File seekingRegisteredUserFolder =
// new java.io.File(callerContext.getFilesDir(), "RegisteredUser");
private final java.io.File seekingRegisteredUserFolder;
// The class constructor. The constructor depends on constructing elements for downloading
// the remoteFile respective to the element_ [cf. constructor parameter] under consideration,
// viz.:
protected FileDownloader(final String x_, final android.content.Context callerContext_)
throws
java.net.MalformedURLException,
java.io.FileNotFoundException,
java.lang.SecurityException
{
this.x = x_;
this.remoteFile = SERVER + PURPOSE + "." + ((String.valueOf(this.x)).trim()) + "." + SUFFIX;
int parsedW = 0;
try
{
parsedW = Integer.parseInt(x_);
}
catch (Exception throwableThrownParsingW)
{
throw new java.net.MalformedURLException();
}
// Implementation specific
if (parsedW < 1)
{
throw new java.net.MalformedURLException();
}
this.callerContext = callerContext_;
this.seekingRegisteredUserFolder = new java.io.File((this.callerContext).getFilesDir(), "RegisteredUser");
if (!((this.seekingRegisteredUserFolder).exists()))
{
throw new java.io.FileNotFoundException();
}
this.url = new java.net.URL(this.remoteFile);
this.filesize = -1;
this.bytesDownloaded = 0;
this.currentStatus = ISDOWNLOADING;
}
// Begins the file download. This is to be called under an object of this class instantiation
boolean work()
{
final java.io.RandomAccessFile[] randomAccessFile = {null};
final java.io.InputStream[] inputStream = {null};
final java.io.File[] purpose = {null};
try
{
purpose[0] = new java.io.File(seekingRegisteredUserFolder, (PURPOSE + "." + x + "." + SUFFIX));
// Opens a connection to the URL via ssl
final javax.net.ssl.HttpsURLConnection[] connection = {null};
connection[0] = (javax.net.ssl.HttpsURLConnection) url.openConnection();
// Defines the file part to download
connection[0].setRequestProperty("Range", "bytes=" + bytesDownloaded + "-");
// Connects to the server
connection[0].connect();
// The response code must be within the 200 range
if ((connection[0].getResponseCode() / 100) != 2)
{
currentStatus = ERROROCCURRED;
}
// Inferring the validity of the content size
final int[] contentLength = {0};
contentLength[0] = connection[0].getContentLength();
if (contentLength[0] < 1)
{
currentStatus = ERROROCCURRED;
}
// Configuring the download size, case not yet configured
if (filesize == -1)
{
filesize = contentLength[0];
}
// Opens the file, seeking its final
randomAccessFile[0] = new java.io.RandomAccessFile(purpose[0], "rw");
randomAccessFile[0].seek(bytesDownloaded);
inputStream[0] = connection[0].getInputStream();
while (currentStatus == ISDOWNLOADING)
{
// Defines the buffer according to the left amount of file to complete
byte[] byteBuffer = null;
if ((filesize - bytesDownloaded) > MAXIMUM_BUFFER_SIZE)
{
byteBuffer = new byte[MAXIMUM_BUFFER_SIZE];
}
else
{
byteBuffer = new byte[filesize - bytesDownloaded];
}
// Reads from server to the buffer
int read = inputStream[0].read(byteBuffer);
if (read == -1)
{
break;
}
// Writes from buffer to file
randomAccessFile[0].write(byteBuffer, 0, read);
bytesDownloaded += read;
}
// Changing the status for complete since this point of code has been reached
if (currentStatus == ISDOWNLOADING)
{
currentStatus = DOWNLOADISCOMPLETE;
}
}
catch (java.lang.Exception connectionException)
{
currentStatus = ERROROCCURRED;
}
finally
{
// Closes the [RandomAccessFile] file
if (randomAccessFile[0] != null)
{
try
{
randomAccessFile[0].close();
}
catch (java.lang.Exception closingFileException)
{
currentStatus = ERROROCCURRED;
}
}
if (inputStream[0] != null)
{
try
{
inputStream[0].close();
}
catch (java.lang.Exception closingConnectionException)
{
currentStatus = ERROROCCURRED;
}
}
}
if ((currentStatus == DOWNLOADISCOMPLETE) && (purpose[0] != null) &&
(purpose[0]).isFile() && (purpose[0].length() > 0) && (purpose[0].length() == filesize))
{
((AppCompatActivity) callerContext).runOnUiThread
(
new Runnable()
{
#Override
public final void run()
{
Toast.makeText(callerContext, "Downloaded: " + remoteFile.substring(remoteFile.indexOf(SERVER) + SERVER.length()), Toast.LENGTH_LONG).show();
}
}
);
return true;
}
return false;
}
}
I am trying to parse some unsigned integers from a file stored on the memory card.
Since java does not provide unsigned types I use longs to store the obtained values.
The performance seems to be influenced by the Debugger:
Without the debugger connected I can parse 20000 values in ~820ms.
With the debugger ~5800ms (on HTC Desire).
Can you reproduce this on your devices? Any clue why the debugger has such an overhead?
Here is the code:
public class IntParsingTest extends Activity {
public static final String TEST_FILE = "yourfile";
public static final int LOOPS = 20000;
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Toast.makeText(IntParsingTest.this, (CharSequence) msg.obj, Toast.LENGTH_LONG).show();
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
Runnable r = new Runnable() {
#Override
public void run() {
Message m = new Message();
File path = Environment.getExternalStorageDirectory();
File f = new File(path, TEST_FILE);
long startTime = SystemClock.currentThreadTimeMillis();
try {
InputStream is = new FileInputStream(f);
for (int i = 0; i < LOOPS; i++) {
readUnsignedInt(is);
}
long total = SystemClock.currentThreadTimeMillis() - startTime;
m.obj = "Time to parse\r\n"
+ LOOPS
+ " unsigned integers:\r\n"
+ total + " ms";
handler.sendMessage(m);
} catch (Exception e) {
m.obj = e.getMessage();
handler.sendMessage(m);
}
}
};
new Thread(r).start();
} catch (Exception e) {
}
}
public static long readUnsignedInt(InputStream input) throws IOException {
long b1 = input.read();
long b2 = input.read();
long b3 = input.read();
long b4 = input.read();
return (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;
}
}
Edit: It is also interesting that only the shift opperations are slow. If I return one of the bytes or a sum of them it works much faster. It may be the way shift is implemented !?
I'm guessing here - with debugger connected JVM cannot do just-in-time compilation; to be able to detect breakpoints it has to do bytecode interpretation all the time. Debugger also connects to device log stream, which may cause some overhead.