When I show an alertdialog, I start a thread that starts a 30 second countdown to update a determinate progressbar shown in this alertdialog.
I create the runnable as a static inner class so that I don't leak the context(activity), but then of course I can't access the flag to stop the thread, nor the views I want to update. How can I get around this?
public class MyDialogFragment implements DialogInterface.onShowListener, DialogInterface.onDismissListener {
private boolean stopThread = false;
private Progressbar countdownBar;
private TextView countdownRatio;
#Override public void onShow() {
Thread progressThread = new Thread(new myRunnable());
progressThread.start();
}
#Override public void onDismiss() {
stopThread = true;
this.dismiss();
}
private static class myRunnable implements Runnable {
int progressStatus = 0;
int numSeconds = 30;
#Override public void run() {
while (!threadStop && progressStatus < numSeconds) {
progressStatus++;
handler.post(new Runnable() {
public void run() {
countdownBar.setProgress(progressStatus);
countdownRatio.setText(progressStatus + "/" + numSeconds + " secs");
}
});
try {
// update the counter every sec
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
First - don't use Thread - you're asking for troubles, especially that you don't seem to be comfortable with multi-threaded programming. It's a tricky topic with tons of pitfalls. It's definitely not for noobs.
You may use AsyncTask for this - it has nice integration with UI event loop via AsyncTask.onProgressUpdate(). AsyncTask uses internal thread pool.
http://developer.android.com/guide/components/processes-and-threads.html#Threads
AsyncTask is ok for most trivial stuff. For more advanced uses try using Service with worker threads and message bus to communicate with fragments or activities. There is plenty of libraries for asynchronous programming. I can recommend this one:
https://github.com/stephanenicolas/robospice
It's main purpose if networking, but you can use it for other stuff as well.
Third solution is Loader API:
http://developer.android.com/reference/android/content/Loader.html
It's intended for asynchronous loading of data from database (SQLite is slow), but it's quite easy to use it for other stuff, such as data processing.
Remember: if you use Thread, there are 2 possibilities:
You are expert and you know what you're doing
You are green and you're doing it wrong
Related
basically, I have this code which was initially working with console i/o now I have to connect it to UI. It may be completely wrong, I've tried multiple things although it still ends up with freezing the GUI.
I've tried to redirect console I/O to GUI scrollpane, but the GUI freezes anyway. Probably it has to do something with threads, but I have limited knowledge on it so I need the deeper explanation how to implement it in this current situation.
This is the button on GUI class containing the method that needs to change this GUI.
public class GUI {
...
btnNext.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
controller.startTest(index, idUser);
}
});
}
This is the method startTest from another class which contains instance of Question class.
public int startTest() {
for (int i = 0; i < this.numberofQuestions; i++) {
Question qt = this.q[i];
qt.askQuestion(); <--- This needs to change Label in GUI
if(!qt.userAnswer()) <--- This needs to get string from TextField
decreaseScore(1);
}
return actScore();
}
askQuestion method:
public void askQuestion() {
System.out.println(getQuestion());
/* I've tried to change staticaly declared frame in GUI from there */
}
userAnswer method:
public boolean userAnswer() {
#SuppressWarnings("resource")
Scanner scanner = new Scanner(System.in);
if( Objects.equals(getAnswer(),userInput) ) {
System.out.println("Correct");
return true;
}
System.out.println("False");
return false;
}
Thanks for help.
You're correct in thinking that it related to threads.
When you try executing code that will take a long time to process (eg. downloading a large file) in the swing thread, the swing thread will pause to complete execution and cause the GUI to freeze. This is solved by executing the long running code in a separate thread.
As Sergiy Medvynskyy pointed out in his comment, you need to implement the long running code in the SwingWorker class.
A good way to implement it would be this:
public class TestWorker extends SwingWorker<Integer, String> {
#Override
protected Integer doInBackground() throws Exception {
//This is where you execute the long running
//code
controller.startTest(index, idUser);
publish("Finish");
}
#Override
protected void process(List<String> chunks) {
//Called when the task has finished executing.
//This is where you can update your GUI when
//the task is complete or when you want to
//notify the user of a change.
}
}
Use TestWorker.execute() to start the worker.
This website provides a good example on how to use
the SwingWorker class.
As other answers pointed out, doing heavy work on the GUI thread will freeze the GUI. You can use a SwingWorker for that, but in many cases a simple Thread does the job:
Thread t = new Thread(){
#Override
public void run(){
// do stuff
}
};
t.start();
Or if you use Java 8+:
Thread t = new Thread(() -> {
// do stuff
});
t.start();
For a long time I tried to make smooth animation for the application. And I got this solution: several threads launch draw frame of SceneRenderer:
public class OGLView extends GLSurfaceView {
public void init(Context context, int versionGLES) {
...
renderer = new SceneRenderer(context, versionGLES);
setRenderer(renderer);
...
}
}
public class SurfaceRunnable implements Runnable {
...
#Override
public void run() {
while(true) {
surfaceView.requestRender(); // draw frame
if (Thread.currentThread().isInterrupted()) break;
}
}
}
public class SurfaceExecutor implements Executor {
private List<Thread> threads = new ArrayList<>();
#Override
public void execute(#NonNull Runnable runnable) {
Thread thread = new Thread(runnable);
thread.setPriority(10);
thread.start();
threads.add(thread);
}
...
}
public class GameActivity extends AppCompatActivity {
private SurfaceExecutor executor = new SurfaceExecutor();
#Override
protected void onResume() {
...
SurfaceRunnable sr = new SurfaceRunnable(oglView);
/* run four threads for SceneRender */
executor.execute(sr);
executor.execute(sr);
executor.execute(sr);
executor.execute(sr);
...
}
}
As a result, the animation has become smoother. Long testing of the application did not lead to errors. Testing on different device configurations did not detect changes in the animation rate. Question: How much is this approach thread safe? All drawing and operations with matrices are done in SceneRenderer. Thank you all. Please, excuse my English.
Without a complete application it's impossible to say whether this is safe or not, as that entirely depends on what those 4 threads are doing and what resources are shared across them.
In all honesty though, this looks like a nasty hack. All 4 threads seem to be doing the same thing, any any fix of "just run 4 copies of the same thing and hope" seems to be running better by luck rather than any particular intentional design benefit.
I am building an app that requests the temperature of a server. When a button is pressed, I would like the app to:
1) Show a 'contacting server' message and show a spinning progress bar.
2) Contact the server on a new thread.
3) Display the result and hide the progress bar.
Here is my MainActivity:
public class MainActivity extends AppCompatActivity {
private Button mFetchTempButton;
private TextView mResultTextView;
private ProgressBar mProgressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mResultTextView = (TextView) findViewById(R.id.result_textview);
mFetchTempButton = (Button) findViewById(R.id.fetch_temperature_button);
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
mFetchTempButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mResultTextView.setText("Contacting server... ");
mProgressBar.setVisibility(View.VISIBLE);
String[] args = {};
String temperature = RequestServerTemp.main(args);
mProgressBar.setVisibility(View.INVISIBLE);
mResultTextView.setText("Server temperature is " + temperature);
}
});
}
}
This calls the java class 'RequestServerTemp', which uses a Callable to make the server request on a new thread:
public class RequestServerTemp {
public static String main(String[] args) {
final ExecutorService service;
final Future<String> task;
String result = "";
service = Executors.newFixedThreadPool(1);
task = service.submit(new GetTemp());
try {
result = task.get();
}
catch(InterruptedException | ExecutionException ex) {
ex.getMessage();
}
service.shutdownNow();
return result;
}
}
class GetTemp implements Callable<String> {
public String call() {
// simulate a long networking operation
try {
Thread.sleep(3*1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
return "30 degrees C";
}
}
The error this causes is that the App only updates once the whole onClick has been completed. This prevents my required step 1) from occurring. I am new to Android, and this raises several questions for me:
1) Why does onClick execute at the end, unlike traditional scripting languages which execute line by line?
2) If I've launched RequestServerTemp in a new Thread, why does MainActivity wait for it to finish? I feel this is bad for an app, and delays like this are the whole reason we launch networking in new threads.
3) Several similar questions to this say that AsyncTask is the 'correct' way to handle networking, rather than Runnable or Thread. Is that true, and should I avoid using Runnable and Thread in an App?
I am mostly interested in question 3, as many stackoverflow answers point to using Runnable and Thread techniques to accomplish networking, and now I am here I am worried I've wasted a lot of time and effort. Thanks for reading, and any general hints and advice for a new app developer (or stackoverflow user!) are welcome.
result = task.get();
get() is a blocking method. It waits until T is available to be returned. That's why "MainActivity wait for it to finish".
Is that true, and should I avoid using Runnable and Thread in an App?
No it is not. When I am not allowed to use third party library to send requests to a webservice, I use an ExecutorService.
Why does onClick execute at the end, unlike traditional scripting
languages which execute line by line?
it does not execute at the end. You are providing a delegate to your mFetchTempButton, the code in the callback, onClick, is executed when the event on click takes place.
My game has a stats queue, after each game the current game stats goes into the queue.
Whenever the mainmenu starts i want to upload all the game stats to a server, and this take like 1-3 seconds and I want to do this in an other thread.
My code
#Override
public void show() {
Global.key = Global.getKey();
// System.out.println(Stats.getJSONObject(Global.key));
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
Stats.TryUploadGame1();
System.out.println("DONE");
}
});
.....
}
But this also freezes my game.
What should I do?
Your current code is posting a Runnable instance that will be executed by the render thread before the next frame. The Gdx.app.postRunnable API is generally used so background threads can ask for something to happen on the render thread. You want to post a Runnable to execute anywhere but the render thread.
As long as your Stats code doesn't interact with OpenGL context at all (since Android OpenGL APIs assume only a single thread interacts with them), you can just post your Runnable on a new background thread:
new Thread(new Runnable() { ... }).start();
This should unblock your render. (Of course, if your background thread uses a lot of CPU, it can still interfere with the render thread, but if its mostly doing blocking IO or host has spare cores, it shouldn't interfere.)
This could be improved in lots of ways (using a ThreadPool, or using Android-aware background task support), but if your stats update is relatively quick and the thread creation isn't frequent this should work fine.
Okay to do something in a other thread you need to take care of the OpenGL context. Inside of a different thread you cant do anything that does render stuff. You are forced to push such thing into the renderthread in any way. And you need to synchronize everything that can be called from the regular render thread from libgdx. For example you want to call the .act(float delta) from a stage from a different thread you are forced to put the stage indo an synchronized block.
The post runable isn't a thread. It is an runable that get executed at the beginning of the next rendercall. So it will stop the game till it's done but it is inside of the OpenGl context thread. (That's why your game stops)
So here is an example of how to use threading in libgdx. I use this inside of my game. It runs on 210 frames so 210 updatecalls per second. You can change it to as fast as possible or just to 60fps whatever you need:
public class GameLogicThread extends Thread {
private GameScreen m_screen;
private boolean m_runing;
private long m_timeBegin;
private long m_timeDiff;
private long m_sleepTime;
private final static float FRAMERATE = 210f;
public GameLogicThread(GameScreen screen) { //pass the game screen to it.
m_screen = screen;
setName("GameLogic");
}
#Override
public void run() {
m_runing = true;
Logger.log("Started");
while (m_runing) {
m_timeBegin = TimeUtils.millis();
// act of the camera
synchronized (m_screen.figureStage) { //stage with figures
// now figures
if (m_screen.m_status == GameStatus.GAME) {
m_screen.figureStage.act(1f / GameLogicThread.FRAMERATE);
}
}
m_timeDiff = TimeUtils.millis() - m_timeBegin;
m_sleepTime = (long) (1f / GameLogicThread.FRAMERATE * 1000f - m_timeDiff);
if (m_sleepTime > 0) {
try {
Thread.sleep(m_sleepTime);
}
catch (InterruptedException e) {
Logger.error("Couldn't sleep " + e.getStackTrace());
}
} else {
Logger.error("we are to slow! " + m_sleepTime); //meight create it dynamic so if you are to slow decrease the framerate till you are not to slow anymore
}
}
}
/**
* Stops the thread save<br>
*/
public void stopThread() {
m_runing = false;
boolean retry = true;
while (retry) {
try {
this.join();
retry = false;
}
catch (Exception e) {
Logger.error(e.getMessage());
}
}
}
}
This does update all my figures. To not cause any troubles with the rendering thread the figurestage is synchronized. (Kind of critical section)
Dont forget that you need to create a new thread every time you stopped it. so for example inside of the show you need todo this:
#Override
public void show() {
super.show();
m_logic = new GameLogicThread(this); //create a new one inside of the GameScreen
m_logic.start(); //start the thread
}
Also dont forget to savestop it inside of the pause stop and so on.
#Override
public void dispose() {
m_logic.stopThread();
}
According to the wiki
To pass data to the rendering thread from another thread we recommend using Application.postRunnable(). This will run the code in the Runnable in the rendering thread in the next frame, before ApplicationListener.render() is called.
So calling that method is just creating a new thread on to run on the render thread.
You may want to use standard java practice on creating threads unless this is frowned upon in libgdx because of android, that I am not sure of.
I need to call the same thread multiple times in my app. Using my original code, the first time is can be executed just fine. But the second time it crashes - I then learned that each thread shall only be executed not more than one time.
My original piece of code:
View.OnClickListener myClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
mythread.start();
}
};
Thread mythread = new Thread(){
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Running...");
}
});
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Finished...");
}
});
}
};
So as I said, it crashes if I try to run it for the second time. So I tried modifying it like:
View.OnClickListener myClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
test();
}
};
private void test(){
Thread mythread = new Thread(){
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Running...");
}
});
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Finished...");
}
});
}
};
mythread.start();
}
It works very good; but my question is that whether this is the correct way to do this action or there is a more optimal way to do this?
Also, is it an acceptable thing to call a thread from insider of another thread? (like the way I put stuff on UI Thread inside the new thread of mine)
EDIT:
This is just an example. For my actual code I have heavy math-based simulation to be done which takes 10sec to be done. Based on the results that will be shown to the user , they may want to change their input parameters and let the simulation run again. This will happen several times.
In addition to the other good answers about using AsyncTask or runOnUiThread(), you could define a private member as a Runnable, like this:
private Runnable mytask = new Runnable() {
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Running...");
}
});
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Finished...");
}
});
}
};
Then, whenever you want to run it, do
new Thread(mytask).start();
There is nothing bad with that but I think a better way would be using AsyncTask. It is exactly designed for this cases.
You can use AsyncTask multiple times just creating a new one like this new MyAsyncTask().execute(""); (source from here)
Also, is it an acceptable thing to call a thread from insider of another thread? (like the way I put stuff on UI Thread inside the new thread of mine)
runOnUiThread exists solely for that purpose. But there are usually much better ways (e.g. AsyncTask) so using this method is probably a bad idea.
my question is that whether this is the correct way to do this action or there is a more optimal way to do this?
You should not use a thread just to schedule future tasks. They are useful to execute something in parallel to the main thread but add lots of potential errors (try rotating the screen between it prints running..finished, could crash)
I would use a CountDownTimer in your case.
Or a Handler, examples e.g. here: Schedule task in android
From the provided code I assume that you want to perform an UI operation before and after your long mathematical computation. In such as #Andres suggested, AsyncTask is your best buy. It provides method onPreExecute, onPostExecute which runs on UI thread, and thus no need for explicitly calling runOnUiThread.
Key concepts :
You can't start an already started thread. This will return in an IllegalStateException. If you need to perform same task again, you should create a new instance.
If you find yourself creating several instances of a thread (even AsyncTask), since you need to run same task again and again, I would suggest you to use Thread Pool or simple Java Executor Service. Create a singleThread or may be pool and post your runnable onto executorService and it will take care of the rest.
Inter-Thread or Inter-Process communication is quite common requirement.