I have created an AsyncTask which read JSONArray in the doInBackground Method and return an ArrayList of custom Items (ArrayList). Before this, in the onPostExecute method i move the ArrayList charged in the AsyncTask to another ArrayList of the Main thread, but i think that my AsyncTask never ends and still working. Here I put my code:
Here the AsyncTask:
private class ReadJSONTask extends AsyncTask<Void, Void, ArrayList<Item>>{
#Override
protected ArrayList<Item> doInBackground(Void... params) {
// TODO Auto-generated method stub
ArrayList<Item> auxList = new ArrayList<Item>();
LoadData(auxList); //Method that reads JSON and load information in the ArrayList
return auxList; // Return ArrayList
}
#Override
protected void onPostExecute(ArrayList<Item> result) {
// TODO Auto-generated method stub
Log.i("OnPostExecute", String.valueOf(result.size())); //The size of the array
listMain = result; // Move the data of the AsyncTask to the main Thread
Log.i("OnPostExecute", String.valueOf(listaComic.size())); //The size of the ArrayList I use in the Main Thread
}
}
Here the call to the AsyncTask in the Main Thread:
if (isOnline()){ //Return true if there is internet connection
ReadJSONTask task = new ReadJSONTask();
task.execute();
Log.i("Main Thread - listMain Size", String.valueOf(listMain.size())); //Never executed
//This for loop its only for debug purposes, never executed
for (Item item : listMain){
Log.i("Items", item.toString());
}
}
In the log i see that all Log in the onPostExecute() method are printed, but nothing from the Main Thread.
I don't know where is the error to fix it, i have been working on it 2 days and searching in forums, here in StackOverflow and i can't fix that :S
As name indicates AsyncTask is asynchronous, but you for some reason expects execute() to be blocked unless async task ends, which is wrong. Your code works fine and I expect listMain to simply be empty and once execute() fires asynctask, for would show nothing because async task is not done yet. You should rework your app logic, so async task could tell "main thread" it finished. I.e. move your for loop to separate method and call it from onPostExecute().
Related
I have a method that should return a long value. Within this method, there is an asyncTask that inserts the information into the room database. How can I send the asyncTask return value as the result of the same method that I called it ?!
Public long insert(MyTask task){
.
.
.
return /* result of AsyncTask */
}
When you are dealing with Thread or AsyncTask, you cannot use their result as a return of the method that starts them.
Results of AsyncTask are handled by onPostExecute.
You can override the onPostExecute method of the AsyncTask. Then process your result there.
class MyAsyncTask {
void onPostExecute(long result) {
// process the result here
}
}
I am writing a Android application which reads data from a SQLite Database and then displays the data on a next screen. Whenever I was doing a query on the database I would get an error message that too much work is being done on the main thread.
I then put my query in a new Thread:
(new Thread()
{
public void run()
{
Looper.prepare();
try
{
FPJobCardWizard data = dbHelperInstance.loadFPJobCardWizardFull(fitmentHash);
wState.fitmentItemSet(data.fitmentItemGet());
} catch (Exception e) {e.printStackTrace();}
Looper.loop();
}
}).start();
Now the gui/main thread is completing it's operation prior to the Query being complete and as a result the data variable is still empty. I read a few posts and the API documentation and it seems that I need to use a Looper (this seems to be the correct fix) but I have never used a Looper and cannot seem to get it to work.
Please can you check the code above and guide me in the right direction.
Thank you all in advance.
the best choice here will be using an AsyncTask, as it will enables you to perform all the background work in a background thread, then when the result is generated it will apply it using the UI thread:
So, as explained in the life cycle of AsyncTask, you can do all of your background work in the method doInBackground() and then do all of your UI work on the method onPostExecute() which will be executed after taking the result from doInBackground() method according to the life cycle, and to put your hands more on the AsyncTask, have a look at this example which provides the following example code:
public class AsyncTaskTestActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// This starts the AsyncTask
// Doesn't need to be in onCreate()
new MyTask().execute("my string paramater");
}
// Here is the AsyncTask class:
//
// AsyncTask<Params, Progress, Result>.
// Params – the type (Object/primitive) you pass to the AsyncTask from .execute()
// Progress – the type that gets passed to onProgressUpdate()
// Result – the type returns from doInBackground()
// Any of them can be String, Integer, Void, etc.
private class MyTask extends AsyncTask<String, Integer, String> {
// Runs in UI before background thread is called
#Override
protected void onPreExecute() {
super.onPreExecute();
// Do something like display a progress bar
}
// This is run in a background thread
#Override
protected String doInBackground(String... params) {
// get the string from params, which is an array
String myString = params[0];
// Do something that takes a long time, for example:
for (int i = 0; i <= 100; i++) {
// Do things
// Call this to update your progress
publishProgress(i);
}
return "this string is passed to onPostExecute";
}
// This is called from background thread but runs in UI
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// Do things like update the progress bar
}
// This runs in UI when background thread finishes
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
// Do things like hide the progress bar or change a TextView
}
}
}
I have an AsyncTask which is called whenever the camera is moved in Google Maps because i want to load new data from web services against the co-ordinates of center point of the map. Now everything is working fine but the thing is that whenever user move the map very fast, the tasks start queuing up. In the result when user stop moving map, the task in queues keep loading the old data until the task which is in the last, come with actual data.
My AsyncTask Class:
private class GetOffersLocations extends AsyncTask<String[], Void, Boolean> {
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
loader.setVisibility(View.VISIBLE);
}
#Override
protected Boolean doInBackground(String[]... params) {
// TODO Auto-generated method stub
[web api called in here and load the data against the center point (latlng)]
}
#Override
protected void onCancelled() {
// TODO Auto-generated method stub
super.onCancelled();
this.cancel(true);
}
#Override
protected void onPostExecute(Boolean result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
loader.setVisibility(View.GONE);
if (result) {
[drawing pins on map here]
}
}
}
And here in a function i called this AsyncTask on camera move of the map:
private void showMarkers(String lat, String lng, String radius, int position) {
String[] latLng = { lat, lng, radius, String.valueOf(position) };
new getOffersLocations().execute(latLng);
}
Now this function is called in OnCameraChangeListener and when ever user move the camera this asynctask is called.
So, i think i properly made my question and if not please correct me.
Waiting for help.
Thanks.
You can't stop and start again an AsyncTask, but you can cancel it execution by calling
myGetOffersLocations.cancel(true);
This will interrupt the execution, however, you will need to create a new AsyncTask object to be able to run it again, so you can do this:
myGetOffersLocations.cancel(true);
myGetOffersLocations = new GetOffersLocations();
And then, run it again.
NOTE: Make sure you create an object reference to the AsyncTask, instead of executing it directly as you're doing on your method.
Replace this:
new getOffersLocations().execute(latLng);
With this:
getOffersLocations myOffers = new getOffersLocations();
myOffers.execute(latLng);
in your doInBackground make sure you are doing something like this
while(!isCancelled()){
// Do I/O work
}
and your for loop
for(int i = 0; i < 100 && !isCancelled(); ++i){
// Do something
}
You can cancel it like this
myGetOffersLocations.cancel(true);
myGetOffersLocations = new GetOffersLocations();
Cancelling a task (quoted from AsyncTask | Android Developer)
A task can be cancelled at any time by invoking cancel(boolean).
Invoking this method will cause subsequent calls to isCancelled() to
return true.
After invoking this method, onCancelled(Object), instead of
onPostExecute(Object) will be invoked after doInBackground(Object[])
returns.
To ensure that a task is cancelled as quickly as possible, you should
always check the return value of isCancelled() periodically from
doInBackground(Object[]), if possible (inside a loop for instance.)
You can create an object of the AsyncTask class and call execute(..) on it:
GetOffersLocation mGOL = new getOffersLocations();
mGol.execute(latLng)
When you need to cancel the task call:
mGol.cancel(true);
This will send a signal to ongoing task and try to cancel it.
I say try, because AsyncTasks do not terminate everytime necessarily.
I have an AsynchTask which is called from with in a function in my MainActivity.
After the onPostExecute method is executed ,the control doesn't seem to return to the function where I called the AsynchTask.
public class MainActivity extends FragmentActivity {
private class GetPlaces extends AsyncTask<AsynchInput,Void,AsynchOutput>{
protected AsynchOutput doInBackground(AsynchInput... placesURL) {
...
}
protected void onPostExecute(AsynchOutput result) {
....
}
}
public void showInterestingPlacesNearby(GoogleMap myMap,Location loc){
....
...
new GetPlaces().execute(new AsynchInput(myMap,placesSearchStr));
}
}
The code I write after the new new GetPlaces().execute doesn't execute. How do I continue after the AysnchTask returns.
edit: I used the AsynchTask as an inner class for my MainActivity.
AsyncTask is used to run code on the background thread from the UI thread. This does not behave like a function call, and execution continues immediately with the statement following the .execute() call. At the same time, the code in doInBackground of your AsyncTask is executed on the background thread and runs without blocking the UI thread. This is the intended behaviour, and without it using AsyncTask would be pointless.
The only way to respond to the end of the async operation is to do that within onPostExecute - you can also take action within onProgressUpdate if you need to take some action in response to your background code.
So your showInterestingPlacesNearby() method does not need to do anything after the .execute call - the code you want to execute there should probably go into onPostExecute.
Alternatively, you could use onProgressUpdate to process items as they are found, instead of waiting for the entire async operation to complete before showing everything at once. For this you need to use publishProgress in your doInBackground whenever something is found.
a possibile solution could be:
take the codes you entered after .execute and put that in a private method
private void AfterTask() {
//your code written after .execute here
}
in the onPostExecute, just call that method
protected void onPostExecute(AsynchOutput result) {
AfterTask();
}
myTask.execute("url");
String result = "";
try {
result = myTask.get().toString();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Basically, do I have to put code I want to run on another thread inside doInBackground, or can I call another function/class/whatever-it-is-functions-are-called-in-JAVA within doInBackground and have it run asynchronously? IE: (example code I found online)
protected String doInBackground(String... params) {
for(int i=0;i<5;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");
return null;
}
is how I have seen it done, but can I instead do:
protected String doInBackground(String... params) {
postToServer(x,y,z,h);
}
and have it call a function I already wrote and then have that function run in another thread? Sometimes my HTTP server is a bit slow to respond (it is but a lowly testing server at the moment) and Android automatically pops up the kill process box if my postToServer() call takes more than 5 seconds, and also disables my UI until the postToServer() call finishes. This is a problem because I am developing a GPS tracking app (internally for the company I work for) and the UI option to shut the tracking off freezes until my postToServer() finishes, which sometimes doesn't ever happen. I apologize if this has been answered, I tried searching but haven't found any examples that work the way I'm hoping to make this work.
You can do that, but you will have to move the UI updates to onPostExecute as it is run on the UI thread.
public MyAsyncTask extends AsyncTask<foo, bar, baz> {
...
protected String doInBackground(String... params) {
postToServer(x,y,z,h);
}
protected void onPostExecute(Long result) {
TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");
}
....
}
You may want to pass in the TextView to the constructor of the AsyncTask and store it as a WeakReference.
private final WeakReference textViewReference;
public MyAsyncTask(TextView txt) {
textViewReference = new WeakReference<TextView>(txt);
}
And then in onPostExecute you would make sure that the TextView reference still exists.
protected void onPostExecute(Long result) {
TextView txt = textViewReference.get();
if (txt != null)
txt.setText("Executed");
}
If you want to notify the user that the task is executing I would put that before invoking the AsyncTask.
myTextView.setText("Update in progress...");
new MyAsyncTask().execute();
then in onPostExecute set the TextView to say "Update complete."
Have you tried it the second way?
From what you've posted it seems like it should work fine how you have it in the second example.
However (perhaps unrelated to your question?) in your first example I think it will fail because you are trying to change the UI from a background thread. You'd want to put the parts that manipulate the TextView inside of onPostExecute() rather than doInBackground()
Yes you can, the call to your postToServer method (that's the name in java) will run off the main thread.
Everything inside the doInBackground method of an AsyncTask is run on a pooled thread, but be sure to NOT invoke it directly! Call execute on your asynktask instead, the android framework will do the work for you and run doInBackground on another thread.
try doing something like this:
new AsyncTask<Void, Void, Void>() {
#Override
// this runs on another thread
protected Void doInBackground(Void... params) {
// assuming x, y, z, h are visible here
postToServer(x, y, z, h);
return null;
}
#Override
// this runs on main thread
protected void onPostExecute(Void result) {
TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");
}
}.execute(); // call execute, NOT doInBackGround
Also, notice that every other method of AsyncTask, such as onPostExecute runs on the main thread, so avoid heavy loading them.
Basically The Bottom Line Is the doInBackground() method is Can't interact with The Ui Thread Or The Main thread. that's Why When You are Try To Interact With The TextView in doInBackground () it Will Crash the UI Thread Cuz It's Illegal.
so if anytime You want to Interact with the UI Thread,When You are Working on doInBackground You need to Override
OnPostExecute() //this Function is Called when The doInBackground Function job is Done.
So You can Update The UI Thread Content By this When You're Job is Done In doInBackground () or You are In doInBackground ()