System.currentTimeMillis() behaving erroneously - java

I'm creating a text file with timestamps derived from the result of System.currentTimeMillis(). My algorithm is such:
Create file and record timestamp of creation
Save timestamp each time a button is pressed
Subtract file-creation timestamp from button-press timestamp
Write result to the file
For some odd reason, the timestamp of the file creation is usually greater (younger, more recent) than the timestamp of the button presses, which always happen AFTER the file was created. This results in a negative value being returned from step 3.
What is causing this?
FileCreationMenu.java
public class FileCreationMenu extends Fragment {
public Button toggleRecordingButton;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.menu_fragment_calibrator, container, false);
toggleRecordingButton = (Button) v.findViewById(R.id.recordAudioToggle);
toggleRecordingButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
recordAudio = !recordAudio; //toggle audio recording on/off
if (recordAudio==true){
AudioRecorder.createFile(System.currentTimeMillis()); //generate file for new track if record is togged ON
}
}
});
AudioRecorder.java
public static void createFile(long time) { //create file and record creation timeStamp
recordingStartTime = time;
myFile = new File(Environment.getExternalStorageDirectory(), "file.txt"); //save to external storage
try {
myFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void recordNote(long timeStamp){ //record timeStamps of notes
String playedNote = (timeStamp+ "\n" );
try {
fos = new FileOutputStream(myFile, true);
fos.write(playedNote.getBytes());
fos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void playTrack(String fileName){ //playback Notes
try {
FileInputStream fis = new FileInputStream(myFile.getPath());
BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
String line;
try {
int i =0;
while ((line = reader.readLine()) != null) { //read each line of input file
historicalTime[i] = Long.parseLong(line); //store time current line's note was played
if (i==0){
timeStream[i] = (Long.parseLong(line) - recordingStartTime); //if first note, calculate wait based on file creation time
}
else{
timeStream[i] = (Long.parseLong(line) - historicalTime[i-1]); //otherwise, calculate wait as amount of time note was played after most recent preceding note
}
i++;
}
} catch (IOException e){
e.printStackTrace();
}
for (int i=0; i<noteStream.length; i++){
try {
AudioRecorder.class.wait(timeStream[i]); //wait
//Play Note
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
MainActivity.java
...
public static void noteDetected(){
if (FileCreationMenu.recordAudio == true){
AudioRecorder.recordNote(System.currentTimeMillis());
}
Again, the problem is that recordingStartTime in AudioRecorder.java is often greater than the input parameter "timeStamp" to recordNote from the MainActivity. For example, in a recent debugging session recordingStartTime =1,450,573,093,044 while timeStamp=1,450,565,187,318.
What could be causing this seemingly impossible behavior?

The problem is this line:
myFile.createNewFile();
The JavaDoc for this method says
Atomically creates a new, empty file named by this abstract pathname if and only if a file with this name does not yet exist
So every time you try to start a new recording you are actually reusing the same file (with timestamps from long ago) but record a new recordStartTime.
If you want to remove the old file first you will have to write
myFile.delete();
myFile.createNewFile();

Related

Weird bug whilst making android app

So I'm trying to make my first ever Android app. It's just a simple tally counter for now but I've come across a weird bug.
You see, I've got a simple save and load function, an increment, decrement and reset button. and a TextView that displays the value all together (see below).
Now when I increment the value up to say 10 and close the app, it saves as it should and when I open the app again, it does come back as 10. However, when I then increment up to say 30 or 100, close and restart the value does not stick and comes out as either -1 or a value that is completely different.
What could be happening?
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
int value;
TextView textView_value;
final String filename = "tallyCountPlus";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadValue(filename);
textView_value = (TextView) findviewById(R.id.textView_value);
textView_value.setText(Integer.toString(value));
}
/** Called when the user presses the increment button */
public void incValue(View view) {
value++;
textView_value.setText(Integer.toString(value));
}
/** Called when the user presses the decrement button */
public void decValue(View view) {
if (value > 0) {
value--;
}
textView_value.setText(Integer.toString(value));
}
/** Called when the user presses the reset button */
public void resetValue(View view) {
value = 0;
textView_value.setText(Integer.setString(value));
}
#Override
public void onPause() {
super.onPause();
saveValue(filename, Context.MODE_PRIVATE);
}
#Override
public void onResume() {
super.onResume();
loadValue(filename);
textView_value.setText(Integer.toString(value));
}
public void onDestroy() {
super.onDestroy();
saveValue(filename, Context.MODE_PRIVATE);
}
private void loadValue(String name) {
try {
FileInputStream fis = openFileInput(name);
value = fis.read();
fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void saveValue(String name, int context) {
try {
FileOutputStream fos = openFileOutput(name, context);
fos.write(value);
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Anyone know what my problem could be?
Thanks.
Jamie.
EDIT:
So I think I've fixed the bug by doing:
private void loadValue(String filename) {
/* this is wrapped in a try-catch statement */
FileInputStream fis = openFileInput(name);
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
StringBuilder = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
value = Integer.parseInt(sb.toString());
fis.close() /* Not sure if this is actually neccessary? */
if (value == -1) {
value = 0;
}
}
private void saveValue(String name) {
/* This is also wrapped in a try-catch statement */
FileOutputStream fos = openFileOutput(name, Context.MODE_PRIVATE);
String data = Integer.toString(value);
fos.write(data.getBytes());
fos.close();
}
And after putting in a couple of values, it seems to work fine. However, I'm unsure as to whether it is appending or deleting the previous value and replacing it... I'd rather the latter to prevent the save file from getting too big.
onDestroy() is not dependable. Just stick with onPause(). Also, in general, for the methods that handle events when the activity is "going away", you should call the super method after your own code, to ensure your custom code can still execute.
Other things to check might be:
Is the method that saves the output replacing the previous file, or just appending to it?
Are you properly loading and saving each time?
If the file is properly loaded, is the value making it into the TextView? You might need to construct an anonymous Runnable that ensures that the TextView is updated by the main (UI) thread.
Sprinkle log statements liberally throughout the code to keep track of what the tally is, what you get out of the file, etc.
When diagnosing file issues, it helps to test on an emulator, which gives you root access to the device storage.
You need to modify loadValue() method. You are assigning fis.read() to value which returns next byte or -1 if EOF reached.
private void loadValue(String name) {
try {
FileInputStream in = openFileInput(name);
InputStreamReader inputStreamReader = new InputStreamReader(in);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
StringBuilder sb = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
}
value = Integer.parseInt(sb.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

java xmlpull parse random string from XML

I'm very new to Android programming and I'm trying to figure out how to get strings from a file and display those strings on buttons randomly.
The goal is to make a multiple choice test with randomly generated questions (based on a database) and keep track of the user's correct and incorrect answers (but I'm far from that part).
I watched an xmlpull tutorial which showed me how to pull a section of every line in the document and I tried to adapt it to pull a section of one line. Here's what I have:
String item;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_layout);
try {
item = getItemFromXML(this);
} catch (XmlPullParserException e) {
} catch (IOException e) {
}
String[] items = item.split("\n");
setListAdapter (new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items));
}
public String getItemFromXML(Test test) throws XmlPullParserException, IOException {
StringBuffer stringBuffer = new StringBuffer();
Resources res = test.getResources();
XmlResourceParser xpp = res.getXml(R.xml.database);
xpp.next();
int eventType = xpp.getEventType();
for (int sCount = 0; sCount<1; sCount++) {
if (eventType ==XmlPullParser.START_DOCUMENT)
if (eventType == XmlPullParser.START_TAG) {
if (xpp.getName().equals("character")) {
stringBuffer.append(xpp.getAttributeValue(null, "english") + "\n");
}
}
eventType = xpp.next();
}
return stringBuffer.toString();
}
The XML file looks kind of like this:
<root id="kanji">
<characters>
<character english="one" grade="1"/>
How can I make this work to pull a value from a random line?

audiotrack, how to skip wave header noise?

I'm creating an app that plays .wav files by audiotrack class in static mode, but i can't figure out how to skip the wave header, here is the code i've done so for, i cant see whats wrong with it! anyone knows how to skip the header?
Thanks!
public class MainActivity extends ActionBarActivity {
AudioTrack player;
int minBufferSize = 200000;
int waveHeader = 44;
byte[] buffer = new byte[minBufferSize -waveHeader];
InputStream is;
public TextView text;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);
player = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STATIC);
is = getResources().openRawResource(R.raw.crash);
try {is.read(buffer, waveHeader, minBufferSize);} catch (IOException e) {e.printStackTrace();}
try {is.close();} catch (IOException e) {e.printStackTrace();}
player.write(buffer, 0, minBufferSize);
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
playDrums();
}});
}
public void playDrums(){
player.play();
}
}
As indicated in read documentation:
The first byte read is stored into element b[off], the next one into b[off+1], and so on. The number of bytes read is, at most, equal to len. Let k be the number of bytes actually read; these bytes will be stored in elements b[off] through b[off+k-1], leaving elements b[off+k] through b[off+len-1] unaffected.
In other words the parameter off does not skip those bytes from the input stream, but instead stores them with an offset in the provided array.
To skip bytes from the input, you can either use skip:
try {is.skip(waveHeader);} catch (IOException e) {e.printStackTrace();}
try {is.read(buffer, 0, minBufferSize);} catch (IOException e) {e.printStackTrace();}
Or read the wave header in another buffer:
byte[] header = new byte[waveHeader];
try {is.read(header);} catch (IOException e) {e.printStackTrace();}
try {is.read(buffer, 0, minBufferSize);} catch (IOException e) {e.printStackTrace();}
After all you probably need the wave header in order to properly interpret the data (eg. is the data 1 or 2 bytes per sample, sampling rate, number of channels, ...)

How to save and load state of a GridView in Android

I am making a simple game that uses GridView and a custom Adapter. It is basically a game that player can move through the GridView (simply changing the images of cells). The game has 10 levels. Problem is, when I get out of the activity (e.g. going back to the MainActivity) the game is reset. Also naturally when phone is turend off and on the game is reset.
I want to preserve the game state so when the player enters the GameActivity, he/she can continue with the game.
I only require 3 things to be saved, the Adapter, number of Level and the available moves. Simply if I knew how to work this out I could achieve what I need:
public class GameState implements Serializable {
private GameAssetAdapter mAdapter;
private int mLevel;
private int mAvailableMoves;
public GameState(GameAssetAdapter adapter, int level, int availableMoves) {
mAdapter = adapter;
mLevel = level;
mAvailableMoves = availableMoves;
}
public GameAssetAdapter getAdapter() {
return mAdapter;
}
public int getLevel() {
return mLevel;
}
public int getAvailableMoves() {
return mAvailableMoves;
}
}
So the question is, how can I save this object to internal storage and retrive it back when necessary?
I already have tried the onSaveInstanceState but it does not work as expected. phone off/on will reset this. Even if user wipes the app in the app list of android it will be reset. What should I do?
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable(AppConstants.GAME_SAVE_ASSET_ADAPTER, mGameAssetAdapter);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
if(savedInstanceState != null)
{ //Restore mGameAssetAdapter if was saved perviously
if(mGameAssetAdapter == null){
restoreGameAssetAdapter(savedInstanceState);
}
}
//TODO get level and states!!
mGameGridView = (GameGridView)findViewById(R.id.game_grid_view);
mGameGridView.setNumColumns(GameConstants.COLUMNS);
mGameGridView.setColumnWidth(GameHelper.getOptimumAssetImageWidth(this,
GameConstants.COLUMNS));
if(mGameAssetAdapter == null) {
mGameAssetAdapter = new GameAssetAdapter(this, mLevel);
}
mGameGridView.setAdapter(mGameAssetAdapter);
this.setTitle("Snakes and Ladders - Level " + mLevel);
setupEvents();
}
private void restoreGameAssetAdapter(Bundle savedInstanceState) {
if(savedInstanceState.getSerializable("GAME_ASSET_ADAPTER") != null){
mGameAssetAdapter =
(GameAssetAdapter) savedInstanceState.
getSerializable("GAME_ASSET_ADAPTER");
Log.v(TAG, "Restored saved GameAssetAdapter! Hoooray!");
}
}
You can just write the state to storage. Here is some code from my personal stash:
private static byte[] readBytes(String dir, Context context) throws IOException
{
FileInputStream fileIn = null;
DataInputStream in = null;
byte[] buffer = null;
fileIn = context.openFileInput(dir);
in = new DataInputStream(fileIn);
int length = in.readInt();
buffer = new byte[length];
for(int x = 0;x < buffer.length;x++)
buffer[x] = in.readByte();
try
{
fileIn.close();
} catch (Exception e) {}
try
{
in.close();
} catch (Exception e) {}
fileIn = null;
in = null;
return buffer;
}
private static void writeBytes(String dir, byte bytes[], Context context) throws IOException
{
FileOutputStream fileOut = null;
DataOutputStream out = null;
fileOut = context.openFileOutput(dir, Context.MODE_PRIVATE);
out = new DataOutputStream(fileOut);
int length = bytes.length;
out.writeInt(length);
out.write(bytes);
out.flush();
try
{
fileOut.close();
} catch (Exception e) {}
try
{
out.close();
} catch (Exception e) {}
}
You can save your state by using the writeBytes() method, then when the app is relaunched, all you have to do is use readBytes() to restore the game state.
If I may make one small structural suggestion, I like to make a 'package' class that holds my state variables when I write it to disk like this:
public class SavedState implements Serializible
{
public GameState state;
int id;
...
}
Then when you write this to disk, you will have all of your state variables in one clean class. I would also recommend not saving your DisplayAdapter for your list view (you might have a lot of problems) or whatever it is. Save the underlying data structure to this package class and then create a new DisplayAdapter when you resume the app state.
If you don't know how to turn an object into a byte array, here is the SO question for it:
Java: object to byte[] and byte[] to object converter (for Tokyo Cabinet)

Java- Error with Eclipse reading excel file

I'm new to java, but a quick learner.
I'm trying make my Android App to take user-input from an EditText, search an Excel column for a matching string, and return the value of (the same row of) another column.
I added a jxl.jar on the build path, and my code seems like it should work. Teaching myself, I am slowly figuring out the debugging. The problem seems to be source android.jar was not found (if i remember correctly). I located it, and now I get "the source attachment does not contain the source for the file instrumentation.class"
This is my first app using excel. Do I need to address the Android Manifest somehow?
Here's my code, just in case, and any help is very appreciated!:
public class Frame_Bore extends Activity {
private String inputFile;
public void setInputFile(String inputFile) {
this.inputFile = "c:/Desktop/AAS Work/PDA Programs/JBDB.xls";
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.framebore);
Button Btn1 = (Button) findViewById(R.id.button1);
final EditText T1 = (EditText) findViewById(R.id.et1);
final EditText T2 = (EditText) findViewById(R.id.et2);
Btn1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
String t1Value = T1.getText().toString();
File inputWorkbook = new File(inputFile);
Workbook w;
String bore = null;
try {
w = Workbook.getWorkbook(inputWorkbook);
Sheet sheet = w.getSheet("Frame-Bore");
int y = 6;
while (y < 200) {
int x = 2;
Cell columnB = sheet.getCell(x, y);
String motorframe = columnB.getContents();
if (motorframe == t1Value) {
Cell columnC = sheet.getCell(x + 1, y);
bore = columnC.getContents();
} else {
y = y + 1;
}
}
} catch (BiffException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
T2.setText("" + bore);
}
}
});
}
You are trying to access c: drive ( "c:/Desktop/AAS Work/PDA Programs/JBDB.xls" ) from your emulator, which is not possible. You need to put your excel file either in the resources folder or in SD card, if you are running it in device.
An Emulator has a virtual SD Card, and its limitations is that it can not direct access any other drive from the computer. However you can do it by making a webservice which will perform operation on behalf of your android application. You need to call this web-service from your android application.
Put the file in assets folder and access it like this:
InputStream is = null;
try {
is = context.getAssets().open("JBDB.xls");
workbook = Workbook.getWorkbook(is);
} catch (IOException e) {
e.printStackTrace();
} catch (BiffException e) {
e.printStackTrace();
}
if(workbook!=null)
sheet = workbook.getSheet("Frame-bore");
context is your main activity context.

Categories