i am new in "programming thing , try to learn .
my "app" run bat test files , and all result printed in the textarea , it's working good.
but my goal now is to present progress bar that will show the progress while printing into the text area.
how can i do it ? I've read some guides and I tried somethings but it doesn't work for me
this is the method behind the button that run the bats files
public void RunTestScrip() throws IOException {
Process p = Runtime.getRuntime().exec(path);
final InputStream stream = p.getInputStream();
new Thread(new Runnable() {
public void run() {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(stream));
String line = null;
while ((line = reader.readLine()) != null) {
console.appendText("\n" + line);
progressBar.progressProperty().bind(RunTestScrip()); // dont know how to use it right in my code
}
} catch (Exception e) {
// TODO
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// ignore
}
}
}
}
}).start();
I dont think the script is able to update a javafx ProgressBar. The easiest way is to create your own rules about progress (probably based on the output you are currently appending to the console).
Here is a nice tutorial on how to create a working Progressbar in javafx. Hopefully you are able ro figure out a way to update the progress accordingly.
Edit:
I added a small example of what can be found in the tutorial in case the provided link breaks.
// initialization of a progressBar with 'indeterminate progress'
ProgressBar pb = new ProgressBar(-1.0D);
// to set the current state of a progress bar you simply do the following
pb.setProgress(current_progress);
Note that progress is a value between 0.0D and 1.0D (e.g. in percentage).
A value of -1.0D indicate that the progress is indeterminate.
Related
For my activities to work, I have to get data from the internet.
I implemented threads, but I am not that good with Java or threads yet, so I kinda rushed through it just hoping it would work. Well it works, but the UI feels slow sometimes because it takes awhile until the activity appears.
Here is my code
an activity, lets call it MainActivity calls:
JSONObject Data = WebApi.getData(id);
the class WebApi pieces the url together:
public static JSONObject getData(String id) {
String url = URL;
url += DATA_URL;
url += VALUE_DATA_ID + id;
return WebInterface.executeWeb(url);
}
and hands it over to WebInterface, in WebInterface the whole thing gets executed:
public static String getUrl(final String url) {
final StringBuilder sb = new StringBuilder();
Thread thread = new Thread(new Runnable() {
public void run()
{
try
{
InputStream is = (InputStream) new URL(url).getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String result, line = reader.readLine();
result = line;
while((line=reader.readLine())!=null){
result+=line;
}
sb.append(result);
} catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
}
}
});
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String result = sb.toString();
Log.d(App.TAG, result);
return result;
}
public static JSONObject executeWeb(final String url) {
String result = WebInterface.getUrl(url);
JSONObject json = null;
try {
json = new JSONObject(result.trim());
} catch (JSONException e) {
try {
json = new JSONObject("{}");
} catch (JSONException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
return json;
}
well this works but i feel like this would work even better, if I would implement it with ASyncTask. My Activity could show some cached data until the "real" data appears. Would that be possible with AsyncTask? And would I need to redo a lot of my code for that?
thanks in advance for the help!
Edit:
thanks to whoever suggested AsyncTaskLoader (i think that one deleted his answer)
I did it with AsyncTaskLoader, very handy and very easy!
In effect your code is single threaded because of thread.join(). The current thread just waits for the newly spawned thread to finish. You have in effect not removed the network from the main thread, hence the UI "locks up" or feels slow.
You could have a callback that runs on the main thread when your thread is finished, but AsyncTask does this for you, and allows you to update a progress bar properly if desired. Read the documentation on how to implement AsyncTask.
svenoaks is correct that your use of thread.join() is making your code effectively single threaded. His solution of using an AsyncTask is also correct.
An alternative approach is to use a Handler in conjunction with the threads you already have. Create the Handler on your main thread, then in the spawned thread obtain() a new message and use the handler to send it. You then have code in the handler (which executes on the main thread) that receives the message and updates the UI.
Without seeing more of your code I can't be sure what it is you want to do with the data, but I can give you a basic example of how to use an AsyncTask. First you won't need any of that Thread stuff in getUrl(), so lets get rid of it. getUrl() should look something like this:
public static String getUrl(String url) {
final StringBuilder sb = new StringBuilder();
try
{
InputStream is = (InputStream) new URL(url).getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String result, line = reader.readLine();
result = line;
while((line=reader.readLine())!=null){
result+=line;
}
sb.append(result);
} catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
}
String result = sb.toString();
return result;
}
Next lets wrap your call to WebApi.getData in an AsyncTask, so that it runs in the background.
new AsyncTask<Void, Void, JSONObject>(){
#Override
protected JSONObject doInBackground(Void... params) {
JSONObject data = WebApi.getData(id);
return data;
}
#Override
protected void onPostExecute(JSONObject result){
//here you can do something with result
}
}.execute();
AsynTask will execute whatever code is in doInBackground() in a background thread, and then return the result to onPostExecute(), which will be run on the UI thread. Please note id will have to be declared final in the example I gave above.
As has already been said, you should probably read the documentation on AsyncTask.
I'm new in java, and im trying to read a text file from the web into a variable, but i'm getting the text file's url, instead of the content, and just can't figure out what could be the problem.
The class where i'm trying to read the file:
public class readtextfile extends AsyncTask<String, Integer, String>{
private TextView description;
public readtextfile(TextView descriptiontext){
this.description = descriptiontext;
}
#Override
protected String doInBackground(String... params) {
URL url = null;
String result ="";
try {
url = new URL("http://example.com/description1.txt");
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String line = null;
while ((line = in.readLine()) != null) {
result+=line;
}
in.close();
}
catch (MalformedURLException e) {e.printStackTrace();}
catch (IOException e) {e.printStackTrace();}
return result;
}
protected void onProgressUpdate() {
//called when the background task makes any progress
}
protected void onPreExecute() {
//called before doInBackground() is started
}
#Override
protected void onPostExecute(String result) {
this.description.setText(result);
}
}
The Activity where i call the class:
public class PhotosActivity extends Activity {
TextView description;
String descriptiontext;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.photos_layout);
description = ((TextView)findViewById(R.id.description1));
new readtextfile(description).execute();
}
}
Try url.openConnection and the use connection object to get inputStream. The updated method would be like
protected String doInBackground(String... params) {
URL url = null;
String result = "";
try {
url = new URL("http://www.example.com/description1.txt");
URLConnection connection = url.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
result += line;
}
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
Update based on your comment.
You need not invoke the postExecute method. If you invoke postExecute it just execute that method. The doInBackground wont get exeuted. Instead you should use the execute method. Just like java thread.start() method invoke the overridden run() method.
When an asynchronous task is executed, the task goes through 4 steps:
onPreExecute(), invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
refer developer doc
Try using Scanner like this.
URL url = new URL("http://www.example.com/description1.txt");
Scanner s = new Scanner(url.openStream());
I have a class 'one' that compiles class 'two' using commands
I use this code to run two
Process p2 = Runtime.getRuntime().exec("java two");
BufferedReader in = new BufferedReader(
new InputStreamReader(p2.getInputStream()) );
while ((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
Now when 'two' has printings in its main method, it works fine and they are printed in the console but when it has a user input Eclipse crashes.
when I even remove the while loop it doesn't allow me to write in the console
I am creating a new console using
MessageConsole console = new MessageConsole("", null);
console.activate();
ConsolePlugin.getDefault().getConsoleManager()
.addConsoles(new IConsole[] { console });
MessageConsoleStream stream = console.newMessageStream();
System.setOut(new PrintStream(stream, true));
I had a similar problem. I extended the MessageConsole (just to be able to have a specific consolePageParticipant) and in the constructor I have redirected the System.out to a new MessageConsoleStream. With the first version of my code the RCP application crashed, with the second version it hanged.
I already don't remember how did the code which crashed/hanged look like, but I found out that I cannot redirect the output sooner, than the MessageConsole is displayed. So I used a new thread to wait for some time (5 seconds - maybe too much?) before the redirect.
messageConsoleStream = myConsole.newMessageStream();
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
OutputStream out = new OutputStream() {
#Override
public void write(int b) throws IOException {
messageConsoleStream.write(b);
oldOut.write(b);
}
};
System.setOut(new PrintStream(out));
LOGGER.debug("'System.out' is redirected to the console."); //$NON-NLS-1$
}
}, "Redirect system out to console...").start(); //$NON-NLS-1$
Still it would be good to change the Thread.sleep(5000); to some wait until the console is displayed...
specify the Terminal in the line:
Process p2 = Runtime.getRuntime().exec("gnome-terminal -x java two");
or
Process p2 = Runtime.getRuntime().exec("xterm -x java two");
this makes the program to run in the foreground otherwise it becomes an invisible process...
I've been trying to google this around for quite a while now, without any success. I'm hoping to get my issue solved here.
First function:
public void startTFServer(Channel c) {
try {
ProcessBuilder procBuilder = new ProcessBuilder("tfs.exe");
procBuilder.redirectErrorStream();
Process proc = null;
System.out.println(Runtime.getRuntime().freeMemory());
proc = procBuilder.start();
System.out.println(Runtime.getRuntime().freeMemory());
StreamGobbler gobbler = new StreamGobbler(proc.getInputStream(), "STD_OUT");
gobbler.start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The thread that captures the process output:
private class StreamGobbler extends Thread {
InputStream is;
String type;
private StreamGobbler(InputStream is, String type) {
this.is = is;
this.type = type;
}
#Override
public void run() {
try {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(type + "> " + line);
}
}
catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
The problem:
When running the application the input interrupts at the same place every time. The application I'm running with the "Process class" is a server that required quite some memory to run, can this be one of the reasons for why the process won't finish loading my app? I was thinking that the memory would run out, but I can't really diagnostise it.
Any help would be greatly appreciated!
There is one issues that I notice:
procBuilder.redirectErrorStream();
This is not what you want. This is a getter method which tells you what the value of the redirectErrorStream property is. It could possibly be that you have errors and you are blocked because they are not read. Therefore, you need to use the setter method: see the API redirectErrorStream(boolean)
procBuilder.redirectErrorStream(true);
I'm guessing so sorry if I'm wrong, but I think you are exhausting the output from the external process, not waiting until it finishes in order to keep reading. I mean, basically:
while ((line = br.readLine()) != null) {
System.out.println(type + "> " + line);
}
If the process stops writing to the output for a second, your logger will stop logging. If it starts writing again, you will be out of the loop.
ImageThread it = new ImageThread(this.imageURL,this);
Thread t = new Thread(it);
t.start();
I'm new to threads and had to implement the above in my field that loads an image, because it slowed down the UI thread.
Whether my threads are downloading an image or some json content, they appear to still be downloading even though the user has pushed a new mainscreen onto the uiapplication. This continuous loading could be a problem if a user enters a screen and then accesses another in quick succession. As a result, the last screen they are on only finishes its thread when the others are done.
What am I supposed to do with my threads that would be deemed responsible? I don't want my app to be bogged down by a queue of threads. How do I, say, cancel downloads on screen change?
I'm posting this question in Java since I think the process is the same.
You can force your threads to close by keeping a public close() method inside your class that extends Thread:
private class MyConnectionThread extends Thread {
/** determines whether the thread is runnuing or not. */
private boolean alive = false;
private HttpConnection hconn = null; // or whatever connection method you want to use ( SocketConnection etc.)
private InputStream inputStream = null; // or DataInputStream etc...
public MyConnectionThread() {
alive = false;
// ...
// ...
}
public void run() {
alive = true;
try {
String connection_parameter = ";deviceside=false"; // [For BlackBerry: ] this parameter is for connection using MDS, need to add different parameters for different connection methods.
hconn = (HttpConnection) Connector.open("http://your_url.com"+connection_parameter);
int response = hconn.getResponseCode();
if (response == HttpConnection.HTTP_OK) {
inputStream = hconn.openInputStream();
// process the result here by reading the inputStream ...
// ...
// ...
}
inputStream.close();
hconn.close();
}catch(Exception excp) {
// Handle Exceptions here...
}catch (Throwable e) {
// Exception in reading inputStream
}finally{
alive = false;
this.interrupt();
}
}
/**
* Forces the connection to close anytime.
*/
public void closeConnection() {
alive = false;
try {
if (inputStream != null) {
inputStream.close();
}
inputStream = null;
if (hconn != null) {
hconn.close();
}
hconn = null;
this.interrupt();
} catch (Exception excp) {
// Handle Exception here...
System.out.println("Exception in closing HttpConnection: " + excp.toString());
}
}
}
Now whenever you navigate to another screen you just need to call the MyConnectionThread.closeConnection() method to force-close this Thread.
See Also:
how-to-abort-a-thread-in-a-fast-and-clean-way-in-java
How can we kill the running thread in java?
How to Stop a Thread or a Task
Hope these will be helpful for you.
As #Rupak suggested you make method (using isDisplayed() for example):
boolean isScreenOnTop()
And pass it to the Thread (better over interface StopCondition.shouldStop()). And modify you downloading algorithm to next:
while(moreDataAvailable() && !topCondition.shouldStop()) {
loadNextDataChunk();
}
if (!topCondition.shouldStop()) {
notifyDataDownloaded();
}