I'm trying to setup a combat system that allows the user to pick between a melee attack and ranged attack (pick one of two radio buttons). Based on variables what actions the buttons can say, "out of range", "attack melee", "attack range", "reload range". onresume radioButtons have the correct text. After firing ranged weapon for the first time (combat starts with ranged weapon already reloaded) The text for rangeRadio changes to "reload range" but wont change back from "reload range" to "attack range" even when the weapon is 'reloaded' and will fire dealing damage when I end the turn (and preform set actions). If the weapon takes 2 turns to reload. I spend 2 turns reloading, click home button then return to activity it will setText correctly and say "range attack", other wise it will stay "reload range".
finds radioButtons, if statements to first check if there is a ranged weapon equip(rangeId == 50 means no weapon) then check to see if weapon is loaded (int rangeReload = 100), then finally check to see if in range to attack/fire.
private void setActions(){
RadioButton meleeRadio = (RadioButton) findViewById(R.id.meleeRadio);
RadioButton rangeRadio = (RadioButton) findViewById(R.id.rangeRadio);
if (meleeRange >= distance){meleeRadio.setText(meleeString);}else{meleeRadio.setText(oorString);}
if (rangeId == 50){rangeRadio.setText(norangeString);}else{if(rangeReload<=99){rangeRadio.setText(reloadString);}else{
if (rangeRange >= distance){rangeRadio.setText(rangeString); Log.e(rangeString, "Range Attack called");}else{rangeRadio.setText(oorString);}}}
}
I call setActions(); in two places. in onresume via preCombat() -> layoutcombat()
#Override
protected void onResume() {
new pullCombatActions().execute();
new prepCombat().execute();
super.onResume();}
private class prepCombat extends AsyncTask<String, Void, String>{
#Override
protected String doInBackground(String... params) {
playerBattlePrep();
findNPC();
return null;}
#Override
protected void onPostExecute(String result) {
new layoutCombat().execute();
}
}
private class layoutCombat extends AsyncTask<String, Void, String>{
#Override
protected String doInBackground(String... params) {
startCombat();
pullCombatText();
return null;}
#Override
protected void onPostExecute(String result) {
setActions();
popStats();
refreshStats();
combatStartText();}
}
the 2nd place I call setActions(); is in my AsyncTask that I run at the end of a combat turn to refresh the screen and show the user what happened via rolls.
private class replaceScreen extends AsyncTask<String, Void, String>{
#Override
protected String doInBackground(String... params) {
pullCombatStory();
return null;
}
#Override
protected void onPostExecute(String result) {
refreshStats();
refreshCombatStory();
highLightPlayerActions();
highLightNpcActions();
setActions();
}
}
I don't understand why it seems to stop half way through my if statement when setting the rangeRadio but onResume lets it complete all the way and display the proper text for rangeRadio.
Just a suggestion, try moving
RadioButton meleeRadio = (RadioButton) findViewById(R.id.meleeRadio);
RadioButton rangeRadio = (RadioButton) findViewById(R.id.rangeRadio);
Outside of your onResume method, and put it on your onCreate (or onActivityCreated if it is a fragment) method and put rangeRadio and meleeRadio as private variables in your activity (or fragment)
Then, since you are using chained AsyncTasks I'm not sure if all of your onPostExecute are running on your UI thread, so I would try to encapsulete all your calls to rangeRadio.setText() on a handler like this:
On your on Activity onCreate:
handler = new Handler();
then when setting your text do :
handler.post(new Runnable() {
public void run() {
rangeRadio.setText("...");
}
});
TY for helping. In my haste to find a good stopping place for the night I forgot to setup AsyncTask for when the character reloads. So setActions() wasn't being called when the player didn't attack because they were out of range or when the player was reloading.
Related
I have an AsyncTask which does a lot of JSON calculations.
public class InitializationTask extends AsyncTask<Void, Void, InitializationResult> {
private ProcessController processController = new ProcessController();
private ProgressDialog progressDialog;
private MainActivity mainActivity;
public InitializationTask(MainActivity mainActivity) {
this.mainActivity = mainActivity;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(mainActivity);
progressDialog.setMessage("Die Daten werden aufbereitet.\nBitte warten...");
progressDialog.setIndeterminate(true); //means that the "loading amount" is not measured.
progressDialog.setCancelable(false);
progressDialog.show();
};
#Override
protected InitializationResult doInBackground(Void... params) {
return processController.initializeData();
}
#Override
protected void onPostExecute(InitializationResult result) {
super.onPostExecute(result);
progressDialog.dismiss();
if (result.isValid()) {
mainActivity.finalizeSetup();
}
else {
AlertDialog.Builder dialog = new AlertDialog.Builder(mainActivity);
dialog.setTitle("Initialisierungsfehler");
dialog.setMessage(result.getReason());
dialog.setPositiveButton("Ok",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
mainActivity.finish();
}
});
dialog.show();
}
}
}
processController.initializeData() runs for about 20 seconds. All this works. It even works when I install the application, and pressing home button while application is initializing. The AsyncTask is working in the background. When I restart the application from Android device again after the AsyncTask has been finished, the application still works.
But the application cannot handle this use case: When I deploy the application (or start it when no data is initialized), so that it really takes about 20sec to initialize the data and when I hit home to close the application while initialization (the AsyncTask) runs in the background and start the application again, it leads to unexpected behavior as RuntimExceptions and so on. It seems that the device wants to load the application twice, but none of them can start successfully. How to deal with that?
I thought about checking if there is a running AsyncTask in MainActivity to avoid starting it again:
private InitializationTask initializationTask = new InitializationTask(this);
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if (!AsyncTask.Status.RUNNING.equals(initializationTask.getStatus())) {
initializationTask.execute((Void[])null);
}
initializeMap();
}
Unfortunately this does do nothing. Moreover I'm not sure if such use case is possible at all, because when I start the same application twice, they cannot "share" an AsyncTask. Should I somehow avoid starting the application twice or something? I'm not sure what options do I have on this? Any ideas?
I usually do it a bit more bluntly. I set my AsyncTask reference to null when I'm not using it. When the onClick fires, I check if it's not null, which means I started it. If it is null, I create and execute a new AsyncTask right there. It is plenty fast and it's clean enough. One bonus of this approach is that an AsyncTask can only be executed once anyway, so it fits in well with that. At the end of onPostExecute, you can set the reference back to null again if you intend to stay in the same Activity.
While you're perfecting your AsyncTask flow, make sure that it survives orientation changes as well.
I found the solution: It's actually not an AsyncTask issue. The problem was that my parse method of JSONParser (that does the most of the work) which is invoked in processController.initializeData(), was not synchronized.
The goal:
Using Google App Engine server and Android client, I'm trying to put on the Google map at the Android client Users overlays. Every 30 seconds I'm polling the server and getting Vector that contains users and adding it to the map.
Current status:
I'm dong all that using in one new thread, So after running the app I got:
weird behaviors(delayed overlays, multiple overlays) and after that crushed with ConcurrentModificationException.
After reading a bit i figured out that I need to work with AsyncTask.
Correct me if I'm wrong,But I understand that everything done in the Activity at at onCreate is "running" in UIhread so I need to put the "Logic" (All the Network handling) in doInBackground and all the UI Handling like putting overlays on the map in onPostExecute.
My Question are:
1) In the current status I'm doing:
new Thread()
{
#Override
public void run()
{
super.run();
while(true)
{
SystemClock.sleep(30000);
Vector responseFromServer = getUsersVectorFromServer();
putNewOnlineUserOnTheMap();
}
}
}.start();
What is the right way to convert this To AsyncTask?
Do I poll the server still using new thread in the doInBackground or there is right way to do this?
2) Is there a specific list of what counts as UI to put in onPostExecute or any concepts list?
In my case I guess that in need to put putNewOnlineUserOnTheMap() in onPostExecute.
Thanks.
Something similar to the following:
class UpdateTask extends AsyncTask<Void, Vector, Void>{
#Override
protected Void doInBackground(Void... params) {
// this is running in a background thread.
while (!isCancelled()) {
SystemClock.sleep(30000);
Vector responseFromServer = getUsersVectorFromServer();
// send the result back to the UI thread
// onProgressUpdate will be called then
publishProgress(responseFromServer);
}
return null;
}
#Override
protected void onProgressUpdate(Vector... values) {
// this is executed on the UI thread where we can safely touch UI stuff
putNewOnlineUserOnTheMap(values[0]);
}
}
You can't use the result of the task since the task is finished then. But you can use the progress publishing mechanism to get periodic results. If you use it like that and do the modification on the UI thread you should not get ConcurrentModificationException because you do the modifications on the one thread that can safely modify the UI.
One thing to note here: create new instances of your Vector in the background thread and then use it to update the UI. But don't touch the same object afterwards in the backgroundthread. That way you don't need any synchronization since after the background thread sends it away it is only the UI thread that touches it. (and you could use a simple ArrayList instead of a Vector)
AsyncTask uses generics and varargs.The parameters that are passed to the asyntask are . TypeOfVariableArgumentsParameters is passed into the doInBackground(), ProgressParam is used for progress information and ResultParam must be returned from doInBackground() and is passed to onPostExecute() as parameter.
example:--
protected class ParsingTask extends AsyncTask> {
private ProgressDialog loadingDialog = new ProgressDialog(JsonParserActivity.this);
protected void onPreExecute() {
loadingDialog.setMessage("loading app store..");
loadingDialog.show();
}
#Override
protected ArrayList<Items> doInBackground( Context... params ) {
// do ur process here.
return result;
}
if (!this.isCancelled()) {
}
return result;
}
#Override
protected void onProgressUpdate(String... s) {
super.onProgressUpdate(s);
Toast.makeText(getApplicationContext(), s[0], Toast.LENGTH_SHORT).show();
}
#Override
protected void onPostExecute( ArrayList<Items> response ) {
//if u r dealing with list view and adapters set the adapter here at the onPostExecute()
loadingDialog.dismiss();
}
#Override
protected void onCancelled() {
super.onCancelled();
Toast.makeText(getApplicationContext(), "The operation was cancelled", 1).show();
}
}
You can use AsyncTask like below. Hope this will help you..
Class YourClass{
void YourClass(){
NetworkTask nT = new NetworkTasK();
nT.execute();
}
}
protected class NetworkTask extends AsyncTask<Void, String, Boolean>
{
#Override
protected Boolean doInBackground(Void... params)
{
try
{
String response;
while(keepreceiving)
{
response = in.readLine();//Prog Counter stops here until getting i/p.
if(response != null)
yourFunctionForResponse(response);
}
}
catch (Exception ex)
{
}
return null;
}
private void yourFunctionForResponse(String response){
//things to do....
}
}
You may also try runOnUiThread(Runnable action) along with this to implement your work.
Iv'e got an Android app that is using a list activity to display a list of items pulled from the internet. I First use an AsyncTask to load the list and that Async task finishes it calls a different async task to start loading the thumbnail pictures that go along with the list items. The problem I am having is that the user has access to a refresh button that they can press at any time and when it is pressed, the whole list of items is delete and the loading starts over. The Async task that loads the thumbnails could potentially still be running if this happens and may try to add a thumbnail to a non existing list item then. Iv'e tried synchronizing on the list, using a Boolean which after researching I realized would not work. I have also tried using a static atomic boolean to check if refresh has been hit to cancel the thumbnail loader. Any ideas?
public class LoadItems extends AsyncTask<Void, Void, Boolean> {
private Activity activity;
private static boolean loading = false;
public static final AtomicBoolean refreshing = new AtomicBoolean(false);
private static final String TAG = "LoadItems";
private int start;
private List<ListItem> items;
public LoadItems(Activity activity) {
this.activity = activity;
}
#Override
protected void onPreExecute() {
loading = true;
start = ItemViewer.itemList.size();
}
#Override
protected Boolean doInBackground(Void... arg0) {
items = WebFunctions.getMoreItems(activity);
return (items != null);
}
protected void onPostExecute(Boolean success) {
if (success) {
for (ListItem item: items) {
ItemViewer.itemList.add(item);
Log.d(TAG, "added item " + item.getTitle());
}
LoadThumbnails thumbnailLoader = new LoadThumbnails();
thumbnailLoader.execute(start, ItemViewer.itemList.size());
}
loading = false;
}
public void protectedExecute() {
if (!loading)
execute();
}
public void refresh() {
if (!refreshing.getAndSet(true)) {
WebFunctions.reset();
ItemViewer.itemList.removeAllItems();
execute();
}
}
}
public class LoadThumbnails extends AsyncTask<Integer, Void, Drawable> {
private int position;
private int end;
#Override
protected Drawable doInBackground(Integer... params) {
position = params[0];
end = params[1];
Drawable thumbnail = null;
synchronized(ItemViewer.itemList) {
if (LoadItems.refreshing.get())
cancel(true);
String url = ItemViewer.itemList.get(position).getThumbnailUrl();
if (!url.isEmpty())
thumbnail = WebFunctions.loadDrawableFromUrl(ItemViewer.activity, url);
}
return thumbnail;
}
protected void onPostExecute(Drawable d) {
synchronized (ItemViewer.itemList) {
if (LoadItems.refreshing.get())
cancel(true);
if (d != null)
ItemViewer.itemList.setThumbnail(position, d);
position++;
if (position < end) {
LoadThumbnails lt = new LoadThumbnails();
lt.execute(position, end);
}
}
}
}
This is pretty simple to solve. Whenever the user hits the refresh button, make sure you call cancel() on the last async tasks you have created before you create new tasks. For example,
private void onRefreshClick(View v) {
if(mLastLoadItemTask != null) mLastLoadItemTask.cancel(true);
if(mLastLoadThumbnailTask != null) mLastLoadThumbnailTask.cancel(true);
mLastLoadItemTask = new LoadItems(...);
mLastLoadItemTask.execute();
}
Then, in the onPostExecute of each of your async tasks, first check to see if they were cancelled by calling isCancelled(). If they were cancelled, make sure the onPostExecute method does no work by just returning. For example,
protected void onPostExecute(...) {
if(isCancelled()) return;
//Adding items to list
//Or start load thumbnail task
}
As you can see that should prevent any unintentional or stale updates because the onPostExecute methods and your cancel calls will all happen on the main therad. The last thing I would suggest is to alter your loadThumbs task to be able to stop doing work as soon as possibly by checking isCancelled() whenever it makes sense to do so.
The following steps might help:
cache the results, whatever you have previously pulled from the net should be saved and quickly restored back when your application is launched. this way you avoid long delays and empty screens on application startup, which, in turn, stops the user from pressing 'reload'
make a boolean variable reload_in_progress, set it to true when you start pulling data from the net, and set it to false when all thumbnails are ready. 'reload' click handler should ignore clicks when reload_in_progress is true.
show some king of progress bar to the user, so (s)he knows it's already reloading and does not push reload again.
almost forgot, never update data shown to the user "live", this leads to wonderful situations, when the user clicks on item while it's changing and doing something completely different from what (s)he expected. long updates should keep its data to themselves and quickly swap old data for the new one only when everything is ready.
I have an activity, composed of an AsyncTask aiming to launch a request when the user clicks on the button. I have been looking for answers, but I didn't find the same problem, or it didn't the same for me. The code is doing what I want, but the ProgressDialog looks blocked as the spinner is not turning sometimes (almost all the time).
When I click on the button :
AsyncTask is launched -> showDialog() is called onPreExecute -> startSearch ( SearchManager launches a new AsyncTask with in the doInBackground there is a heavy call with network ) -> doInBackground in Activity waits for SearchManager to be loaded -> display.
Code for button :
button_search.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
new SearchTask().execute();
}
});
Code for AsyncTask in Search Activity :
private class SearchTask extends AsyncTask<Void,Void,Void>{
#Override
protected void onPreExecute(){
showDialog(DIALOG_LOADING_ID);
searchManager.startSearch();
}
#Override
protected Void doInBackground(Void... params) {
while(searchManager.isLoading()){
try {Thread.sleep(150);} catch(Exception e){};
}
return null;
}
#Override
protected void onPostExecute(Void ret){
try {dismissDialog(DIALOG_LOADING_ID);} catch (Exception e){};
if ( searchManager.errorOccurred() ){
//Error
} else {
//No Error
}
}
Code for SearchManagerAsyncTask : which is directly launched by startSearch
protected class SearchAsync extends AsyncTask <Void,Void,Void>{
#Override
protected Void doInBackground(ComSearchAds... datas) {
global.getDataManager().doSearch();
//... When finished
setIs_loading(false);
}
}
I'm apparently doing something wrong, but can't find what and how to avoid this. Thanks for your help !
SOLUTION :
Finally, it appears that the not spinning ProgressDialog was because I was using the same instance of ProgressDialog and
showDialog(DIALOG_LOADING_ID);
//doInBackground
dismissDialog(DIALOG_LOADING_ID);
used with causes problem, I changed to
removeDialog(DIALOG_LOADING_ID)
and now it's working fine.
Thanks All, and hope it can help someone someday !
You don't need to create another task , just instead of doing the search stuff via another activity.
all you need to do is to put you search cod ein doInbackGround() of search task. e.g
#Override
protected Void doInBackground(Void... params) {
global.getDataManager().doSearch();
return null;
}
also use class level variable to get search result to store true/false
#Override
protected void onPostExecute(Void ret){
// Set you result here
setIs_loading(my_searh_result);
try {dismissDialog(DIALOG_LOADING_ID);} catch (Exception e){};
if ( searchManager.errorOccurred() ){
//Error
} else {
//No Error
}
}
Could you please try to add a ProgressBar control in your layout file and set its Visible to true when starting async task and set to gone when end of process reached. Below is the code for the same.
<ProgressBar
android:layout_width="wrap_content"
android:id="#+id/progressBar1"
android:layout_height="wrap_content"></ProgressBar>
It's hard to say, but try this for onClickListner:
button_search.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
new SearchTask().execute();
setIs_loading(true);
searchManager.startSearch();
}
});
It's a pretty wild guess, but it might work
In my activity class i want to perform a series of long calculations that require around 5 sec to complete when i press a button. So in order to do that i have create a new class which does all the calculations in its run method(since it implements Runnable) and when finished i set a variable to true to indicate that. In the code that checks the if the button is pressed i start a new Thread passing my class in it and then cheking whether the run method has finished or not. If it finished i then print the data. The problem with this is that when i check if the calculations have finished they actually havent so it pass that line of code and never prints the data. I have tried to do the Async Class method but still i think it wont work. Is there a way to create the thread when i press the button and keep checking if had finished so i can print the data? Which piece of code in an Activity is actually get executed over and over again? Thanks for any information.
if(v.equals(this.button)) {
EditText param1 = (EditText)findViewById(R.id.param1);
EditText param2 = (EditText)findViewById(R.id.param2);
calculations = new MathCalc(param1.getText().toString(), param2.getText().toString());
new Thread(calculations).start();
while(!calculations.isReady());
Intent intent = new Intent(this,Show.class);
intent.putExtra("show1", calculations.getResult());
startActivity(intent);
}
This is want i want to achieve.
The AsyncTask is the right tool for this. The typical use case for the AsyncTask is that you want to do something small in the background and leave feedback through the UI before, during and/or after the task is done.
Be aware that running things in the background can get you in trouble if the user quits and restarts your activity a lot, since the background task will not end when the Activity is removed from screen.
An example activity is shown below. You could add the onPreExecute and onProgress methods to the AsynchTask to give the user feedback before and during the calculation.
public class CalcActivity extends Activity {
private Button button;
private TextView resultView;
public void onCreate() {
button = (Button) findViewById(R.id.my_button);
resultView = (TextView) findViewById(R.id.result);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
button.setEnabled(false);
AsyncCalculation calc = new AsyncCalculation();
calc.execute();
}
});
}
public class AsyncCalculation extends AsyncTask<Void, Void, Integer> {
#Override
protected Integer doInBackground(Void... params) {
int result = 0;
// Do some calculation
return result;
}
#Override
protected void onPostExecute(Integer result) {
// Set the result, start another activity or do something else
resultView.setText("The result was " + result);
button.setEnabled(true);
}
}
}
I don't see how this won't work with AsyncTask. You basically need to override two methods - doInBackground() and onPostExecute().
You're guaranteed that onPostExecute() will be invoked on the UI thread after the background computation finishes. You also don't have to worry how to update the UI Thread from another thread.
Here's a good example.
Use
Button someButton = (Button) findViewById(R.id.favouriteButton);
someButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while(!isDone){
doAlotOfCalculations();
}
}
});
thread.start();
}
});
private void doAlotOfCalculations(){
...
if(whenDone){
isDone = true;
}
....
}
Which piece of code in an Activity is actually get executed over and
over again?
There is no such a thing.
It is just onResume which executes every time you start(restart) this activity