I am trying to write a code for an application that displays the values of the magnetometer sensor and save these data in a file.
I wrote the following code but the problem is in my file I find only one line containing the last values.
FloatingActionButton fab;
fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener( new View.OnClickListener(){
#Override
public void onClick(View view){
final Thread t = new Thread() {
File openfilename= new File(Environment.getExternalStorageDirectory(),"myfile.txt");
FileOutputStream f;
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(500);
runOnUiThread(new Runnable() {
#Override
public void run() {
TextView tv;
tv=(TextView)findViewById(R.id.tv);
tv.setText(" x="+Float.toString(xx)+" y="+Float.toString(yy)+" z="+Float.toString((zz))+" Puissance="+Float.toString(magneticStrenght));
try {
FileOutputStream f =new FileOutputStream(openfilename);
PrintWriter pw=new PrintWriter(f);
pw.append("\n x="+Float.toString(xx)+" y="+Float.toString(yy)+" z="+Float.toString((zz))+" Puissance="+Float.toString(magneticStrenght));
//close the file
pw.flush();
pw.close();
f.close();
} catch (java.io.IOException e) {
//do something if an IOException occurs.
Log.e("Exception", "File write failed: " + e.toString());
}
}
});
}
} catch (InterruptedException e) {
}
}
};
t.start();
Can you please try to help and see what is wrong with my code.
You should open the FileOutputStream in append mode, by passing a boolean true as the second parameter
FileOutputStream f = new FileOutputStream(openfilename, true);
See this for more details
As documented here you should use this constructor to open the file in append mode :
FileOutputStream fStream = new FileOutputStream(fileName, true);
As you've not used the append flag while creating the FileOutputStream object, you're overwriting the previous data in the file everytime you're opening and writing it.
There's nothing wrong with the other answers but the problem with the code stems from certain logic errors and omissions.
It seems you have some things conceptually wrong. At what point are you trying to write the text out to file? You seem to be creating a loop and within that loop, you create a text file on each iteration where data is written to the file.
This will always result in the problem you've described.
Step back, think about the logic here and then place the file writing code into a separate function. Call that function only when you want the data to be saved (for example; when leaving the textview, tapping a button on the activity, or some other useful time).
Calling the write procedure should happen only once you have finished collecting your data but before the activity is off screen. As written your logic may even be creating multiple files and always writes only one line of code to that file. Given your specific task, you might want to try using a StringBuffer and output it's content to file. Searching SO and Google will give you tons of examples.
It's unclear why you are showing the data in a textview so you may want to capture that data independently of a textview and show what is needed only when necessary.
Related
I'm working on an app that goes through all of the phone directories, and collecting all the songs.
When i run it normally it works fine, just takes about 6 seconds to go through everything, and causes the app to skip a lot of frames.
I changed it so every time a file is found, a different thread reads the metadata and saves it.
I'm also waiting for all of them in the end, because after that I'm trying to use that list.
All of a sudden several of the song are null, even though they're not initialized as such anywhere.
What can cause that? an app that works fine, but not with threads..?
the constructor that calls the search:
phoneSongsList = new Playlist();
findSongs(Environment.getExternalStorageDirectory().getAbsolutePath()); //.concat("/Music")
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
The function that recursively looks for songs:
public void findSongs(String path) {
File home = new File(path);
for (final File file : home.listFiles()) {
if (file.isDirectory())
findSongs(path.concat("/" + file.getName()));
else if (isAcceptableExtension(file.getName())) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
phoneSongsList.add(fileToSong(file));
}
});
t.start();
threads.add(t);
}
}
}
The function that converts the file to a song object:
private Song fileToSong(File file) {
final Album album = new Album();
Song song = new Song();
song.setName(file.getName().substring(0, (file.getName().length() - 4))); // remove suffix
song.setPath(file.getPath());
final MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
metaRetriever.setDataSource(file.getPath());
song.setArtists(metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST));
album.setName(metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM));
album.setYear(metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR));
album.setCover(metaRetriever.getEmbeddedPicture(), context);
song.setAlbum(album);
song.setDuration(Long.parseLong(metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)));
song.setGenre(metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE));
metaRetriever.release();
return song;
}
The Playlist.add function:
public void add(Song song) {
add(list.size(), song);
}
public void add(int index, Song song) {
if(song==null)
return;
if (index > list.size())
index = list.size();
if (list.contains(song))
list.remove(song);
list.add(index, song);
}
Even when i explicitly specify that no null objects would be added to the list, it runs fine when it saves the songs, but give a null error when trying to read.
Each time i run different songs and a different number of songs are set to null.
Please help.
You're dynamically trying to add new Threads to the list of threads on other threads, but reading that thread on one thread. That means you'll finish the loop on some subset of those threads before all of them are added. This entire approach is one big race condition.
This isn't something threads are going to speed up much, and you're doing your threading all wrong anyway. Throw this out and just do it on a single background thread, and do not join on that thread (or you may as well do it sequentially)- have it post back to the main thread when done.
I've got a thread in a for loop to download some files from a http server reading the file names in an array list.
I need to launch several times the thread to get all the files, it seems that some threads don't achieve but with no rules at all.
I would like to launch the threads in order to see if each task works fine and optionally do something if not.
here's my code
for(String object:stringArrayList_dwlfromex){
try {
//String result = stringArrayList_dwlfromex.get(k);
String result = String.valueOf(object);
String[]row=result.split(";");
imei = row[4].toString();
dir = row[1].toString();
filename = row[2].toString();
compteur++;
//Toast.makeText(getApplicationContext(),dir+"&"+filename,Toast.LENGTH_SHORT).show();
Toast.makeText(getApplicationContext(),compteur+" "+result,Toast.LENGTH_SHORT).show();
new Thread(new Runnable() {
public void run() {
DownloadFiles(imei,dir,filename);
}
}).start();
}catch (Exception e) {
e.printStackTrace();
}
}
any idea?
I never see any workaround like you did.
You will have to make a service with AsyncTask. You will not use for loop.
Solution is to download another file when one is downloaded. You have to set a interface callback when a file is downloaded. and execute next download after this. Also destroy service when executed files size is equal to your list.
I'm trying to figure out a good way to give my services a preference file, like the SavedInstanceState of an activity. This service starts, sets an alarm, and calls stopSelf();, because it may be days before it runs again, I want it to start, do its task, then be done. I'm just going to same some key/value pairs in a comma separated text file.
OK, so I want to open the FileInputStream provided by Context, but I have to handle the exception. I'd rather check to be sure the file exists first to avoid the error, and in case a large list of files is returned I want to do this work off the UI thread. Here is my code:
public void setNewAlarm() {
Log.d("alarmServ", "inside setNewAlarm()");
FileInputStream fis;
Time time = new Time();
Boolean prefsAvail = false;
String[] fileList = fileList();
Runnable fileCheck = new Runnable() {
public void run() {
int i = 0;
while (i<fileList.length) {
if (fileList[i] == "preferences") {
prefsAvail = true;
break;
}
i++;
}
if (prefsAvail) {
try {
fis = openFileInput("preferences");
} catch (FileNotFoundException ioe) {
Log.d("alarmServ", "i/o error: output file fail");
ioe.printStackTrace();
}
}
}
};
//do something with the InputStream - read prefs and build alarm based on the criteria
}
The problem then, obviously, is the FileInputStream, boolean, and String[] are not available inside the runnable. How can I work around this, my understanding was that nested classes had access to their container's variables. Is this not true because its declared inside a method?
I tried googling, and discovered that one way to do this would be to declare the data as final, but this doesn't seem appropriate for a boolean or the stream.
If you need just to save key/value pairs I would suggest you using SharedPreferences, this is a preferred Android way.
Also if you intended to use files I would suggest you just to run it on the worker thread, that way you won't need to share your FileInputStream, boolean, and String[] between threads.
P.S. to use reference inside anonymous inner class, you have to define it as final.
I am creating an app that involves reading data from text files that are in the Assets folder. For each file, it stores the data in a separate ArrayList. The files are read in one after another in the onCreate() method of the activity. All of the text files combined total 1.8 MB and on the emulator it currently takes 12 seconds for the activity to load. The app does not crash on the emulator (it just takes approx 12 seconds).
I have read about asynchronous threads, but I have never had a need for them in the past. I was planning on having some sort of message or progress bar to notify the user that the activity is in fact loading and has not crashed.
So my question is: even though the app does not crash when loading the activity, should I still put the reading of the files on an asynchronous or different thread? If so, how would I go about doing it properly? (I have never done it before.)
Here is sample code with the reading of the text files:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_name);
populateArrayLists();
}
public void populateArrayLists() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(getAssets().open(
"text1.txt")));
String text;
while ((word = br.readLine()) != null) {
ArrayList1.add(text);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close(); // stop reading
} catch (IOException ex) {
ex.printStackTrace();
}
}
br = null;
try {
br = new BufferedReader(new InputStreamReader(getAssets().open(
"text2.txt")));
// the same process is duplicated for 1-15
// it may not be the best or most efficient way but it works
Any help would be appreciated.
Yes, you'll need a background thread for this. The Loader api may be your easiest bet.
This will allow you at least display a notice and offer some content while the files load. Maybe even load them and incrementally displaying the data, if that's what you're doing.
Edit: Loaders are a 3.0 feature available in the compatibility library. If you're not willing to add the dependency, you can always fall back to AsyncTask, in which case you could take a look at this.
ive been thinking about this for hours and im not closer to an solution!
My thread just stops looping when im fetching a message from an server for some reason, and works perfectly when im not doing it.
This works and prints refreshing every second:
public class ChatRoom extends Activity implements OnClickListener, Runnable {
private Thread t = new Thread(this);
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chatroom);
Button send = (Button) findViewById(R.id.send);
send.setOnClickListener(this);
Intent receiver = getIntent();
String host = receiver.getStringExtra("Host");
int port = receiver.getIntExtra("Port", 4456);
try
{
socket = new Socket(host, port);
this.receive = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
this.send = new PrintWriter(this.socket.getOutputStream(), true);
}
catch(IOException ioe) { System.out.println(ioe); }
t.start();
}
public void run()
{
String message = "";
while(true)
{
try
{
// message = receive.readLine(); BufferedReader
t.sleep(1000);
}
//catch(IOException ioe) { System.out.println(ioe); }
catch (NullPointerException npe) { System.out.println(npe); }
catch (InterruptedException e) { System.out.println(e); }
System.out.println("Refreshing...");
}
}
And when i use my commented code, it actually works and i get a message from the server but it loops just once! Why is that?
Output:
Server Message
Refreshing...
I get no Exception or errors, but i had an error before with some similar code that said that i cant change UI on other threads. So ive been looking at some runOnUiThread but it didnt make it better, and i dont know why it should :(
The method BufferedReader.readLine() blocks until a newline character is received. If there is no newline in your receiver stream it will block forever.
A few things here:
Swap from System.out.println("string"); to Log.d("tagname","string"); then look on DDMS for output lines.
I don't think you're creating a thread properly, and you certainly aren't providing any interface to kill it, which may cause issues when you test it. I would separate the thread into a new file, say NameOfThread:
//File "NameOfThread"
public class NameOfThread extends Thread{
//any fields you want here to mess with e.g.
private String message;
private boolean running;
public NameOfThread(){
message = "";
running = true;
}
#Override
public void run(){
while(running){
//do stuff
}
}
public void setRunning(boolean run){
running = run;
}
}
//When you want to call it
NameOfThread varThread = new NameOfThread();
varThread.start();
//when you want to kill the thread
varThread.setRunning(false);
You may think 'why bother with this whole running variable junk, I don't need it.' but how else will this thread end gracefully? There is another method of killing the thread properly, which is using InterruptedException and your cleanup code goes there, but that's just an alternative.
Try doing this first, then you'll need to sort out the message itself (the method you're using currently isn't great since readLine() will block until a line is received (meaning you'll get "Refreshing..." when you get a new line rather than once per second.
You're surely getting some exceptions thrown, you just can't see them cause you're trying to print them on the standard output, which is missing on Android. Your exception is handled correctly and the code finishes. To properly get the exception information use Logs, or just throw a RuntimeException. Hope this helps.