Retry AsyncTask - android

For example I have following AsyncTask:
private class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {
#Override
protected Void doInBackground(Void... params) {
try {
//some code that may throws exception
return true;
} catch (IOException ex) {
return false;
}
}
#Override
protected void onPostExecute(Boolean param){
if (!param) {
AlertDialog.Builder builder = new AlertDialog.Builder(MyActivity.this);
builder.setMessage("Error");
builder.setPositiveButton("Retry", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//I want to retry MyAsyncTask here
}
});
builder.setNegativeButton("Exit", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
AlertDialog alert = builder.create();
alert.show();
}
}
}
What is best practice to do this? I'm afraid of recursion this code.

You cannot strictly "retry" an instance of AsyncTask. You have to create a new instance and execute it, just as you did the first one. You should not encounter a recursion problem.

I retry the code within doInBackground() for x number of times:
#Override
protected Void doInBackground(Void... params)
{
final int MAX_RETRY=3;
int iLoop;
boolean bSuccess=true;
for (iLoop=0; iLoop<MAX_RETRY; iLoop++)
{
try
{
//do some code that throw an exception
//success! exit loop
iLoop=0;
break;
}
catch (IOException ex)
{
bSuccess=false;
}
}
if (iLoop==(MAX_RETRY-1))
{
bSuccess=false;
}
return bSuccess;
}
This is also one of those times when the two values of a boolean are inadequate to measure success. You could replace bSuccess with an enum for a third measure of success: retry later.

I solved the same problem using BetterASyncTask.
It provides the handy HandleError abstract method, which allows me to catch the exception on the UI thread and decide if retry and how.

Please take a look at retryableasynctask and see if it helps.
Usage:
// Params, Progress and Result could be anything, same as a regular AsyncTask
new RetryableAsyncTask<Params, Progress, Result>(myActivity) {
#Override
protected void onPreExecute() {
// write some code here
}
#Override
protected Result doInBackground(Params... params) {
// execute some expensive task here with your params
// eg: MyExpensiveTask with method called 'get'
return MyExpensiveTask.get(params);
}
#Override
protected void onPostExecute(Result result) {
// write some code here with your result
}
}.execute(myParams);
Overriding "onError" behaviour
By the default, onError method shows a dialog "Cancel" and "Retry" button options. However, you might wanna do something else when something goes wrong. To do so, override onError with your own error handling.
// Params, Progress and Result could be anything, same as a regular AsyncTask
new RetryableAsyncTask<Params, Progress, Result>(myActivity) {
// ...
#Override
protected void onError(Throwable error, final Params... params) {
// write your own error handling
}
}.execute(myParams);

Related

How to show AlertDialog in AsyncTask without leaking Context?

I have the below code working fine to find and read a record in a Room database via an id. Android Studio required adding a try/catch block which I've included below.
Two questions:
Can I leave the if{} section blank in onPostExecute() if there is no Exception?
How do I show an AlertDialog here without leaking contect and without using a hack via WeakReference?
// AsyncTask for reading an existing CardView from the database.
private static class ReadAsyncTask extends AsyncTask<Integer, Void, Quickcard> {
private QuickcardDao asyncTaskDao;
Exception e;
ReadAsyncTask(QuickcardDao dao) {
asyncTaskDao = dao;
}
#Override
public Quickcard doInBackground(final Integer... params) {
Quickcard result;
try {
result = asyncTaskDao.readCardForUpdate(params[0]);
} catch (Exception e) {
this.e = e;
result = null;
}
return result;
}
#Override
protected void onPostExecute(Quickcard quickcard) {
if (e == null) {
// *** Okay to leave this blank? If not, what should go here?
}
else {
// *** How do I show an AlertDialog here with leaking context?
}
}
}
You cannot use a view object while using a thread that operates in background.. U must implement the dialog in the UI thread. When you are implementing the the asynchronous class, in that method you should show the alert dialog. Hope this helps..
This is what I will do to prevent leaks from happening.
private static class showDialog extends AsyncTask<String, String, String> {
private WeakReference<MainActivity> mainActivityWeakReference;
showDialog(MainActivity mainActivity){
this.mainActivityWeakReference = new WeakReference<>(mainActivity);
}
#Override
protected String doInBackground(String... params) {
//do your long long time consuming tasks here.
return "Done";
}
#Override
protected void onPostExecute(String result) {
// execution of result of Long time consuming operation
//Just building an alert dialog to show.
if (mainActivityWeakReference.get() != null){
final MainActivity activity = mainActivityWeakReference.get();
new AlertDialog.Builder(activity).setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast.makeText(activity, "Yes was clicked", Toast.LENGTH_SHORT).show();
}
}).show();
}
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(String... text) {
}
}

submitScoreGPGS does not work with AsyncTask

I am trying to get the Google Play Services working as following using AsyncTaks:
1 - The Login Dialog is only displayed when the user click on the leaderboard button which call the method loginGPRS() below;
2 - An ansync task is then executed which call the startLoginGRPS() method on the onPreExecute
3 - [Here is the problem] Once he is logged in, I want to call the methods submitScoreGPRS() and getLeaderBoardGPRS() in onPostExecute method, but the leaderboard dialog is never opened...
Here is the relevant source code:
#Override
public void loginGPGS() {
try {
MyAsyncTask asyncTask_a = new MyAsyncTask();
asyncTask_a.execute();
} catch (final Exception ex) {
}
}
class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {
String errorMsg;
#Override
protected void onPreExecute() {
startLoginGPGS();
super.onPreExecute();
}
#Override
protected Boolean doInBackground(Void... v) {
return true;
}
#Override
protected void onPostExecute(Boolean success) {
if(success){
submitScoreGPGS(bestScore);
getLeaderboardGPGS();
}
}
}
public void startLoginGPGS() {
try {
// runOnUiThread(new Runnable() {
// public void run() {
gameHelper.beginUserInitiatedSignIn();
// }
// });
} catch (final Exception ex) {
}
}
#Override
public void submitScoreGPGS(int score) {
if(getSignedInGPGS()){
Games.Leaderboards.submitScore(gameHelper.getApiClient(),
getString(R.string.leaderboard1_id), score);
}
}
Have you trace your code??
Write something like...
Log.d("Trace","Point X"):
In the doInBackground method just before the return true, another one in the onPostExecute method just before the if and inside the if.
Take a look at your Logcat and come back...
Hope it helps.
You're executing your method on the UI thread, because onPostExecute() runs on the UI thread and your method has network execution..
You should move your method to the doInBackground() method

Executing AsyncTask from onClick of AlertDialog doesn't call opPostExecute

I am getting weird behavior when executing AsyncTask from AlertDialog. I need some suggestion/workaround to fix it. I am stuck at this point.
When I execute AsyncTask from AlertDialog, it is not calling onPostExecute. It call doInBackground, but after finish, it doesn't call onPostExecute. I want AsyncTask to get executed on the basis of AlertDialog's button press value.
Here is the function that creates AlertDialog and executes AsyncTask:
private void processDownloadChoosen(String msg, int __position){
final AlertDialog.Builder alertBox = new AlertDialog.Builder(new ContextThemeWrapper(ShivaniMP3Activity.this, android.R.style.Theme_Dialog));
final int position = __position;
alertBox.setMessage(msg);
alertBox.setCancelable(false)
.setPositiveButton("Download", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog,int id){
dialog.dismiss();
String downloadURL = entries.get(position);
AsyncTaskDownload atd = new AsyncTaskDownload(downloadURL);
if((downloadURL != null) &&(downloadURL != "")){
EnglishMP3Activity.totalDownloads++;
if(downloadWindow == null){
downloadWindow = new PopupWindow(downloadPopupLayout, LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT, true);
downloadWindow.showAtLocation(downloadPopupLayout, Gravity.CENTER, 0, 0);
}
atd.execute();
}
}
}).setNegativeButton("Listen", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog,int id){
dialog.dismiss();
String downloadURL = entries.get(position).replace("%20", " ");
emp = new EasyMediaPlayer(mp3PopupLayout,buttonPlayPause,seekBarProgress,tv_mp3,downloadURL);
emp.startPlayingMP3();
}
}).show();
}
And I am calling this function from listview's on item click:
//lv is listview
lv.setOnItemClickListener(new AdapterView.OnItemClickListener(){
public void onItemClick(AdapterView<?> p, View v, int position, long id) {
processDownloadChoosen("Do you want to Listen or Download this file ?",position);
}
});
My AsyncTask definition look like:
public class AsyncTaskDownload extends AsyncTask<Void, String, Void> {
//
protected void onPreExecute(){
pBar1.setVisibility(View.INVISIBLE);
//
}
protected Void doInBackground(Void... vd){
try{
//do something
}
catch(Exception e){
//do somting
}
return null;
}
protected void onProgressUpdate(String... msg) {
//do smething
}
protected void onPostExecute(Void in){
cancelDownloadButton.setVisibility(View.GONE);
//do smtthing
}
}
PLEASE NOTE: When I execute AsyncTask directly from ListView's on item click function, all works well. But while calling from AlertDialog, it doesn't call onPostExecute.
Any help to resolve/workaround for this is appreciated.. Advance Thanks
Try using a handler/Runnable such that in the alertDialog's onPositiveClick callback you do
Handler mHandler;
prtected void onCreate(Bundle sis) {
//other code
this.mHandler = new Handler();
}
//In your DialogInterface.OnClickListener
mHandler.post(new Runnable() {
#Override
public void run() {
//Init and launch your asynctask here
}
});
The reason this is not working is that an AsyncTask must be invoked on the UI thread and im pretty sure that invoking on the positive button callback is not linked directly with the activities context (given that the task works from the ListView's onItemClick callback)
After going through several posts, it looks like AsyncTask doesn't work properly from AlertDialog.
So I achieved this by "fooling" Android. Noe I am doing everything inside doInBackground function and also getting the feel as if preexecute/postexecute is getting called.
Below is what i did:
1) Removed onPreExecute() and onProgressUpdate() from AsyncTask.
2) define doInBackground something like:
protected Void doInBackground(Void... vd){
publishProgress("I_AM_STARTED");
//Other Work
publishProgress("I_AM_DONE");
}
3) define onProgressUpdate something like:
protected void onProgressUpdate(String... msg) {
if(msg[0].equals("I_AM_STARTED")){
//code for onPreExecute
}
else if(msg[0].equals("I_AM_DONE")){
//code for onPostExecute
}
else{
//normal code
}
}
Hope this may be helpful for someone who got stuck like me. :-)

Android AlertDialog Activity & Async Error

I have a fully functional asynctask in my android app, but when I'm not connected it causes my app to crash in the Error message within my Activity (in AlertDialog.Builder) stemming from the Async not connecting. I pass Context to my async, so that may have something to do with it, but not sure.
Below is the code from Async class and Activity. LogCat is telling me error is occurring in the AlertDialog alert builder.create(). How can I solve?
From Async class:
InputsRecapUploadTask extends AsyncTask<String, Void, Integer> {
public InputsRecapUploadTask(InputsRecap activity,
ProgressDialog progressDialog, Context ctx) {
this.activity = activity;
this.myCtx = ctx;
this.progressDialog = progressDialog;
}
#Override
protected void onPreExecute() {
progressDialog.show();
}
}
#Override
protected Integer doInBackground(String... arg0) {
//// http code
responseCode = 1;
}
}
} catch (Exception e) {
e.printStackTrace();
progressDialog.dismiss();
activity.showLoginError("");
}
return responseCode;
}
#Override
protected void onPostExecute(Integer headerCode) {
progressDialog.dismiss();
if (headerCode == 1)
activity.login(id);
else
activity.showLoginError("");
}
Activity Class:
public void showLoginError(String result) {
AlertDialog.Builder builder = new AlertDialog.Builder(InputsRecap.this);
builder.setPositiveButton("okay",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.setMessage("unable to upload database");
AlertDialog alert = builder.create();
alert.setCancelable(true);
alert.show();
}
If an exception is thrown in your doInBackground method these two lines:
progressDialog.dismiss();
activity.showLoginError("");
Will cause Exception - you can not modify the UI from within the doInBackground method. Instead set a flag and show the error dialog in the onPostExecute which is executed in the main thread.
Check the link below especially the topic under heading The 4 steps.
http://developer.android.com/reference/android/os/AsyncTask.html

How to cancel an Android AsyncTask after a certain amount of time? (Eg. 10 seconds)

I want to use a AsyncTask to check an InetAddress, such as in the code below. The variable tempInet is a global variable that indicates whether the website was contactable or not.
I begin the AsyncTask with the code... new InetAsyncTask().execute("www.facebook.com");
My problem is that I want the AsyncTask to cancel itself after (say) 10 seconds.
Some other questions suggest using the get(10, TimeUnit.SECONDS) method. I would like to do this but not sure where/how to put the get method. With execute? In the doInBackground method?
Also, does the get() method block the main thread? If it does, what is the point of it?
Any help appreciated.
class InetAsyncTask extends AsyncTask<String, String, Boolean> {
#Override
protected Boolean doInBackground(String... params) {
try {
InetAddress.getByName("www.facebook.com");
return true;
} catch (UnknownHostException e) {
return false;
}
} //end doInBackground function
protected void onPostExecute(Boolean... result) {
tempInet = result[0];
}
} //end class
Related Questions
Android - Setting a Timeout for an AsyncTask?
stop async task after 60 second
Android Developers AsyncTask Documentation
http://developer.android.com/reference/android/os/AsyncTask.html
You should make a handler which cancels the Asynctask (http://developer.android.com/reference/android/os/AsyncTask.html#cancel(boolean))
Send a delayed message to this Handler like:
Handler.sendMessageDelayed(msg, delayMillis)
private android.os.Handler mHandler = new android.os.Handler() {
#Override
public void handleMessage(Message msg) {
(Your AsyncTask object).cancel(true);
}
}
To answer your question. The code to use with get() is the following:
Boolean isHost = new AsyncTask<String, Void, Boolean>() {
#Override
protected Boolean doInBackground(String... params) {
try {
InetAddress.getByName(params[0]);
return true;
} catch (UnknownHostException e) {
return false;
}
}
}.execute("www.facebook.com").get(PING_TIME, TimeUnit.MILLISECONDS);
The get method blocks the caller thread as long as the result needs to be returned. You should therefore only use it in test situations. If you want to get an asynchronous answer start it as follows (this is one of my examples, you'll have to change it for your purpose):
private AsyncTask<Void, Void, Boolean> mAsyncTask;
private android.os.Handler timeHandler = new android.os.Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// react here or...
mAsyncTask.cancel(true);
}
};
public void pingServer() {
timeHandler.sendEmptyMessageDelayed(1, PING_TIME);
mAsyncTask = new AsyncTask<Void, Void, Boolean>() {
#Override
protected Boolean doInBackground(Void... params) {
// stop the time handler
timeHandler.removeMessages(1);
return restService.pingServer();
}
#Override
protected void onPostExecute(Boolean isOnline) {
super.onPostExecute(isOnline);
// use result after execution (e.g.: send to callback)
}
#Override
protected void onCancelled(Boolean aBoolean) {
super.onCancelled(aBoolean);
// ...react here
}
}.execute();
}

Categories

Resources