How to update something in main class in thread - java

Hi I am trying to make a multiplayer game where it would find the opponent in another thread, but I am not sure why the code running in the thread does not update the model in the main class...
Here is the code in the main class. The call to the LoadTask starts another thread
// Start model, passing number of words, user name, and selected animal
model = new MultiPlayerModel(NUM_WORDS, username, anmID);
model.addObserver(this);
new LoadTask().execute();
setContentView(R.layout.activity_multi_player);
initialDisplay(animal, background, oppAnimal);
Here is the code for the thread class
private class LoadTask extends AsyncTask<Void, Integer, Void> {
// called before running code in a separate thread
private boolean quitFlag;
#Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(MultiPlayer.this,"Finding a Game...",
"Searching for opponent, please wait...", false, false);
}
#Override
protected Void doInBackground(Void... params) {
synchronized (this) {
try {
model.beginMatchMaking();
model.setWordsList();
// Get the opponent's animal from the model
oppAnimal = reverseDrawable(model.getOpponentAnimal());
// Display the multiplayer screen
} catch (InternetConnectionException e) {
e.fillInStackTrace();
quitFlag = true;
error(States.error.CONNECTION);
return null;
} catch (EmptyQueueException e) {
e.fillInStackTrace();
quitFlag = true;
error(States.error.NOOPPONENT);
return null;
} catch (InternalErrorException e) {
e.fillInStackTrace();
quitFlag = true;
error(States.error.INTERNAL);
return null;
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
if (!quitFlag) {
progressDialog.dismiss();
gameTimer = new GameTimer(START_TIME, INTERVAL);
gameTimer.start();
}
}
}
And it segfaults on initialDisplay after the thread is called because the fields in model class were not updated at all. it acts as though it was just created and nothing was done to it

I'm not sure about AsyncTask class
but if it's properly configurated Thread and next line
new LoadTask().execute();
will start this thread properly, in this case thread will execute inparallel but usualy after lines:
setContentView(R.layout.activity_multi_player);
initialDisplay(animal, background, oppAnimal);
to prove it you may print messages main methods.
To solve it you may simply add next line after starting thread:
new LoadTask().execute();
Thread.sleep(100)

Related

Modifying a protected field value is not seen in subclass instance

This is a strange situation I've run into. I have an abstract base class that defines a protected field. There is also a public method that modifies the field. I then have some subclasses of the base class that make use of the field.
I've noticed that when I invoke the super-class method to modify the field, the change to the field's value does not seem to "carry through" to an instance of a subclass.
The other thing that needs to be mentioned is that the abstract class (and therefore its subclasses) implements Runnable. I wouldn't think that should have an effect on what I'm seeing, but multi-threading is not my forte.
Abstract base class:
public abstract class AbstractWidget implements Runnable {
// Other fields and methods omitted for brevity.
protected boolean running;
public void shutDown() {
running = false;
}
}
Subclass:
public class ConcreteWidget extends AbstractWidget {
// Other fields and methods omitted for brevity.
#Override
public void run() {
running = true;
while (running) {
// ...
}
logger.info("Shutting down");
}
}
So, when I finally invoke the shutDown() method, the subclass instance, running in a thread does not break from it's loop and return.
I've used the technique of modifying a boolean field from "the outside" to stop a "forever" thread many times before. I don't understand what's happening here.
UPDATE:
Below is an example of the code being called.
ConcreteWidget widet = new ConcreteWidget(...);
thread = new Thread(widget);
thread.start();
logger.info("Started");
...
logger.debug("shutting down");
widget.shutDown();
try {
logger.debug("doing join on thread");
thread.join();
logger.debug("returned from join");
} catch (InterruptedException e) {
logger.error("Exception", e);
}
The call to join() never returns.
UPDATE:
As requested I have included what I hope is a complete (enough) example of the code as I currently have it. NOTE: I have taken the suggestion and changed the protected boolean to AtomicBoolean.
public abstract class AbstractWidget implements Runnable {
protected final AtomicBoolean running = new AtomicBoolean(true);
public void shutDown() {
running.set(false);
}
}
public class ConcreteWidget extends AbstractWidget {
#Override
public void run() {
while (running.get()) {
// ... do stuff (including calling process() below)
}
}
private void process() {
try {
// ... do stuff
} catch (IOException e) {
logger.error("Exception", e);
running.set(false);
return;
}
}
}
In the "main" logic:
private void startService() {
widget = new ConcreteWidget(...);
thread = new Thread(widget);
thread.start();
logger.info("Started");
}
public void close() {
logger.debug("shutting down service");
widget.shutDown();
try {
logger.debug("doing join on service thread");
thread.join();
logger.debug("returned from join");
} catch (InterruptedException e) {
logger.error("Exception", e);
}
}
BTW, it still does not work.
Your problem is actually a simple one. By the time you call widget.shutDown();, the thread has not actually started, so when the thread actually starts, it sets running back to true, and never stops. Instead of using running to terminate the loop, use a separate stopped variable.
public abstract class AbstractWidget implements Runnable {
// Other fields and methods omitted for brevity.
private volatile boolean running = false;
private valatile boolean stopped = false;
public boolean isRunning() {
return running;
}
public boolean hasStopped() {
return stopped;
}
public void shutDown() {
stopped = true;
}
}
public class ConcreteWidget extends AbstractWidget {
// Other fields and methods omitted for brevity.
#Override
public void run() {
running = true;
while (!stopped) {
// ...
}
running = false;
logger.info("Shutting down");
}
}
With this setup, you might want to wait a while before stopping, if not the loop will never run at all.
ConcreteWidget widet = new ConcreteWidget(...);
thread = new Thread(widget);
thread.start();
logger.info("Started");
...
try {
Thread.sleep(500); // <--
} catch (Exception e) {}
logger.debug("shutting down");
widget.shutDown();
try {
logger.debug("doing join on thread");
thread.join();
logger.debug("returned from join");
} catch (InterruptedException e) {
logger.error("Exception", e);
}
Do you run widget.shutDown(); immediately after thread.start(); ?
maybe widget.shutDown(); has run before running = true; code inside run() method
[facepalm]
It turns out the problem was that the thread processing was hanging and never able to check the state of the running field. Once I corrected that problem, it worked just fine.
I did change my logic to use the AtomicBoolean instead of boolean, so thank you for that useful advice.

If a SwingWorker task is canceled how do I know when interrupted method completed

If a SwingWorker task is canceled, how do I know when the interrupted method completed.
I have simplified the code. FixSongsController.start() runs in the background. When it completes, a report is created and when that is done the report is then displayed using the done() method.
There is a progress dialog running and if the user elects to cancel ( whilst FixSongsController.start() is running ), this then invokes cancel(true) on the SwingWorker causing an interrupt to be sent to FixSongsController.start(). The trouble is, as soon as it's sent, it then invokes createReport().
I don't want to to start creating the report until FixSongsController.start() has actually finished. I can't see how to identify when that has occurred.
If I remove the createReport code from FixSongsDialog and the isCancelled() checks on Fix Songs the problem is worse because then FixSongsDialog trys to display the report before it has been created.
I thought I could make use of SwingWorker.getState() but once cancelTask is invoked doInBackground() task is interrupted and completes shortly after even though FixSongsController method is still tidying up.
Then I thought I could use SwingWorker.setProgress() within FixSongsController.start() method in its finally block and add a listener that would only invoke showReport once the progress value had changed but setProgress is protected so I cannot access it outside of FixSongs class itself.
SwingWorker Class
public class FixSongs extends SwingWorker<String, Object>
{
#Override
public String doInBackground() throws Exception
{
try
{
new FixSongsController().start();
if (!isCancelled())
{
new FixSongsReportCreator().createReport();
}
return "";
}
catch (Throwable ex)
{
MainWindow.logger.log(Level.SEVERE, ex.getMessage(), ex);
throw ex;
}
}
#Override
protected void done()
{
SongKong.mainWindow.dialog.close();
if (!isCancelled())
{
ShowCounters showCounters = new ShowReport();
}
}
}
Progress Dialog Class
public class FixSongsDialog extends RecordBasedProgressDialog
{
....
#Override
public void cancelTask()
{
try
{
swingWorker.cancel(true);
CreateReport createReport = new CreateReport();
createReport.execute();
this.dispose();
}
catch(Exception ex)
{
MainWindow.logger.log(Level.SEVERE,ex.getMessage(),ex);
throw ex;
}
}
class CreateReport extends SwingWorker<String, Object>
{
#Override
public String doInBackground() throws Exception
{
try
{
new FixSongsReportCreator().createReport();
return "";
}
catch(Exception ex)
{
MainWindow.logger.log(Level.SEVERE,ex.getMessage(),ex);
throw ex;
}
}
#Override
protected void done()
{
ShowCounters showCounters = new ShowReport();
}
}
}

kills an Android AsyncTask with a timeout

So my problem is that i have a AsyncTask that scraps html from a page on a server so i used Jsoup as a library .
so the problem is that i want to set a timeout to cancel the Task if i don't receive any data from the page and display that there is a "communication error " on a toast
is there anyway to kill or stop the asynctask within it self and return a result on onPostExecute
{
private class getPageTitle extends AsyncTask<Void, Void, String> {
String title;
#Override
protected void onPreExecute() {
super.onPreExecute();
connectServerProgressDialog = new ProgressDialog(LoginScreen.this);
connectServerProgressDialog.setTitle("CheckingServer");
connectServerProgressDialog.setMessage("Loading...");
connectServerProgressDialog.setIndeterminate(true);
connectServerProgressDialog.show();
}
#Override
protected String doInBackground(Void... params) {
try {
// Connect to the web site
Document document = Jsoup.connect(CONNECT_URL).get();
title = document.title();
} catch (IOException e) {
e.printStackTrace();
}
return null ;
}
#Override
protected void onPostExecute(String result) {
if(result!=null){
switch (title) {
case "0":
Toast.makeText(LoginScreen.this,"offline",Toast.LENGTH_SHORT).show();
connectServerProgressDialog.dismiss();
break;
case "1":
connectServerProgressDialog.dismiss();
Toast.makeText(LoginScreen.this,"Connected",Toast.LENGTH_SHORT).show();
break;
}}else{
Toast.makeText(LoginScreen.this,"Communication error",Toast.LENGTH_SHORT).show();
}
}
}}
I have a convention that I use for AsyncTask subclasses.
Define an inner interface for the client to use. This decouples the client class so that the AsyncTask can be re-used. The interface is named in the form blahblahListener.
The interface has two methods of the form blahblahCompleted() and blahblahException().
Accept a callback object (listener) that is an implementation of that interface. This is either passed in the AsyncTask constructor or set with a setListener() method.
Hold that listener reference in a WeakReference field so that if the listener goes away before the task completes, the listener can still be garbage-collected.
Define a field to hold an Exception. If an exception occurs in the background method, this field remembers the exception in order to report it to the client.
In the onPostExecute() method, check if the Exception field is null. If it is, call blahblahCompleted() with the result. If it isn't, call blahblahException() with the exception. Also check if the WeakReference is still valid.
For killing the task, you can have a timeout set on your connection. Then when your connection times out, you will get an exception, which is remembered and reported.
So using that convention, your code would look like this:
public class WebPageTitleRemoteTask extends AsyncTask<URL, Void, String> {
private WeakReference<WebPageTitleRetrievalListener> mListener;
private Exception mException;
public WebPageTitleRemoteTask(WebPageTitleRetrievalListener listener) {
super();
mListener = new WeakReference<WebPageTitleRetrievalListener>(listener);
}
#Override
protected String doInBackground(URL... params) {
String title = null;
try {
// Connect to the web site
Document document = Jsoup.connect(params[0]).get();
title = document.title();
} catch (IOException e) {
mException = e;
}
return title;
}
#Override
protected void onPostExecute(String result) {
WebPageTitleRetrievalListener listener = mListener.get();
if (listener != null) {
if (mException == null) {
listener.webPageTitleRetrieved(result);
} else {
listener.webPageTitleRetrievalException(mException);
}
}
}
public static interface WebPageTitleRetrievalListener {
public void webPageTitleRetrieved(String title);
public void webPageTitleRetrievalException(Exception e);
}
}
And your client code would look something like this, with your Activity implementing that inner interface:
.
.
.
connectServerProgressDialog = new ProgressDialog(LoginScreen.this);
connectServerProgressDialog.setTitle("CheckingServer");
connectServerProgressDialog.setMessage("Loading...");
connectServerProgressDialog.setIndeterminate(true);
connectServerProgressDialog.show();
new WebPageTitleRemoteTask(this).execute(url);
.
.
.
#Override
public void webPageTitleRetrieved(String title) {
if (isFinishing()) return;
connectServerProgressDialog.dismiss();
Toast.makeText(this, "title = " + title, Toast.LENGTH_SHORT).show();
}
#Override
public void webPageTitleRetrievalException(Exception e) {
if (isFinishing()) return;
connectServerProgressDialog.dismiss();
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
NOTE: Because the listener is held in a WeakReference, you can't use an anonymous inner class for the listener, because the reference will go away almost immediately and be eligible for garbage collection.
I use this convention consistently, and the extra boilerplate code in the AsyncTask subclass makes it a lot cleaner to use in the client class.

Android Thread with Methods

I have this sittuation:
3 public methods, 2 are commands and 1 check inputs and will start command1 or command2 in thread. My question is how i can do that?
public void blablabla() {
input = get_user_input;
if(input == 1) {
start thread with command1
} else {
start thread with command2
}
}
public void command1() {
// do action
}
public void command2() {
// do action2
}
I think its impossible start a thread with method directly but using Runnable i can do that. I was thinking if its good choice and great idea for performance declare command1 and command2 are static runnable on class and use this runnables to start thread. Doing this as static runnable it will spend more memory than a method ?
Thanks!
you can use Asyn thread. try this below example
private class GetExampleDetails extends AsyncTask<String, Void, Void> {
private ProgressDialog dialog = new ProgressDialog(ExpensesListView.this);
String strMsg = null;
protected void onPreExecute() {
this.dialog.setMessage("Loading.....");
this.dialog.setCanceledOnTouchOutside(false);
this.dialog.show();
}
// automatically done on worker thread (separate from UI thread)
protected Void doInBackground(final String... a) {
try
{
//Write your code. which one do backround
}
catch(Exception ex)
{
ex.printStackTrace();
}
return null;
}
// can use UI thread here
protected void onPostExecute(final Void unused) {
if (this.dialog.isShowing()) {
this.dialog.dismiss();
this.dialog = null;
}
}
}//Endtask
check this one. i think this help you

Stop the thread started within a object after the object is no longer in a list?

Say I have a class call MyTask
Every time I new a object for MyTask, it will create a thread
boolean mContinueThread = true;
public MyTask (Activity activity) {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while (mContinueThread) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
});
thread.start();
return null;
};
}.execute();
}
At first I new myTask1, myTask2, myTask3 then add to the List
List<MyTask> myTasks = new ArrayList<MyTask>;
myTasks.add(myTask1);
myTasks.add(myTask2);
myTasks.add(myTask3);
Now there should be 3 threads run on the background, then I renew the by
myTasks = new ArrayList<MyTask>;
And looks like those threads in myTask1, myTask2, myTask3 are still running, the finalize never get called. I know I can set mContinueThread as true for each MyTask objects before I renew the list, but I would like to know is there any way (callback?) I can know those MyTask objects are not no longer in the list and then set mContinueThread as false?
public MyTask (Activity activity) {
...
#Override
protected void finalize() throws Throwable {
mContinueThread = false;
super.finalize();
}
It seems redundant to have an async task which just starts a Thread.You can achieve the desired outcome, by puting the contance of the thread directly into you AsyncTask$doInBackground()
You can call the call the AsyncTask$cancel(boolean mayInterrupt) method, this will rise an InterruptedException, the only thing left to do, is adding a return statement within the catch:
#Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// cancel was called
return null;
}
return null;
};
Cancel the task like that:
myTasks.get(i).cancel(true);
Don't forget to pass true or it won't work
you have to have a variable for your AsyncTask first, so that you can call:
myTasks.get(0).getMyAsyncTask().cancel(boolean);
As you can see here, it is not that easy to cancel an AsyncTask. After you call cancel(boolean), it will: (from docs:
invoking this method will cause subsequent call to isCancelled() to
return true. onCancelled(Object) will be invoked after doInBackground
instead of onPostxecute. To ensure that a task is cancelled, you
should always check the return value of isCancelled from
doInBackground.
So, you call cancel(booelan) onto your reference variable of your AsyncTask and in doInBackground, you always check for isCancelled() in order to stop some processes in your doInBackground method.
You should handle your doInBackground method manually in order to stop all the executions there. So if you have while(true){ do_something }, then it should become while(true){ if(!isCancelled()) { do_something } }

Categories