Android AsyncTask - onPostExecute not called (ProgressDialog) - android-asynctask

I have the following code:
try {
res = new Utils(ubc_context).new DownloadCalendarTask().execute().get();
} catch (InterruptedException e) {
Log.v("downloadcalendar", "interruptedexecution : " + e.getLocalizedMessage());
res = false;
} catch (ExecutionException e) {
Log.v("downloadcalendar", "executionexception : " + e.getLocalizedMessage());
res = false;
}
Log.v("displaymenu", "A");
public class Utils {
private Context context;
public Utils(Context context) {
this.context = context;
}
public class DownloadCalendarTask extends AsyncTask<Void, Void, Boolean> {
private ProgressDialog dialog;
public DownloadCalendarTask() {
dialog = new ProgressDialog(context);
}
protected void onPreExecute() {
Log.v("preexecute", "A");
dialog.setMessage("Loading calendar, please wait...");
Log.v("preexecute", "B");
dialog.show();
Log.v("preexecute", "C");
}
protected Boolean doInBackground(Void... arg0) {
// do some work here...
return (Boolean) false;
}
protected void onPostExecute() {
Log.d("utils", "entered onpostexecute");
dialog.dismiss();
}
}
}
The first part of code is attached to an onClick listener for a button. When I click the button the button flashes (as it does to show it has been clicked), and then after about 8 seconds the Loading dialog appears but never finishes.
According to logcat, as soon as I click the button onPreExecute is executed as is Dialog.show(), so my first problem is why is there this 8 second delay? During these 8 seconds, logcat shows that doInBackground is being executed. However, according to logcat (this is the second problem) onPostExecute is never called (and so Dialog.dismiss()) is never run.
Logcat shows that everything following DownloadCalendarTask().execute().get() is being executed, so it's as if onPostExecute has just been skipped.
Many thanks for your help!

You are calling AsyncTask.get() which causes the UI thread to be blocked while the AsyncTask is executing.
new DownloadCalendarTask().execute().get();
If you remove the call to get() it will perform asynchronously and give the expected result.
new DownloadCalendarTask().execute();
Edit:
You will also need to update the parameters to your onPostExecute method, they need to include the result. e.g.
protected void onPostExecute(Boolean result) {

Related

Problem adding a new record in my Xamarin app

I am using Freshsmvvm in my project and I want to display a list of operations,
this is my method from the crud
public List<Operation> GetAll()
{
try
{
return connection.Table<Operation>().ToList();
}
catch (Exception ex)
{
StatusMessage = $"Error: {ex.Message}";
}
return null;
}
In my viewModel i'm have a list and a method to obtain the saved records
private List<Operation> _listOp;
public List<Operation> ListOp
{
get { return _listOp; }
set
{
_listOp = value;
RaisePropertyChanged();
}
}
private void GetOp()
{
ListOp = App.OperationRepository.GetAll();
}
*add the GetOp method in the constructor to load in the collectionview*
public override void Init(object initData)
{
GetOp();
}
What happens is that the list does not update, I have to close the application and when I open it again, the entered record appears.
This is the list without adding a new record
This is the list with a log after restarting the app
You can use the method OnAppearing() to refresh your list.
protected override async void OnAppearing()
{
base.OnAppearing();
ListOp = App.OperationRepository.GetAll();
}

Finish activity when onPostExecute is called (in AsyncTask)

I use the GMS Drive sample demo.
I want to select a file (with Drive dialog open file), download the file, then finish the activity.
My problem is if I use finish() in the onActivityResult, I cannot get the result in my main activity, if I use finish() in the onPostExecute, the dialog is not closed, and I need to press "Cancel" to return to my main activity (with the result). I would like to return without pressing "cancel" button...
I use the RetrieveContentsActivity and PickFileWithOpenerActivity from the demo.
Here is my code :
public class RestoreActivity extends DriveActivity {
private static final int REQUEST_CODE_OPENER = 1;
#Override
public void onConnected(Bundle connectionHint) {
super.onConnected(connectionHint);
IntentSender intentSender = Drive.DriveApi
.newOpenFileActivityBuilder()
.setSelectionFilter(Filters.contains(SearchableField.TITLE, "settings"))
.build(getGoogleApiClient());
try {
startIntentSenderForResult(intentSender, REQUEST_CODE_OPENER, null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
Log.w(TAG, "Unable to send intent", e);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_OPENER:
if (resultCode == RESULT_OK) {
DriveId driveId = data.getParcelableExtra(OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);
new RetrieveDriveFileContentsAsyncTask(RestoreActivity.this).execute(driveId);
}
finish(); // if I put finish() here, I cannot get the result in onActivityResult (main activity)
break;
default:
super.onActivityResult(requestCode, resultCode, data);
}
}
final private class RetrieveDriveFileContentsAsyncTask extends ApiClientAsyncTask<DriveId, Boolean, String> {
public RetrieveDriveFileContentsAsyncTask(Context context) {
super(context);
}
#Override
protected String doInBackgroundConnected(DriveId... params) {
String contents = null;
DriveFile file = Drive.DriveApi.getFile(getGoogleApiClient(), params[0]);
DriveApi.DriveContentsResult driveContentsResult = file.open(getGoogleApiClient(), DriveFile.MODE_READ_ONLY, null).await();
if (!driveContentsResult.getStatus().isSuccess()) {
return null;
}
DriveContents driveContents = driveContentsResult.getDriveContents();
BufferedReader reader = new BufferedReader(
new InputStreamReader(driveContents.getInputStream()));
StringBuilder builder = new StringBuilder();
String line;
try {
while ((line = reader.readLine()) != null) {
builder.append(line);
}
contents = builder.toString();
} catch (IOException e) {
Log.e(TAG, "IOException while reading from the stream " + e.toString());
}
driveContents.discard(getGoogleApiClient());
return contents;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Intent returnIntent = new Intent();
returnIntent.putExtra("settings",result);
if (result == null) {
Log.w(TAG, "Error");
setResult(RESULT_CANCELED,returnIntent);
} else {
Log.i(TAG, "OK");
setResult(RESULT_OK,returnIntent);
}
// if I put finish() here nothing happens, and dialog is still opened till I press "Cancel" button
}
}
}
How can I return to the main activity after onPostExecute and stop intent DriveApi ?
Thanks
I found a solution that I don't like : make it in 2 steps.
pick the file using the PickFileActivity from demo, return the driveId by declaring it public in MainActivity (public static DriveId driveId) and changing code like this :
MainActivity.driveId = data.getParcelableExtra(OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);
move the AsyncTask in my MainActivity.
If someone find another solution ?

Application crashes when I press back button using AsyncTask

I am trying to use AsyncTask and the activity is working perfectly but I am facing a problem. The problem comes after I have pressed back button, because pressing this button my app crashes. I have seen other posts saying that I must cancel the task in onStop() and onDestroy() but still crashes. Does anyone have any idea how can I solve that?
private class MyAsyncTask extends AsyncTask<Void, Integer, Boolean> {
#Override
protected Boolean doInBackground(Void... args0) {
for(int i=1; i<=10; i++) {
try{
if(isCancelled())
break;
publishProgress(i*10);
Thread.sleep(1000);
}catch (InterruptedException e){}
}
return null;
}
/*
* it will update the publishProgress method and it will
* update the interface (if it's necessary)
*/
#Override
protected void onProgressUpdate(Integer... values) {
int progreso = values[0].intValue();
pbarProgreso.setProgress(progreso); // showing progress
pbarProgreso.setSecondaryProgress(progreso + 5);
}
/*
* Initializing progressBar
*/
#Override
protected void onPreExecute() {
pbarProgreso.setMax(100); // maximum value for process bar
pbarProgreso.setProgress(0); // minimum value to start
}
#Override
protected void onPostExecute(Boolean result) {
if(!this.isCancelled())
Toast.makeText(getApplicationContext(), "Task finished!",
Toast.LENGTH_SHORT).show();
}
#Override
protected void onCancelled() {
Toast.makeText(getApplicationContext(), "Task cancelled!",
Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onStop() {
super.onStop();
if(task != null && task.getStatus() == Status.RUNNING){
task.cancel(true);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
if(task != null && task.getStatus() == Status.RUNNING) {
task.cancel(true);
}
}
It's because when you press back button, AsyncTask continues to work, and when it do context related work, that context no longer exists, and a crash happens, it's better to use a "isResumed" boolean indicator variable inside an activity, and set it to false in onPause and set to true inside onResume, and inside an AsyncTask do context related things, inside an if condition.
Or if this code is inside a fragment, can use isAdded() method, to check if fragment is active or not. Cancel is also important, but there may be a delay, between an Activity pause and AsyncTask cancel, so keeping that variable is important.

Fatal Exception: java.lang.IllegalArgumentException occurs from ProgressDialog

I've 10 apps which uses AsyncTasks. As you know i show progressdialog in asynctasks to show progress of the task. But there is a problem that i couldn't solve so far about progressdialog.
Here is one of my AsyncTask class (which is not in a other class);
public class GetBalanceAsyncTask extends AsyncTask<Void, Void, String> {
Context context;
ProgressDialog pd;
public GetBakiyeAsyncTask(Context context) {
this.context = context;
}
#Override
protected String doInBackground(Void... arg0) {
String userAgent = HttpHelper.getRandomUserAgent(context);
return HttpHelper.post(PreferenceHelper.getBalanceQueryAPI(context), userAgent);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
pd = ProgressDialog.show(context, "","Please wait...",true);
}
#Override
protected void onPostExecute(String result) {
try {
if (pd != null & pd.isShowing()) {
pd.dismiss();
pd = null;
}
} catch (IllegalArgumentException e) {
pd = null;
e.printStackTrace();
}
if (result != null & result.length() > 0) {
Utils.doTask(result);
} else {
Utils.ShowToast(context,
"An error has occurred, please try again.",
STYLE_CONFIRM, LENGTH_LONG);
}
super.onPostExecute(result);
}
}
and the execption is
java.lang.IllegalArgumentException: View not attached to window manager
at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:381)
at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:226)
at android.view.Window$LocalWindowManager.removeView(Window.java:432)
at android.app.Dialog.dismissDialog(Dialog.java:278)
at android.app.Dialog.access$000(Dialog.java:71)
at android.app.Dialog$1.run(Dialog.java:111)
at android.app.Dialog.dismiss(Dialog.java:268)
at fragments.RuyalarFragment$getRuyalarAsyncTask.onPostExecute(GetBalanceAsyncTask.java:27)
at fragments.RuyalarFragment$getRuyalarAsyncTask.onPostExecute(GetBalanceAsyncTask.java:1)
at android.os.AsyncTask.finish(AsyncTask.java:417)
at android.os.AsyncTask.access$300(AsyncTask.java:127)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3691)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:665)
at dalvik.system.NativeStart.main(NativeStart.java)
I've searched the solution almost everywhere but there is no working results. Most of answers contain use isFinishing, onDestroy or something like this but no body is sure which is working.
Thanks for advice.
How to reproduce the bug:
Enable this option on your device: Settings -> Developer Options -> Don't keep Activities.
Press Home button while the 'AsyncTask' is executing and the ProgressDialog is showing.
The Android OS will destroy an activity as soon as it is hidden. When onPostExecute is called the Activity will be in "finishing" state and the ProgressDialog will be not attached to Activity.
How to fix it:
Check for the activity state in your onPostExecute method.
Dismiss the ProgressDialog in onDestroy method. Otherwise, android.view.WindowLeaked exception will be thrown. This exception usually comes from dialogs that are still active when the activity is finishing.
try this code :
public class YourActivity extends Activity {
<...>
private void showProgressDialog() {
if (pDialog == null) {
pDialog = new ProgressDialog(StartActivity.this);
pDialog.setMessage("Loading. Please wait...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
}
pDialog.show();
}
private void dismissProgressDialog() {
if (pDialog != null && pDialog.isShowing()) {
pDialog.dismiss();
}
}
#Override
protected void onDestroy() {
dismissProgressDialog();
super.onDestroy();
}
class LoadAllProducts extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute() {
showProgressDialog();
}
/**
* getting All products from url
* */
protected String doInBackground(String... args)
{
doMoreStuff("internet");
return null;
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url)
{
if (YourActivity.this.isDestroyed()) {
return;
}
dismissProgressDialog();
something(note);
}
}
}
Late to the party, but really this question has many duplicates on SO.
The most comprehensive summary of solutions I've found is here.
Basically use a retained Fragment to connect your AsyncTask to the new Activity.

Prevent event from being fired when calling expandItem()

the title says almost everything. When I execute the expandItem() function programmatically I do not want the fired event causing a nodeExpand() call.
I have implemented the ExpandListener:
#Override
public void nodeExpand(ExpandEvent event)
{
System.out.println("This should only appear when the user clicks the node on the UI");
}
When I call the expandItem() function of the Tree class, there is always an event fired. This is the code of the original Tree class:
public boolean expandItem(Object itemId) {
boolean success = expandItem(itemId, true);
requestRepaint();
return success;
}
private boolean expandItem(Object itemId, boolean sendChildTree) {
// Succeeds if the node is already expanded
if (isExpanded(itemId)) {
return true;
}
// Nodes that can not have children are not expandable
if (!areChildrenAllowed(itemId)) {
return false;
}
// Expands
expanded.add(itemId);
expandedItemId = itemId;
if (initialPaint) {
requestRepaint();
} else if (sendChildTree) {
requestPartialRepaint();
}
fireExpandEvent(itemId);
return true;
}
What I did now to get this work is:
m_Tree.removeListener((ExpandListener)this);
m_Tree.expandItem(sItemId);
m_Tree.addListener((ExpandListener)this);
Is there any nicer approach?
You could try to create a switch to your listener. For example:
private boolean listenerDisabled;
void setListenerDisabled(boolean disabled)
{
listenerDisabled = disabled;
}
#Override
public void nodeExpand(ExpandEvent event)
{
if(listenerDisabled) return;
System.out.println("This should only appear when the user clicks the node on the UI");
}
and disable the listener when needed.
If there are more than one listener, you could try creating a subclass of Tree and overriding some methods.

Resources