Android - How to accommodate a thread executing in AsyncTask doInBackground method - android

I am trying to query a web service using loopJ and during this operation I want to show the users a progress dialog. When the operation is complete, I want the progress dialog to dismiss and start a new activity intent.
I know AsyncTask is the way to go. On onPreExecute method I show the progress dialog. On doInBackground I am performing the network operation. And onPostExecute I am dismissing the dialog and starting a new activity intent.
My issue is doInBackground will perform loopJ networkcall asynchronously so onPostExecute will finish first before my network operation. If you look at my logs it will show:
"Starting new activity!"
"Fetched category services!"
rather
"Fetched category services!"
"Starting new activity!"
How do I accommodate an asynchronous task running doInBackground? Is there a way in onPostExecute to wait till my asynch loopJ operation is done?
public class FetchCategoriesServices extends AsyncTask<HITECategory, String, String>
{
private Category userSelectedCategory;
private ProgressDialog busyDialog;
#Override
protected void onPreExecute()
{
busyDialog = ProgressDialog.show(SearchActivity.this, getApplicationContext().getString(R.string.progressDialogTitle),
getApplicationContext().getString(R.string.progressDialogMessage));
}
#Override
protected String doInBackground(HITECategory... params)
{
userSelectedCategory = params[0];
String requestCategoryServiceURL = BASE_URL + "GetServices?CategoryID=" + userSelectedCategory.categoryID + "&ResponseType=JSON";
try
{
Client.get(requestCategoryServiceURL, new AsyncHttpResponseHandler()
{
#Override
public void onSuccess(String jsonResponse)
{
Gson gson = new Gson();
CategoryServicesListResponse Response = gson.fromJson(jsonResponse, CategoryServicesListResponse.class);
categoryServiceresults = Response.categoryServices;
Log.d(getString(R.string.DebugKey), "Fetched category services!");
}
});
}
catch (Exception e)
{
Log.d(getString(R.string.DebugKey), "Error connecting to service and fetching category services list");
}
return null;
}
#Override
protected void onPostExecute(String params)
{
busyDialog.dismiss();
Log.d(getString(R.string.DebugKey), "Starting new activity!");
Intent intent = new Intent(getApplicationContext(), CategoriesSearchActivity.class);
startActivity(intent);
}
}

Just put the code in onPostExecute into onSuccess method:
Client.get(requestCategoryServiceURL, new AsyncHttpResponseHandler()
{
#Override
public void onSuccess(String jsonResponse)
{
Gson gson = new Gson();
CategoryServicesListResponse Response = gson.fromJson(jsonResponse, CategoryServicesListResponse.class);
categoryServiceresults = Response.categoryServices;
Log.d(getString(R.string.DebugKey), "Fetched category services!");
youractivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
busyDialog.dismiss();
Log.d(getString(R.string.DebugKey),
"Starting new activity!");
Intent intent = new Intent(getApplicationContext(),
CategoriesSearchActivity.class);
youractivity.this.startActivity(intent);
}
});
}
});

Related

Android ProgressDialog not dismissing from Thread

i'm developing an android App.
The user registration process calls a service that sends an email so it takes several seconds, like 5 or 6 seconds,that's why I execute that task within a thread. The problem is, the Dialog is never dismissing. It stays rolling and the user can do nothing. Here's my code:
try
{
final ProgressDialog progDailog = new ProgressDialog(ActividadAltaUsuario.this);
new Thread(new Runnable()
{
#Override
public void run()
{
try
{
URL url = new URL("slowWS");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
InputStream in = new BufferedInputStream(conn.getInputStream());
String response = IOUtils.toString(in, "UTF-8");
final JSONObject jsonPrincipal = new JSONObject(response);
Boolean success = jsonPrincipal.get("status").toString() == "true";
if (success)
{
ActividadAltaUsuario.this.runOnUiThread(new Runnable() {
#Override
public void run() {
progDailog.show(ActividadAltaUsuario.this, "Sendind email");
}
});
final String idUsuario = jsonPrincipal.get("idUsuario").toString();
URL url2 = new URL("anotherSlowWS");
HttpURLConnection conn2 = (HttpURLConnection) url2.openConnection();
conn2.setRequestMethod("POST");
InputStream in2 = new BufferedInputStream(conn2.getInputStream());
String response2 = IOUtils.toString(in2, "UTF-8");
JSONObject jsonRtaMail = new JSONObject(response2);
//finish();
}
else
{
//finish();
showToast(jsonPrincipal.get("message").toString());
}
ActividadAltaUsuario.this.runOnUiThread(new Runnable() {
#Override
public void run() {
progDailog.dismiss();
}
});
}
catch (Exception e)
{
e.printStackTrace();
}
}
}).start();
}
catch(Exception e)
{
Log.e("log_tag", "Error in http connection" + e.toString());
}
Can anybody help me?
Thanks!
AsyncTask would be a better approach instead of thread, Replace your network call from thread to use AsyncTask. You can use something like this
private class LongOperation extends AsyncTask<Void, Void, Void> {
#Override
protected String doInBackground(Void... params) {
//Main stuff that needs to be done in background
}
#Override
protected void onPostExecute(Void result) {
//Post Execution this method will be called, handle result accordingly
//You can dismiss your dialog here
}
#Override
protected void onPreExecute() {
//Do initialization relative stuff here
// Initialize your dialog here.
}
}
As both onPostExecute() and onPreExecute() work on main thread you can show and dismiss your dialog in this methods.
The UI controls have to be accessed only from the UI thread.
Usually I do this in class that extends AsyncTask
Something like:
public class MyTask extends AsyncTask {
protected void onPreExecute() {
//create and display your alert here
progDialog = ProgressDialog.show(MyActivity.this,"Please wait...", "Logging ...", true);
}
protected Void doInBackground(Void... unused) {
// here is the thread's work ( what is on your method run()
...
// if we want to show some progress in UI, then call
publishProgress(item)
}
protected void onProgressUpdate(Item... item) {
// theoretically you can show the progress here
}
protected void onPostExecute(Void unused) {
//dismiss dialog here where the thread has finished his work
progDialog.dismiss();
}
}
LE:
More detalis about AsyncTask https://developer.android.com/reference/android/os/AsyncTask
check especially the Protected Methods

How can use update UI Thread

I have same stock item , I want to send local database to ApiService, But when I send also I want to update ProgressBar message. I tried the code below but it just shows when all proccessing is finishing.
ProgressDialog progress= new ProgressDialog(this);
progress.setTitle(getResources().getString(R.string.progress_exporting));
progress.setMessage("0/0");
when click button I call below method
public void Export() {
runOnUiThread(new Runnable() {
#Override
public void run() {
findViewById(R.id.btnExportOnlineWithStocktaking).setEnabled(false);
progress.show();
}
});
UpdateUI(send, total);
try {
switch (_stocktakingType) {
case Division: {
switch (_onlineExportType) {
case Item: {
isExport = ExportDivisionStocktakingItems(stocktakingId);
}
break;
}
} catch (Exception ex) {
}
}
// ExportDivisionStocktaking method
public boolean ExportCustomStocktakingItems(int stocktakingId) {
result = Boolean.parseBoolean(SendCustomStocktakingItems(stocktakingId,countResults).responseString);
}
My call back method
public ResponseModel SendCustomStocktakingItems(int selectedDivision, List<ExtensionServiceStocktakingItem> countResults) throws ExecutionException, InterruptedException {
return new SendCustomStocktakingItemsService(flag -> true).execute(String.valueOf(selectedDivision), countResults.toString()).get();
}
//AsyncTask method
public class SendDivisionStocktakingItemsService extends AsyncTask<String, Void, ResponseModel> {
public AsyncResponseSendDivisionStocktakingItems delegate = null;
public SendDivisionStocktakingItemsService(AsyncResponseSendDivisionStocktakingItems delegate) {
this.delegate = delegate;
}
#Override
protected ResponseModel doInBackground(String... parameters) {
RequestHandler requestHandler = new RequestHandler();
JSONObject params = new JSONObject();
try {
params.put("stocktakingItems", parameters[1]);
} catch (JSONException e) {
e.printStackTrace();
}
ResponseModel responseModel = requestHandler.getRequestPostString(UHFApplication.getInstance().apiUrl
+ "/api/MobileService/SendDivisionStocktakingItemsPost?stocktakingID="
+ parameters[0],
parameters[1]);
return responseModel;
}
#Override
protected void onPreExecute() {
UpdateUI(send,total);
super.onPreExecute();
}
#Override
protected void onPostExecute(ResponseModel responseModel) {
super.onPostExecute(responseModel);
if (HttpURLConnection.HTTP_OK == responseModel.httpStatus) {
delegate.processFinish(true);
} else {
delegate.processFinish(false);
}
}
}
//UICalled method
public void UpdateUI(int send, int total) {
runOnUiThread(() -> {
progress.setMessage(send + "/" + total);
Log.d("Send Data : ", send + "/" + total);
if (send == total) {
progress.dismiss();
Toast.makeText(getApplicationContext(), "Succsess", Toast.LENGTH_SHORT).show();
}
});
}
//Update
//Ok I have a simle example how can I use. Below code when I click button I wan to open progress firstly and after that for loop is working and update progres message. I try it but not working.
Firstly For loop is working and after that progres opened.
public void ExportTry(){
UpdateUI(send,total);
runOnUiThread(new Runnable() {
#Override
public void run() {
btnExport.setEnabled(false);
progress.show();
}
});
for(int i=0;i<1000000;i++){
UpdateUI(i,1000000);
}
}
You are missing the part of AsyncTask that will allow you to show progress messages while doInBackground is running. Take a look at onProgressUpdate and publishProgress on the same page.
publishProgress
void publishProgress (Progress... values)
This method can be invoked from doInBackground(Params...) to publish updates on the UI thread while the background computation is still running. Each call to this method will trigger the execution of onProgressUpdate(Progress...) on the UI thread. onProgressUpdate(Progress...) will not be called if the task has been canceled.

Freezing app when using AsyncTask

I download a high amount of data from API and want to make it efficient so I get first 100 record in one asyncTask and then in another asyncTask get another several thousands(in 500 hundred portions) The loadListAsynchronously(); looks identicall as loadData function without content,progress,loadContent(); function but this functions are not the problem - without loadListAsynchronously(); app runs smoothly after frezee when download first data. I tried add transaction but that does not help me.
private void loadData() {
DottedProgressBar progressBar = (DottedProgressBar) findViewById(R.id.loadIngDots);
progressBar.startProgress();
content = (LinearLayout)findViewById(R.id.activity_main) ;
progress = (RelativeLayout) findViewById(R.id.progressPage) ;
AsyncTask<String, Void, String> read =new AsyncTask<String, Void, String>() {
SharedPreferences keyValues;
#Override
protected void onPreExecute() {
content.setVisibility(View.GONE);
keyValues = getSharedPreferences(Settings.MODEL_LAST_CALL, Context.MODE_PRIVATE);
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
height = displaymetrics.heightPixels;
width = displaymetrics.widthPixels;
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
modelList = new ArrayList<>();
Map<String,String> options= new HashMap<>();
options.put("limit",String.valueOf(AMOUNT_OF_LOADED_modelS));
ApiHelper.getModelWithParams(new Callback<ModelApiEnvelope>() {
#Override
public void onResponse(Call<ModelApiEnvelope> call, Response<ModelApiEnvelope> response) {
Log.i(TAG,"First call model Get response");
final ModelApiEnvelope envelope = response.body();
if(envelope==null)
Toast.makeText(MainActivity.this,getString(R.string.server_down_explanation),Toast.LENGTH_SHORT).show();
else{
try {
final Dao<Model,Integer> modelDAO = getHelper().getmodelDAO();
final Dao<Submodel,Integer> submodelDAO=getHelper().getsubmodelDAO();
TransactionManager.callInTransaction(getHelper().getConnectionSource(),
new Callable<Void>() {
public Void call() throws Exception {
modelList=envelope.getData();
Log.i(TAG,"LoadData loop Start");
for( final model m: modelList){
m.setLogo(m.getLogo()+"?width="+width/2+"&height="+height);
m.setLanguage(m.getLanguage().substring(0,2));
if(m.getLanguage().equals("uk"))
m.setLanguage("ua");
if(m.getsubmodels().size()!=0){
for(final submodel e: m.getsubmodels()){
e.setLanguage(m.getLanguage());
submodelDAO.createOrUpdate(e);
}
}
try {
modelDAO.createOrUpdate(m);
}catch (SQLException e) {e.printStackTrace();}
}
return null;}
});
if(envelope.getData().isEmpty()){
SharedPreferences.Editor editor = sharedPreferences.edit();
long time = System.currentTimeMillis();
editor.putString(Settings.model_LAST_CALL , Long.toString(time));
editor.apply();
}
else
loadListAsynchronously();
} catch (SQLException e) {
Log.i(TAG," message "+e.getMessage()) ; e.printStackTrace();
}}
loadContent();
content.setVisibility(View.VISIBLE);
progress.setVisibility(View.GONE);
}
#Override
public void onFailure(Call<modelApiEnvelope> call, Throwable t) {
Log.i(TAG,"ERROR"+ t.getMessage());
Toast.makeText(MainActivity.this,getString(R.string.server_down_explanation),Toast.LENGTH_LONG).show();
loadContent();
}
},MainActivity.this,options, keyValues.getString(lang,"0"));
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
}
};
read.execute();
}
UPDATE: Method Trace added
UPDATE 2: Removing the transaction solve my problem. It seems that the making transaction for thousands saveings into database freeze Ui.
Callback in Retrofit1 and AsyncTask are not compatible. You have to modify your API interface from something like this :
public interface Api {
void getModelWithParams(Callback<Something> callback);
}
To this :
public interface Api {
Something getModelWithParams();
}
Then Retrofit will not provide async execution support and you can execute that row method inside AsyncTask.doInBackground method.
Other option is to stay with that interface definition and just call Retrofit method directly (without AsyncTask wrapping). The question is if your further logic is not heavy, because onResponse will be executed on UI Thread which cause your freezes and in general is root cause of your problem.

Error in starting activity from doInBackground()

I am new to android development.
I want to perform some db operations and then, want to start a new activity. I have written AsyncTask code below.
I am getting error on startActivity call. Please help me out.
private class AsyncTaskRunner extends AsyncTask<String, String, String> {
Context mainContext;
public AsyncTaskRunner(Context mainContext){
this.mainContext=mainContext;
}
#Override
protected String doInBackground(String... params) {
publishProgress("Sleeping..."); // Calls onProgressUpdate()
try {
sql.updateRelations();
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
#Override
protected void onPostExecute(String result) {
InitActivity.progress.dismiss();
Intent intent = new Intent(mainContext, MainActivity.class);
if(mainContext!=null){
mainContext.startActivity(intent);
((Activity)mainContext).finish();
}
}
#Override
protected void onPreExecute() {
InitActivity.progress.show();
}
#Override
protected void onProgressUpdate(String... text) {
}
}
If your async task is an inner class of your activity then do the below
Intent intent = new Intent(YourActivityName.this, MainActivity.class);
if(mainContext!=null){
mainContext.startActivity(intent);
((Activity)mainContext).finish();
}
Else if your async task is a separate class then try the below
Intent intent = new Intent((YourActivityName)mainContext, MainActivity.class);
if(mainContext!=null){
mainContext.startActivity(intent);
((Activity)mainContext).finish();
}
If it doesn't work please post your logs so i can be of better help.

onPostExecute Outer ASyncTask in nested ASyncTasks called before all work finished

I have a few async tasks that get data from JSON services.
In the onPreExecute of the outside task I want to show a progressDialog.
I want to dismiss it in onPostExecute and start another activity.
The problem is that there is still data loading when my onPostExecute is called, so the next activity is executed without the needed data.
Is this normal behavior?
Is there a workaround?
class GetDataAsync extends AsyncTask<Integer, Integer, Integer> {
#Override
protected void onPreExecute() {
Log.d("startupflow","GetDataAsync onPreExecute");
progress = new ProgressDialog(Login.this);
progress.setMessage("Loading...");
progress.show();
super.onPreExecute();
}
#Override
protected Integer doInBackground(Integer... params) {
Log.d("startupflow","GetDataAsync doInBackground");
GetData getData = new GetData();
getData.LoadAllData(getApplicationContext(), token, client);
return null;
}
#Override
protected void onPostExecute(Integer integer) {
Log.d("startupflow","GetDataAsync onPostExecute");
if (progress.isShowing()) {
progress.dismiss();
}
Intent intent = new Intent(Login.this, Admin.class);
startActivity(intent);
super.onPostExecute(integer);
}
In the GetData class:
public void LoadAllData(Context context, Token token, OAuth2Client client) {
this.context = context;
this.token = token;
this.client = client;
new AllDataAsync().execute();
}
class AllDataAsync extends AsyncTask<Integer, Integer, Integer> {
#Override
protected Integer doInBackground(Integer... params) {
try {
Log.d("GetData", "In AllDataAsyc, do in background");
GetClientandToken(token, client);
Log.d("GetData", "getcompanyanddatatapstask");
new GetCompanyAndDataTapsTask().execute();
Log.d("GetData", "getslidestask");
new GetSlidesTask().execute();
} catch (Exception e) {
e.printStackTrace();
errorOccurred = true;
}
return null;
}
}
The Log:
08-12 11:27:37.515 D/startupflow﹕ GetDataAsync onPreExecute
08-12 11:27:37.562 D/startupflow﹕ GetDataAsync doInBackground
08-12 11:27:37.601 D/startupflow﹕ GetDataAsync onPostExecute
08-12 11:27:40.132 D/startupflow﹕ all data saved
The reason your first async is starting the activity early is because it is only starting the second data-loading async. AsyncTasks work on different threads (hence asynchronous), meaning they don't wait for each other.
What you can do is call a function in the postExecute of the data-loading async to notify your activity that it's done. E.g. add an onFinishedLoadingData function, and call that in your postExecute. You can start your new activity there.

Categories

Resources