I have a base class of an activity and a sub class which extends the base class. The superclass has a async task to perform some action. I call this by running it on the ui thread since otherwise it throws an IllegalInitializerError:
superclass.this.runOnUiThread(new Runnable() {
public void run() {
String p="";
try {
p=new asynctasker().execute().get();
}
}
}
In my async task:
protected void onPreExecute()
{
// TODO Auto-generated method stub
super.onPreExecute();
//showDialog();
Log.d("Now","Inside right now");
dialog = ProgressDialog.show(class_create_event.this, "Loading1", "Please Wait");
}
However the dialog is displayed almost at the end of the request. The I am in part is printed correctly. I know that something is blocking my ui thread. But if I dont call the async task from the UI thread it throws an illegal initializer error. Is there any way out?
You don't need to have UIthread for calling AsyncTask
Call it like this way
FetchRSSFeeds async = new FetchRSSFeeds();
async.execute();
private class FetchRSSFeeds extends AsyncTask<String, Void, Boolean> {
private ProgressDialog dialog = new ProgressDialog(HomeActivity.this);
/** progress dialog to show user that the backup is processing. */
/** application context. */
protected void onPreExecute() {
this.dialog.setMessage(getResources().getString(
R.string.Loading_String));
this.dialog.show();
}
protected Boolean doInBackground(final String... args) {
try {
// Fetch the RSS Feeds from URL
// do background process
return true;
} catch (Exception e) {
Log.e("tag", "error", e);
return false;
}
}
#Override
protected void onPostExecute(final Boolean success) {
if (dialog.isShowing()) {
dialog.dismiss();
}
if (success) {
// Setting data to list adaptar
setListData();
}
}
}
Related
I have an asynchronous task in Android Studio, to send and receive data from a server as follows.
private class myTask extends AsyncTask<Void, Void, Integer> {
Exception excepccion;
protected void onPreExecute() {
super.onPreExecute();
Mensaje.mensajeConectandoseSicoy(actMetodoPago,getString(R.string.msg_conexion_sicoy));
}
#Override
protected Integer doInBackground(Void... params) {
try {
return new Servidor().guardarObtnerInfoServidorSicoy(ACCION_PAGAR_PEDIDO);
} catch (Exception e2) {
excepccion = e2;
return -1;
}
}
#Override
protected void onPostExecute(Integer respuesta) {
Mensaje.detenerMensajeConectandoseSicoy();
...
}
Where:
public static void mensajeConectandoseSicoy(Context context, String mensaje){
pd = new ProgressDialog(context);
pd.setMessage(mensaje);
pd.setCancelable(false);
Handler pdCanceller = new Handler();
pd.show();
}
public static void detenerMensajeConectandoseSicoy(){
if (pd.isShowing()){
pd.dismiss();
}
}
This process works very well until a user reported problems and discovered that their internet is of very poor quality.
When the task is running onPostExecute, that is, when the server has already responded, it is again executed onPreExecute, and this triggers a series of errors.
I solved it by putting a Boolean type flag variable, to avoid the problem.
My question is:
Is there a way to do that control in a better way?
In my application, there are multiple asynctasks. Please let me know why doInBackground of an asynctask sometimes does not getting called. Its onPreExecute method gets called. Is there any issue because of multiple asynctasks or something else?
/* ASync class for test table */
public class TestAsynch extends AsyncTask<String, Void, String>{
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
String status = null;
String result1=API_Manager.getInstance().sendTestData(userName);
try {
if(result1 != null) {
// save in db
}
}
}
catch( Exception e) {
e.printStackTrace();
}
return status;
}
#Override
protected void onPostExecute(String status) {
}
}
If your project has multiple asynctasks you must check that there is a limit of asynctasks that can be executed. When you create a new AsyncTask it will be added on a Pool and will be execute only when is possible.
Check this answer:
Multitasking on android
And the docs: ThreadPoolExecutor
Here is an example on how properly handle multiple AsyncTasks AsyncTaskManager
OnPreExecute() gets called on the UI thread and doInBackground() is called on the background thread.
There is one dedicated background thread for the async task. This behaviour can be changed if you want to.
http://android-er.blogspot.in/2014/04/run-multi-asynctask-as-same-time.html
Now, say you have multiple instances of async task and I'm assuming you are calling execute() to run the async tasks. This will trigger all the preExecute immediately since UI thread is free but for the doInBackground it will triggered one by one. Hence it may take some time for the next async task to start.
doInBackground should run on a loop using a Boolean to check before execution. Before your Task is being executed, set a global boolean (may be true/false) depends on which you prefer and values add on thread should call runOnUiThread.
startExect = true;
new TestAsynch().execute();
then change this
public class TestAsynch extends AsyncTask<String, Void, String>{
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
String status = null;
String result1=API_Manager.getInstance().sendTestData(userName);
try {
if(result1 != null) {
// save in db
}
}
}
catch( Exception e) {
e.printStackTrace();
}
return status;
}
#Override
protected void onPostExecute(String status) {
}
}
to this
public class TestAsynch extends AsyncTask<String, Void, String> {
String result1 = null;
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
String status = null;
result1=API_Manager.getInstance().sendTestData(userName);
while (startExecute) {
Thread exe = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5);
}
catch( Exception e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
if(result1 != null) {
// save in db
}
}
});
}
}); exe.start();
}
return status;
}
#Override
protected void onPostExecute(String status) {
}
}
Hi onCancel of dialog i want to cancel to server call but i m facing problem that even i cancel the task, it hits my server and modifies the data. How can I resolve this issue ? Below is my code..
private class UserBoardingTask extends AsyncTask {
#Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage(getResources().getString(R.string.please_wait));
progressDialog.setIndeterminate(false);
progressDialog.setCancelable(true);
progressDialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
if (userOnBoardingTask!= null && userOnBoardingTask.getStatus() != AsyncTask.Status.FINISHED && !userOnBoardingTask.isCancelled()) {
userOnBoardingTask.cancel(true);
}
}
});
progressDialog.show();
}
#Override
protected Void doInBackground(String... urls) {
String boardingURL=null;
boardingURL= getUrl();
UserOnBoardingDTO userOnBoardingDetailsDTO = AppStateManager.getUserBoardingDetails();
try{
RestAPIManager.putToNSWebService(boardingURL, userOnBoardingDetailsDTO, username, password);
}
catch (Exception e) {
errorMessage=getResources().getString(R.string.unknown_exp);
}
return null;
}
#Override
protected void onCancelled() {
super.onCancelled();
closeProgressDialog();
errorMessage="";
AppStateManager.setUserBoardingDetails(null);
userOnBoardingTask=null;
}
#Override
protected void onPostExecute(Void res) {
closeProgressDialog();
userOnBoardingTask=null;
if(!FieldsValidator.isBlank(errorMessage)){
CommonUtil.showToast(getActivity(),errorMessage);
errorMessage="";
return;
}
Just check isCancelled() once in a while:
protected Object doInBackground(Object... x) {
while (/* condition */) {
// work...
if (isCancelled()) break;
}
return null;
}
and another solution is
protected void onProgressUpdate(String... progress1) {
if(condition){
break;
}
}
Move the dialog out of the async task and only start the task when the dialog is not canceled.
Actually the problem is not termination of your asynsTask but the server hit if a server hit is already done before termination of asynsTask then you must interrupt your server request also.Just terminate your server request using abort method.
Where is userOnBoardingTask declared and where it is assigned to a reference to running task? I suspect this does not store a proper reference when the task tries to cancel it.
I am not sure if it is the actual reason of your problem. But for sure you may get rid of this variable if it is intended to pint at current task. Just change dialog's on cancel listener:
private class UserBoardingTask extends AsyncTask<String, Void, Void> {
#Override
protected void onPreExecute() {
// ...
progressDialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
if (UserBoardingTask.this.getStatus() != AsyncTask.Status.FINISHED
&& UserBoardingTask.this.isCancelled()) {
UserBoardingTask.this.cancel(true);
}
}
});
In fact you may omit UserBoardingTask.this phrase as the inner class can point directly fields of nesting class as far as the names are not obscured by the names of inner class members:
private class UserBoardingTask extends AsyncTask<String, Void, Void> {
#Override
protected void onPreExecute() {
// ...
progressDialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
if (getStatus() != AsyncTask.Status.FINISHED && isCancelled()) {
cancel(true);
}
}
});
EDIT
Another point is that before sending request to the server you may check inside doInBackground you may check if the task has not been cancelled
// ...
#Override
protected Void doInBackground(String... urls) {
// ...
try {
if(isCancelled()) {
throw new Exception("Exit: task cancelled!");
}
RestAPIManager.putToNSWebService(boardingURL, userOnBoardingDetailsDTO, username, password);
// ...
RestAPIManager.putToNSWebService(boardingURL, userOnBoardingDetailsDTO, username, password);
This above code hit the server. So you have to validate the execution of code inbetween cancellation.
Try something like this
try{
if(!userOnBoardingTask.isCancelled())
{
RestAPIManager.putToNSWebService(boardingURL, userOnBoardingDetailsDTO, username, password);
}
}
catch (Exception e) {
errorMessage=getResources().getString(R.string.unknown_exp);
}
This is ok. If user cancel the task before ResetAPIManager code executes. Suppose user try to cancel the task after server call initiated you have to tell already modified or remodify server data or unable to cancel or some message to user. All done through getting server reponse and validate server response if it changed or not.
Use something like this
Var rsponse = RestAPIManager.putToNSWebService(boardingURL,userOnBoardingDetailsDTO, username, password);
Validate the reponse message in onPostExecute() or OnCancelled() method.
If you cancel the asynctask after access this method
RestAPIManager.putToNSWebService(boardingURL,userOnBoardingDetailsDTO, username, password); the async task will cancel after running the above code so you should correct this by creating a new method inside RestAPIManager class and call that method inside OnCancelled method from your asyncTask.
Short Anser: Its not possible stop data posts thru a simple cancel. once an async task runs even if you cancel it mid way data posts will occure. Cancellation can be done in a Simple Run
Check this Post
[Android - Cancel AsyncTask Forcefully
I need to display progrees dialog. It is quite simple, however I am absolutly required to wait untill asynctask will finish. That exopse some difficulties to me. To wait for completion of asynctask method .get() is used. But this method blocks my progress dialog.
So, how can I unblock progressdialog with get or what can replace .get()?
I am calling operation in a following way:
Operation o = new Operation();
o.execute(params);
try {
o.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
class Operation
class Operation extends AsyncTask<String, Void, JSONObject> {
ProgressDialog pd;
Context con;
#Override
protected void onPreExecute() {
pd = new ProgressDialog(app);
pd.setOwnerActivity(app);
pd.setTitle("Идет загрузка...");
pd.setCancelable(true);
pd.show();
}
#Override
protected JSONObject doInBackground(String... option) {
/*
some job
*/
return json;
}
#Override
protected void onPostExecute(JSONObject result) {
super.onPostExecute(result);
pd.dismiss();
/*
some job
*/
}
}
Don't use .get() as you have seen it blocks the UI. You can use getStatus() if you need to check if the task is finished. Removing .get() should allow your ProgressDialog to show. If you have code that must wait until the AsyncTask is finished then put it in onPostExecute() or call a function from there
If you need to reference something in the MainActivity from the AsyncTask after it has finished, simply create a constructor to take a reference of your Activity and pass context to your constructor
Operation o = new Operation(this);
and reference it in constructor
lass Operation extends AsyncTask<String, Void, JSONObject> {
ProgressDialog pd;
Context con;
Activity act;
public Operator(Activity curAct)
{
act = curAct; // can use this reference to access methods in your Activity
}
try to use this way
private ProgressDialog dialog=null;
#Override
protected void onPreExecute() {
dialog = ProgressDialog.show(this, "", "Please! Wait...",true);
}
#Override
protected void onPostExecute(JSONObject result) {
super.onPostExecute(result);
dialog.dismiss();
// use here code
}
You might want to change your code to something like this.
Wrap the code you want to run afterwards in a runnable and pass it to your async task.
Runnable onEnd = new Runnable(){
//code to run after the task has completed
}
Operation o = new Operation(onEnd);
o.execute(params);
And here is the modified Operation class.
class Operation extends AsyncTask<String, Void, JSONObject> {
ProgressDialog pd;
Context con;
Runnable afterwards = null;
Operation(Runnable afterwards){
this.afterwards = afterwards ;
}
#Override
protected void onPreExecute() {
pd = new ProgressDialog(app);
pd.setOwnerActivity(app);
pd.setTitle("Идет загрузка...");
pd.setCancelable(true);
pd.show();
}
#Override
protected JSONObject doInBackground(String... option) {
/*
some job
*/
return json;
}
#Override
protected void onPostExecute(JSONObject result) {
super.onPostExecute(result);
pd.dismiss();
/*
some job
*/
if (afterwards != null)
afterwards.run();
}
}
Note the afterwards.run() in onPostExecute.
In my app I performing loading data from web and then displaying it to user. Before loading data app shows progress dialog. I have problem if user locks phone in the middle of loading operation, or server is overloaded and can't respond in time my application freezes, because it doesn't dismiss progress dialog, or in some cases it crashes because lack on needed data.
If some error happened while loading data I want show some dialog to user to let him know about error and ask him should application repeat last request. I tried to use AlertDialog for it, but I haven't succeed.
Here is code of one activity (There is no progress dialog here, but it demonstrates how I loading data):
#EActivity(R.layout.layout_splash)
#RoboGuice
public class SplashScreenActivity extends Activity {
#Inject
private AvtopoiskParserImpl parser;
#Bean
BrandsAndRegionsHolder brandsAndRegionsHolder;
#ViewById(R.id.splash_progress)
ProgressBar progressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loadData();
}
#Background
protected void loadData() {
publishProgress(10);
LinkedHashMap<String, Integer> brands = null;
try {
brands = parser.getBrands();
} catch (IOException e) {
Log.e(e.getMessage());
}
publishProgress(50);
LinkedHashMap<String, Integer> regions = null;
try {
regions = parser.getRegions();
} catch (IOException e) {
Log.e(e.getMessage());
}
publishProgress(70);
populateData(brands, regions);
}
#UiThread
protected void populateData(LinkedHashMap<String, Integer> brands, LinkedHashMap<String, Integer> regions) {
Intent intent = new Intent(SplashScreenActivity.this, SearchActivity_.class);
brandsAndRegionsHolder.brandsMap = brands;
brandsAndRegionsHolder.regionsMap = regions;
publishProgress(100);
startActivity(intent);
finish();
}
#UiThread
void publishProgress(int progress) {
progressBar.setProgress(progress);
}
}
parser.getBrands() and parser.getRegions() are loading data from the web.
I want to do something like this:
boolean repeatRequest = true;
while (repeatRequest) {
try {
brands = parser.getBrands();
repeatRequest = false;
} catch (IOException e) {
Log.e(e.getMessage());
repeatRequest = showErrorDialog();
}
}
But I didn't manage to do so because this code executes in background thread, but dialog should be shown in UI thread.
I believe that it should be standard approach of doing so, but didn't manage to find it.
Any ides how can I implement this?
The best way is to use AsyncTask.
private class LoadDataTask extends AsyncTask<Void, Integer, Object> {
private ProgressDialog mProgress;
protected Object doInBackground(Void... params) {
// This method runs in background
Object result = null;
try {
result = parser.parse();
} catch (Exception e) {
result = e.getMessage();
}
return result;
}
protected void onProgressUpdate(Integer... progress) {
// This method runs in UI thread
mProgress.setProgress(progress[0]);
}
protected void onPreExecute() {
// This method runs in UI thread
mProgress = new ProgressDialog(context);
mProgress.show();
}
protected void onPostExecute(Object result) {
// This method runs in UI thread
mProgress.dismiss();
if (result instance of String) {
// Here you can launch AlertDialog with error message and proposal to retry
showErrorDialog((String) result);
} else {
populateData(result);
}
}
}