I am trying to work with Asynctask, but everytime I'm getting its status, it always returns running.
What is wrong in my code?
This is how I load my asynctask:
LongOperation LongOperation = new LongOperation(finalLink[0], download_data);
LongOperation.execute();
Toast.makeText(getApplicationContext(), LongOperation.getStatus().toString(), Toast.LENGTH_SHORT).show();
This is my asynctask:
private class LongOperation extends AsyncTask<Void, Void, Void> {
public Download_data download_data;
public String link;
public boolean loading;
public LongOperation(String link, Download_data download_data){
this.link = link;
this.download_data = download_data;
}
#Override
protected Void doInBackground(Void... params) {
download_data.download_data_from_link(link);
return null;
}
protected void onPostExecute() {
finish();
}
#Override
protected void onPreExecute() {
Toast.makeText(getApplicationContext(),"Executed.", Toast.LENGTH_LONG).show();
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
Because you are checking status right after executing it:
LongOperation.execute();
Toast.makeText(getApplicationContext(), LongOperation.getStatus().toString(), Toast.LENGTH_SHORT).show();
AsyncTask runs on background thread. So right after calling execute() controls moves to display Toast. And by that time, task is still running.
You will receive finished status in onPreExecute of AsyncTask.
#Override
protected void onPostExecute(Void mVoid) {
Toast.makeText(getApplicationContext(), this.getStatus().toString(), Toast.LENGTH_SHORT).show();
finish();
}
In case you are confused about threads, do read this: Java Multithreading
The correct signature of onPostExecute() is really;
protected void onPostExecute (Result result)
Since you're not overriding the one in AsyncTask but defining another overload, it (and in its turn finish() is never called).
Fix the signature and it should complete as intended.
Related
I use an async task to upload an image and get some results.
While uploading the image I see a progress dialog, written in onPreExecute() method like this:
protected void onPreExecute() {
uploadingDialog = new ProgressDialog(MyActivity.this);
uploadingDialog.setMessage("uploading");
uploadingDialog.setCancelable(true);
uploadingDialog.show();
}
Ok when I press the back button, obviously the dialog disappears because of the setCancelable(true).
But (obviously) the async task doesn't stop.
So how can I fix this? I want to cancel both dialog and async task when I press the back button. Any ideas?
From SDK:
Cancelling a task
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.)
So your code is right for dialog listener:
uploadingDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
myTask.cancel(true);
//finish();
}
});
Now, as I have mentioned earlier from SDK, you have to check whether the task is cancelled or not, for that you have to check isCancelled() inside the onPreExecute() method.
For example:
if (isCancelled())
break;
else
{
// do your work here
}
FOUND THE SOLUTION:
I added an action listener before uploadingDialog.show() like this:
uploadingDialog.setOnCancelListener(new DialogInterface.OnCancelListener(){
public void onCancel(DialogInterface dialog) {
myTask.cancel(true);
//finish();
}
});
That way when I press the back button, the above OnCancelListener cancels both dialog and task. Also you can add finish() if you want to finish the whole activity on back pressed. Remember to declare your async task as a variable like this:
MyAsyncTask myTask=null;
and execute your async task like this:
myTask = new MyAsyncTask();
myTask.execute();
I spent a while figuring this out, all I wanted was a simple example of how to do it, so I thought I'd post how I did it. This is some code that updates a library and has a progress dialog showing how many books have been updated and cancels when a user dismisses the dialog:
private class UpdateLibrary extends AsyncTask<Void, Integer, Boolean>{
private ProgressDialog dialog = new ProgressDialog(Library.this);
private int total = Library.instance.appState.getAvailableText().length;
private int count = 0;
//Used as handler to cancel task if back button is pressed
private AsyncTask<Void, Integer, Boolean> updateTask = null;
#Override
protected void onPreExecute(){
updateTask = this;
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setOnDismissListener(new OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
updateTask.cancel(true);
}
});
dialog.setMessage("Updating Library...");
dialog.setMax(total);
dialog.show();
}
#Override
protected Boolean doInBackground(Void... arg0) {
for (int i = 0; i < appState.getAvailableText().length;i++){
if(isCancelled()){
break;
}
//Do your updating stuff here
}
}
#Override
protected void onProgressUpdate(Integer... progress){
count += progress[0];
dialog.setProgress(count);
}
#Override
protected void onPostExecute(Boolean finished){
dialog.dismiss();
if (finished)
DialogHelper.showMessage(Str.TEXT_UPDATELIBRARY, Str.TEXT_UPDATECOMPLETED, Library.instance);
else
DialogHelper.showMessage(Str.TEXT_UPDATELIBRARY,Str.TEXT_NOUPDATE , Library.instance);
}
}
create some member variables in your activity like
YourAsyncTask mTask;
Dialog mDialog;
use these for your dialog and task;
in onPause() simply call
if(mTask!=null) mTask.cancel();
if(mDialog!=null) mDialog.dismiss();
I would like to improve the code. When you canel the aSyncTask the onCancelled() (callback method of aSyncTask) gets automatically called, and there you can hide your progressBarDialog.
You can include this code as well:
public class information extends AsyncTask<String, String, String>
{
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... arg0) {
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
this.cancel(true);
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}
#Override
protected void onCancelled() {
Toast.makeText(getApplicationContext(), "asynctack cancelled.....", Toast.LENGTH_SHORT).show();
dialog.hide(); /*hide the progressbar dialog here...*/
super.onCancelled();
}
}
Most of the time that I use AsyncTask my business logic is on a separated business class instead of being on the UI. In that case, I couldn't have a loop at doInBackground(). An example would be a synchronization process that consumes services and persist data one after another.
I end up handing on my task to the business object so it can handle cancelation. My setup is like this:
public abstract class MyActivity extends Activity {
private Task mTask;
private Business mBusiness;
public void startTask() {
if (mTask != null) {
mTask.cancel(true);
}
mTask = new mTask();
mTask.execute();
}
}
protected class Task extends AsyncTask<Void, Void, Boolean> {
#Override
protected void onCancelled() {
super.onCancelled();
mTask.cancel(true);
// ask if user wants to try again
}
#Override
protected Boolean doInBackground(Void... params) {
return mBusiness.synchronize(this);
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
mTask = null;
if (result) {
// done!
}
else {
// ask if user wants to try again
}
}
}
public class Business {
public boolean synchronize(AsyncTask<?, ?, ?> task) {
boolean response = false;
response = loadStuff(task);
if (response)
response = loadMoreStuff(task);
return response;
}
private boolean loadStuff(AsyncTask<?, ?, ?> task) {
if (task != null && task.isCancelled()) return false;
// load stuff
return true;
}
}
I had a similar problem - essentially I was getting a NPE in an async task after the user had destroyed the activity. After researching the problem on Stack Overflow, I adopted the following solution:
volatile boolean running;
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
running=true;
...
}
public void onDestroy() {
super.onDestroy();
running=false;
...
}
Then, I check "if running" periodically in my async code. I have stress tested this and I am now unable to "break" my activity. This works perfectly and has the advantage of being simpler than some of the solutions I have seen on SO.
You can just ask for cancellation but not really terminate it. See this answer.
How to cancel AsyncTask
Full answer is here - Android AsyncTask Example
AsyncTask provides a better cancellation strategy, to terminate currently running task.
cancel(boolean mayInterruptIfitRunning)
myTask.cancel(false)- It makes isCancelled returns true. Helps to cancel the task.
myTask.cancel(true) – It also makes isCancelled() returns true, interrupt the background thread and relieves resources .
It is considered as an arrogant way, If there is any thread.sleep() method performing in background thread, cancel(true) will interrupt background thread at that time. But cancel(false) will wait for it and cancel task when that method completes.
If you invoke cancel() and doInBackground() hasn’t begun execute yet. onCancelled() will invoke.
After invoking cancel(…) you should check value returned by isCancelled() on doInbackground() periodically. just like shown below.
protected Object doInBackground(Params… params) {
while (condition)
{
...
if (isCancelled())
break;
}
return null;
}
I am using an AsyncTask in an activity.
here is my code
public class MyActivity extends AppCompatActivity {
EditText editUserNameLogin;
EditText editPassLogin;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
//ButterKnife.bind(this);
editUserNameLogin = (EditText) findViewById(R.id.input_username_login);
editPassLogin = (EditText) findViewById(R.id.input_password_login);
}
public class AsyncTaskClass extends AsyncTask<String, String, String> {
String strUserName = editUserNameLogin.getText().toString();
String passLogin = editPassLogin.getText().toString();
#Override
protected void onPreExecute() {
}
#Override
protected String doInBackground(String... params) {
Toast.makeText(MyActivity.this, passLogin, Toast.LENGTH_SHORT).show();
}
#Override
protected void onPostExecute(String r) {
}
}
but in doInBackground can't get values passLogin or strUserName
(Toast.makeText(MyActivity.this, passLogin,) don't show any text)
Try and execute AsyncTaskClass in onCreate
new AsyncTaskClass().execute(); //use this method and call this in onCreate
Try this one, inside onCreate
String response="checking";
new AsyncTaskClass().execute(response);
then create inner class AsyncTaskClass,
private class AsyncTaskClass extends AsyncTask<String,Void,String > {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... strings) {
String respose1 = strings[0];
return respose1;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);}
}
You can not perform UI operation inside background AsyncTask doInBackground method because AsyncTask not work with current UI thread, its create new thread while you initialize and execute.
Let me explain you in bref.
While activity start its stay with Activity Thread and when you complete activity operation and destroy its completely remove from operation task.
But while you start AsyncTask on Activity its start with individual operation stat that not depends on activity that you start, so if you perform UI operation in doInBackground method and in case Activity destroyed and you working on UI that already destroyed by activity and UI cannot get reference, its generate an exception. So it's necessary to work with current activity thread not another background thread.
There are many case that you can pass data inside AsyncTask, i'm comfortable with below operation, it can help you also.
// Pass data to AsyncTask comma separated values
new MyBackgroundTask().execute("Hello there!","How are you?");
private class MyBackgroundTask extends AsyncTask<String, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(String... strings) {
String message1 = strings[0];
String message2 = strings[1];
Log.d("_TAG_", "First String: " + message1);
Log.d("_TAG_", "Second String: " + message2);
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
}
}
For more information read Android Official Documents AsyncTask Developer Guides
You cant show ui operations like toast in doInBackground if you still want to do that then use this code to display toast while in doInBackground
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this, "", Toast.LENGTH_SHORT).show();
}
});
and also you need to call yourAsyncTaskObject.execute to start asynctask
I have no idea what exactly you want to achieve by such behavior.
But i am pointing out some point here . First of all you can not access any UI element in background thread .
#Override
protected String doInBackground(String... params) {
Toast.makeText(MyActivity.this, passLogin, Toast.LENGTH_SHORT).show();
}
The above code is not going to work as doInBackground runs asynchronously separate from UI thread.
If you want to show a toast on AsyncTask started then do it in onPreExecute or after execution do it in onPostExecute.
#Override
protected void onPreExecute() {
Toast.makeText(MyActivity.this, passLogin, Toast.LENGTH_SHORT).show();
}
And as i see you never execute the AsyncTask then how are you expecting anything from it. Do call execute().
new AsyncTaskClass().execute();
For more on AsyncTask read AsyncTask.
Try the following:
#Override
protected String doInBackground(String... params) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(MyActivity.this, passLogin, Toast.LENGTH_SHORT).show();
}
});
}
AsyncTask enables proper and easy use of the UI thread. This class
allows you to perform background operations and publish results on the
UI thread without having to manipulate threads and/or handlers.
new AsyncTaskClass("SEND STRING").execute();
You can pass this Your Value this way
private class AsyncTaskClass extends AsyncTask<String, String, String> {
String strRESPONSE="";
public MyAsyncTask(String str_GET) {
this.strRESPONSE=str_GET; // print "SEND STRING"
}
}
As far as I understand once an AsyncTask is called, the result is changed to null and the AsyncTask is cancelled. Is there a way to retain the result and pass it to onPostExecute(String result). developer.android.com says not to call these functions explicitly.
The app basically scans images and if a user cancels the async task, I'd like the async task to display the images scanned so far. So the result should not be set to null.
Is this possible to accomplish? If yes, how?
class openCVOperation extends AsyncTask<String, String, String>{
private MainActivity context = null;
/*lots of variables here*/
public openCVOperation(MainActivity context1) {
context = context1;// set context from mainActivity
// which
// inherits Activity super class.
// Needed
// for accessing widgets.
}
#Override
protected void onPreExecute() {
pd = new ProgressDialog(context);
pd.setIndeterminate(false);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setMax(100);
pd.setCancelable(true);
pd.setCanceledOnTouchOutside(false);
pd.setMessage("Starting up");
pd.show();
}
#Override
protected String doInBackground(String... params) {
publishProgress("Finding path to Storage...");
path = Environment.getExternalStorageDirectory();
p = path.getAbsolutePath();
p=p+"/location";
rm(p);// this has a loop!
return null;
}
#Override
protected void onCancelled()
{
System.out.println("In onCancelled");
super.onCancelled();
}
#Override
protected void onPostExecute(String result) {
pd.dismiss();
/*post execute stuff*
}
rm(p) has a loop, so I tried using isCancelled() as a condition, but that didn't work.
In the doInBackground
if (isCancelled())
{
return // image so far
}
onPostExecute(String result)
{
// show result
}
I just had to add this to my doInBackground()
pd.setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
// TODO Auto-generated method stub
task.cancel(true);
}
});
Where pd is my progress dialog.
Also make sure you check for isCancelled() in doInBackground() or onCancelled() will never be invoked and the application will force close.
Collect the results:
public class MyTask extends AsyncTask<Void,Void,Void>{
private final List<String> data;
public MyTask(){
data = new ArrayList<String>();
}
public synchronized List<String> getData(){
return new ArrayList<String>(data); //--current data snapshot--
}
private synchronized collect(String s){
data.add(s);
}
#Override
public Void doInBackground(Void...args){
//---do stuff--
collect(/*-stuff-*/);
}
}
You won't lose anything even if thread is interrupted.
If onCancelled is not being called, then your rm method is still running.
Because as you mentioned, it's running a loop.
The best way to control the process (know if it needs to be stopped) is by polling or tediously checking the status of a volatile boolean variable within your rm method.
For example, create a static volatile boolean variable within your AsyncTask class called cancel. Set this variable to false in the onPreExecute method.
In your rm method, check to see if cancel is true before and after the heavy tasks (opening a file, reading a file, part of a download loop).
If it's true, then break out of the method with a return statement.
Better yet, make your rm method return an Integer, 0 for Good and 1 for cancelled.
And finally, right before the doInBackground method hits return, see if you need to call a cancel on the thread or not.
public class asyncTask extends AsyncTask<Void, Void, Void>
{
private static synchronized boolean cancel;
protected void onPreExecute()
{
cancel = false;
}
protected String doInBackground(Void ... params)
{
rm(p);
if(cancel)
asyncTask.cancel;
else
return null;
}
protected void onCancelled()
{
// only executed if doInBackground resulted in a cancel == true
}
protected void onPostExecute(Void param)
{
/// only executed if doInBackground resulted in a cancel == false
}
private int rm(String str)
{
if(cancel)
return 1;
//do part of task
if(cancel)
return 1;
//another part of task
if(cancel)
return 1;
//another part of task
return cancel ? 1 : 0;
}
}
Hi I'm making Login page that access MySQL database. But my Activity always runs the code that check fail/success before it finishes the AsyncTask.
I tried using asynctask.get() method, but it just freeze my UI and doesn't work.
I tried this answer that said I should call the result-checker method inside onPostExecute().
But since I need to change the TextView to show success/failed, it results in NullPointerException because I instantiate the TextView inside onCreate().
I can't move the TextView instantiation into constructor because it will return NullPointerException unable to instantiate activity ComponentInfo.
Login.java
public class Login extends Activity{
//declare global Views here
protected void onCreate(Bundle bundle){
//Setup views
}
protected void onClick(View v){
//Setup necessary variables
AsyncClass async = new AsyncClass(this);
async.execute(username, password);
}
public void checkSuccess(boolean success){
if(success)
textView1.setText("Success");
else
textView1.setText("Failed");
}
}
AsyncClass.java
public class AsyncClass extends AsyncTask<String, String, JSONObject>{
protected JSONObject doInBackground(String... params){
//access database
}
protected void onPostExecute(JSONObject json){
//read the json result
Login login = new Login();
login.checkSuccess(true);
}
}
Any solution? Thanks
How about making AsyncTask as your inner class?
So your code should look something like below.
public class Login extends Activity {
//declare global Views here
protected void onCreate(Bundle bundle) {
//Setup views
}
protected void onClick(View v) {
new AsyncClass().execute(username, password);
}
public void checkSuccess(boolean success) {
if (success) textView1.setText("Success");
else textView1.setText("Failed");
}
class AsyncClass extends AsyncTask < String, String, JSONObject > {
protected JSONObject doInBackground(String...params) {
//access database
}
protected void onPostExecute(JSONObject json) {
checkSuccess(true / false);
}
}
}
try this
protected void onPostExecute(JSONObject json){
//read the json result
Login login = (Login)context; // object that you pass to task constructor
login.checkSuccess(true);
}
Also you can add progress dialog to your task to indicate some job execution
public class BaseTask<T> extends AsyncTask<Object, Void, T> {
public Context context;
public ProgressDialog dialog;
public BaseTask(Context context) {
this.context = context;
this.dialog = new ProgressDialog(context);
}
#Override
protected void onPreExecute() {
this.dialog.setMessage(context.getResources().getString(R.string.loading));
this.dialog.show();
}
#Override
protected T doInBackground(Object... objects) {
//....
return something;
}
#Override
protected void onPostExecute(T result) {
if (dialog != null && dialog.isShowing())
dialog.dismiss();
// do something
}
}
You cannot edit the UI from the async task thread. In order to make updates to the UI thread, use the onProgressUpdate() method. This method is part of your AsyncTask class, is actually executed in the main UI Thread (I hope you use the async task as a nested class btw, since it is declared public I guess your not. You should change that). The onProgressUpdate() Method is called by the OS itself if you call publishProgress(...) inside your Async task.
A small sample:
protected JSONObject doInBackground(String... params){
publishProgress("test");
}
/**
* This method is part of the Async Task
*/
protected void onProgressUpdate(String... progress) {
login.checkSuccess(true);
}
I would use it this way, just override your onPostExecute where you need it or create a own interface
//create a object f your asyncclass and
//override the onPostExecute where you need it
mInfo = new ASYNCCLASS({
#Override
public void onPostExecute(Object result){
//doSomething something with your views!
}
}).execute();
Waiting is not the answer, because you do not know how long your Asynctask will take to end.
Code above is not tested, just pseudoce, but it should show what i mean.
Do not have my IDE round here, so if anybody would correct the brackets if neccessary would be great!
Greetz
Is there anyway to use AsyncTask without passing in any parameters? I am currently passing in an empty string, but I'm not doing anything with it:
DownloadWebPageTask task = new DownloadWebPageTask();
task.execute(new String[] { "" });
class DownloadWebPageTask extends AsyncTask<String, Void, String> {
private final ProgressDialog dialog = new ProgressDialog(MainScreen.this);
#Override
protected void onPreExecute() {
dialog.setMessage("Gathering data for\n"+selectedSportName+".\nPlease wait...");
dialog.show();
}
#Override
protected String doInBackground(String... urls) {
//go do something
return "";
}
#Override
protected void onPostExecute(String result) {
dialog.dismiss();
startTabbedViewActivity();
}
}
private void startTabbedViewActivity(){
Intent intent = new Intent(MainScreen.this, TabbedView.class);
intent.putExtra(SPORT_NAME_EXTRA, selectedSportName);
intent.putExtra(HEADLINES_FOR_SPORT_EXTRA, existingSportHeadlines.get(selectedSportName));
intent.putExtra(SCORES_FOR_SPORT_EXTRA, existingSportScores.get(selectedSportName));
intent.putExtra(SCHEDULE_FOR_SPORT_EXTRA, existingSportSchedule.get(selectedSportName));
startActivity(intent);
}
For some reason, when I run the code as shown, with nothing happening in doInBackground(), the dialog dissapears, and the TabbedView activity starts.
But, when I use doInBackground() to run some code, the dialog dissapears, but, the TabbedView activity won't start. So I'm wondering if I could be doing anything differently?
Yes you can use AsyncTask without passing a String to the doInBackground() method.
Just change the first and third generic types from String to Void:
class DownloadWebPageTask extends AsyncTask<Void, Void, Void> {
}
From the doc:
The three types used by an asynchronous task are the following:
1)Params, the type of the parameters sent to the task upon execution.
2)Progress, the type of the progress units published during the
3) background computation. Result, the type of the result of the
background computation.
For the signature of onPostExecutetry this:
#Override
protected void onPostExecute(Void unused) {
}
EDIT:
For the parameters it's actually very simple.
Consider this:
class MyTask extends AsyncTask<Type1, Type2, Type3> {
#Override
protected void onPreExecute() {
}
#Override
protected Type3 doInBackground(Type1... param) {
}
#Override
protected void onProgressUpdate(Type2... progress) {
}
#Override
protected void onPostExecute(Type3 result) {
}
}
In order to determine what Type1, Type2 and Type3 should be, you'll have to ask yourself 3 questions:
What parameter should I pass to my task? => Type1
What is the type of the intermediate results that need to be shown during processing? =>
Type2
What is the type of the resulting operation? => Type3
In your case, I don't know whether the URL that you are downloading data from is defined in a globally or you want to pass it to the task. If it's defined globally, then you don't Type1 should be Void.
If you want to pass it to the task, then you can pass it to the doInBackground() method and Type1 would be String.
Obviously for your case you don't need to worry about Type2 since you aren't publishing any intermediate results and since you aren't doing anything with the result in onPostExecute() then Type3 is Void too.
To summarize you'll have:
class DownloadWebPageTask extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... urls) {
// do something with urls[0]
}
#Override
protected void onPostExecute(Void unused) {
// dismiss pd and start new intent
}
}
Or:
class DownloadWebPageTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... unused) {
}
#Override
protected void onPostExecute(Void unused) {
// dismiss pd and start new intent
}
}
Depending on your needs. Is that clear enough?
You simple specify Void for AsyncTask generics
class DownloadWebPageTask extends AsyncTask<Void, Void, Void> {
Look at the AsyncTask generics section