I have to make an expensive call to a remote server when a Fragment is loaded. I am using the default Dashboard activity with NavigationView to change the fragments. However whenever a fragment is loaded, it freezes the UI for a few seconds while executing the AsyncTask containing the SOAP Request code.
I have already tried to execute the AsyncTask from onAttach() and onStart() but it still freezes the UI.
How can I fix the UI freezing?
Edit :- The async task code:-
private class BindTreasuryTask extends AsyncTask<Void,Void,ArrayList<TreasuryData>> {
private boolean NO_INTERNET;
#Override
protected ArrayList<TreasuryData> doInBackground(Void... voids) {
try {
// SOAP Call returns a JSONArray
JSONArray jsonArray = apiHandler.performBindTreasury(payeeid);
ArrayList<TreasuryData> td = new ArrayList<>();
td.add(new TreasuryData("Select a treasury","none","none"));
for(int i =0; i<jsonArray.size(); i++){
JSONObject j = (JSONObject) jsonArray.get(i);
td.add(new TreasuryData(j.get("TREASURY_NAME"),j.get("TREAS_CODE"),j.get("SCHEMA_NM")));
}
return td;
} catch (IOException e) {
NO_INTERNET = true;
e.printStackTrace();
} catch (XmlPullParserException | ParseException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(ArrayList<TreasuryData> treasuryData ) {
if (treasuryData == null){
if (NO_INTERNET){
Toast.makeText(getActivity(),"No Internet Connection",Toast.LENGTH_LONG).show();
}
} else {
ArrayList<String> treasury = new ArrayList<>();
for(int i=0;i<treasuryData.size();i++){
treasury.add(treasuryData.get(i).getTreasuryName());
}
setUpView();
}
}
}
As Ashok answered you can call AsyncTask in onActivityCreated() method. You may use thread or handler to start the SOAP request with 1-2 secs delay that may avoid freezing of fragment upon calling Api. Or if UI is freezing whenever you're switching fragments from navigation drawer then you may have to manage your own fragment queue.
onActivityCreated() can be your choice and expensive work should be done in doInBackGround() method.
Related
I have this piece of an activity:
public class ResultActivity extends AppCompatActivity implements ResultListener {
private String code = "";
private String data = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
try {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
code = intent.getStringExtra("code");
data = intent.getStringExtra("data");
MyExternal.DecodeAndSend(this, code, data);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
Where MyExternal is a class in other library.
The method DecodeAndSend is something like this:
public static boolean DecodeAndSend(ResultListener caller, String codigo, String data)
{
try {
ExecutorService pool = Executors.newFixedThreadPool(1);
HashMap<String,String> arguments = new HashMap<>();
Future<String> resultado = pool.submit(new ServerConnection(caller, url, arguments));
String status = resultado.get();
if (status.equals("OK"))
caller.OnSuccess();
else
caller.OnError(status);
pool.shutdown();
return true;
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return false;
}
Finally, ServerConnection class implements Callable<String> so I show you the call method:
#Override
public String call() throws Exception {
Thread.sleep(2000);
return "OK";
}
The call to Thread.sleep(2000); is actually a call to a web server to send some data.
The problem is that the ResultActivity does not show its layout until the call call returns.
What is missing in this code?
DecodeAndSend is called from the main thread. It calls Future.get() which waits for the job to finish, so it's blocking the main thread. You should call this method from a background thread as well. I think it would be okay to send it to your same thread pool since it is submitted after the first job that it will wait for.
You cannot return anything about the request results from this method, because it is asynchronous.
public static void DecodeAndSend(ResultListener caller, String codigo, String data)
{
ExecutorService pool = Executors.newFixedThreadPool(1);
HashMap<String,String> arguments = new HashMap<>();
Future<String> resultado = pool.submit(new ServerConnection(caller, url, arguments));
pool.submit(new Runnable() {
public void run () {
try {
String status = resultado.get();
if (status.equals("OK"))
caller.OnSuccess();
else
caller.OnError(status);
pool.shutdown();
return;
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
caller.OnError(null); // No status, only an exception
});
}
However, your ServerConnection class already takes a caller parameter, so it should probably just handle the callback itself. And depending on what you're doing in the callback, you might want to post the callback calls to the main thread.
By the way, convention in Java is to always start method names with a lower-case letter (camel case).
Feature.get() is a blocking call. The UI Thread is blocked waiting for that call to return, hence can't take care of drawing your layout. Try passing the result listener to ResultListener to the ServerConnection and use the two callbacks to update your UI accordingly
Future.get() is a blocking call - execution stops until the result arrives
The result can only be retrieved using method get when the computation has completed, blocking if necessary until it is ready.
So your Activity's onCreate method calls that stuff, and then blocks until call (which is running on another thread) returns its result. So onCreate doesn't finish, and the layout doesn't complete.
If you want to use that blocking code, but after the view has laid out, I'd use another part of the Activity lifecycle like onStart (set a flag so you only run it once!). Otherwise you'll need to use some other concurrency technique to get your result and use it. It depends on what you're actually doing with the result of your call function
I would like to explain the situation to introduce you into my problem. I have an AsyncTask on Android which tries to connect to a database through jdbc driver. On my doInBackground, I have the following instruction:
conn = DriverManager.getConnection(url, connInfo.getUserName(), connInfo.getPassword());
The problem comes when I try to cancel the AsyncTask and that the task is trying to execute the previous instruction.
I want the user to have the option of cancelling the AsyncTask and immediately execute it again to connect to another database. When I cancel the first AsyncTask and I start another one, until the first task achieves to get the connection and finish his doInBackground method, the second task can't get its own connection.
After this complicated explanation, I think that it is not possible for the DriverManager to execute getConnection while another instance is executing the same method.
What I want to achieve is: once the user cancels the first AsyncTask, abort the execution of DriverManager.getConnection(), in order to allow a second task to execute this instruction as soon as possible, without making the user to wait until doInBackground finishes on first task.
I copy part of my code:
class DBConnectionTask extends AsyncTask <ConnectionInfo,Void,Void>{//connection using JDBC driver
private ConnectionInfo connInfo;
private Connection conn;
private Statement st;
private Activity activity;
GlobalData g;
String url;
ProgressDialog loadingCircle;
public DBConnectionTask(Activity activity) {
this.activity = activity;
}
#Override
protected void onPreExecute(){
loadingCircle=ProgressDialog.show(activity,"","Trying to connect, please wait...",false);
loadingCircle.setCancelable(true);
loadingCircle.setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
// actually could set running = false; right here, but I'll
// stick to contract.
cancel(true); //cancela asynctask y no hace el onPostExecute
}
});
}
protected Void doInBackground(ConnectionInfo... params) {
connInfo = params[0];
connect();
return null;
}
And the connect() method
protected void connect(){
try
{
//part of the code here is ommited
conn = DriverManager.getConnection(url, connInfo.getUserName(), connInfo.getPassword());
System.out.println("Acaba doInBackGround " + connInfo.getAlias());
//st = conn.createStatement();
Intent intent = new Intent(activity, SqlMenu.class);
activity.startActivity(intent);
}
catch (SQLException e)
{
System.err.println(e);
cancel(true);
}
catch (Exception e)
{
System.err.println(e);
cancel(true);
}
finally {
loadingCircle.dismiss();//loadingCircle.dismiss();
}
}
I want to make the task cancelled interrupt its attempt to connect to database just at the moment the user cancels the task.
you can not interrupt this DriverManager.getConnection(url, connInfo.getUserName(), connInfo.getPassword()); statement as it is predefined method and you don't have any control over it. But you can do interrupt at some points where predefined methods are getting finished.
See comments following in your edited code:
protected void connect(){
try
{
//part of the code here is ommited
if(isCancelled())
{
return; // return control if ayncTask is cancelled.
}
conn = DriverManager.getConnection(url, connInfo.getUserName(), connInfo.getPassword());
System.out.println("Acaba doInBackGround " + connInfo.getAlias());
if(isCancelled())
{
return; // return control if ayncTask is cancelled.
}
// query data from database .
// if you are going to use a loop to extract data form cursor, same condition can be used in that loop also.
// so whenever ayncTask is cancelled it can be interrupted.
if(isCancelled())
{
return; // return control if ayncTask is cancelled.
}
Intent intent = new Intent(activity, SqlMenu.class);
activity.startActivity(intent);
}
catch (SQLException e)
{
System.err.println(e);
cancel(true);
}
catch (Exception e)
{
System.err.println(e);
cancel(true);
}
finally {
loadingCircle.dismiss();//loadingCircle.dismiss();
}
}
I'm working on a web application that will parse the site and load the news dynamically into the CardView. For now it works and does all the needed stuff. But it's not exactly what I want.
Here's a piece of my code to understand what I am talking about:
public class NewsPage extends ActionBarActivity {
List<NewCard> listNC = new ArrayList<NewCard>();
class NewsParser extends AsyncTask<Void,Void,List<NewCard>> {
Document doc;
List<NewCard> nc = new ArrayList<NewCard>();
ProgressDialog progressDialog;
#Override
protected void onPreExecute()
{
// progressDialog= ProgressDialog.show(NewsPage.this, "Parsing the site", "Please wait while the information is loading...", true);
};
#Override
protected List<NewCard> doInBackground(Void... params) {
try {
//some code skipped
nc.add(new NewCard(forHeader.html(), forDesc, URLforImg, forHeader.attr("href")));
}
} catch (IOException e) {
e.printStackTrace();
}
return nc;
}
protected void onPostExecute(String[] s) {
progressDialog.dismiss();//This method is being called out by new <class name>.execute();
//listNC = new ArrayList<NewCard>(nc);
}
}
In here I am retrieving article headlines for further opening.
This is my onCreate() method:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_news_page);
RecyclerView recList = (RecyclerView) findViewById(R.id.cardList);
recList.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(this);
llm.setOrientation(LinearLayoutManager.VERTICAL);
recList.setLayoutManager(llm);
try {
NewsParser np = new NewsParser();
np.execute();
listNC = np.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
NewsAdapter na = new NewsAdapter(listNC);
size = na.sizes;
recList.setAdapter(na);
I'm using my adapter to fill the cards with information and to handle onClick events.
My question is this:
I need to retrieve information from my AsyncTask in order to create a
list of cards (in this case I need an amount of cards) and I am not
sure I can go on without returning values. But it makes my app freeze
and not show any interface until the action is completed. How is it
better to handle? Maybe I need to make it all different? How do I
load news headlines separately (not all together but in order)? And
what kind of loop (I don't know how to call it correctly) do I need
to add news as they load (because my program doesn't work if it
doesn't have the list before doing UI stuff)?
I've tried to tell every detail from my code and if it's needed I might add my Adapter code too.
Your UI is freezing because your get() method in the try block is blocking waiting on the AsyncTask to complete. This defeats the purpose of even using the AsyncTask. Instead, create your Adapter before you kick off the AsyncTask and then in the onPostExecute() set the data for the adapter to be the new result and call the adapter's notifyDataSetChanged() method. This will cause the UI to pick up the changes.
Be careful with your use of AsyncTask or any other threading mechanism. They are not lifecycle aware, so if the onPostExecute() method has any strong references to the Activity or its inner member fields and tries to directly use them it could run into state exceptions.
I'm getting some data off Parse.com in my app
When it first starts up, it checks the cache if available and displays it, then the user can pull-to-refresh to get the latest data
When the first refresh action is called, everything works great, but when I try to refresh a second time I get the NetworkOnMainThreadException force close
This is the calling method (I'm using Android support's swipe-to-refresh view)
#Override
public void onRefresh() {
// this part is merely a check, crashes both with or without this
if(!runningTask.getClass().equals(AsyncTask.Status.FINISHED))
runningTask.cancel(true);
runningTask = new DownloadEvents(true).execute();
}
This is the async task
private class DownloadEvents extends AsyncTask<Void, Void, ArrayList<Event>> {
boolean forceDownload;
String errorString = "";
public DownloadEvents(boolean forceDownload) {
this.forceDownload = forceDownload;
Parse.initialize(getActivity(), #API KEY CENSORED#);
}
// Do the long-running work in here
protected ArrayList<Event> doInBackground(Void... params) {
List<ParseObject> events = null;
PreferencesHelper ph = new PreferencesHelper(getActivity());
ParseQuery<ParseObject> eventsQuery = new ParseQuery<ParseObject>("events");
try {
eventsQuery.setCachePolicy(ParseQuery.CachePolicy.CACHE_ONLY);
events = eventsQuery.find();
} catch (ParseException e1) {
e1.printStackTrace();
}
if(forceDownload || System.currentTimeMillis() - ph.getLastEventsDownloadTime() > 43200000 || events == null)
{
swipeLayout.setRefreshing(true);
try {
eventsQuery.setCachePolicy(ParseQuery.CachePolicy.NETWORK_ELSE_CACHE);
events = eventsQuery.find();
ph.setLastEventsDownloadTime();
} catch (ParseException e) {
e.printStackTrace();
}
}
// creating classes and sorting goes here
return eventsList;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(ArrayList<Event> events) {
if(events.size() > 0)
{
EventsAdapter adapter = new EventsAdapter(getActivity(), R.layout.events_card, events);
adapter.notifyDataSetChanged();
getListView().setAdapter(adapter);
}
if(errorString != "")
Toast.makeText(getActivity(), errorString, Toast.LENGTH_SHORT).show();
swipeLayout.setRefreshing(false);
}
}
Even if I force the download as the app start, it's always the second pulldown that crashes it, not the second time it downloads something
Please don't suggest turning off the NetworkOnMainThread strict rule, that's not a solution
Edit: here's the logcat
FATAL EXCEPTION: main
Process: com.mdk.test, PID: 24048
android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1145)
at com.android.org.conscrypt.OpenSSLSocketImpl.shutdownAndFreeSslNative(OpenSSLSocketImpl.java:1102)
at com.android.org.conscrypt.OpenSSLSocketImpl.close(OpenSSLSocketImpl.java:1097)
at org.apache.http.impl.SocketHttpClientConnection.close(SocketHttpClientConnection.java:205)
at org.apache.http.impl.conn.DefaultClientConnection.close(DefaultClientConnection.java:161)
at org.apache.http.impl.conn.tsccm.AbstractConnPool.closeConnection(AbstractConnPool.java:320)
at org.apache.http.impl.conn.tsccm.ConnPoolByRoute.shutdown(ConnPoolByRoute.java:678)
at org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager.shutdown(ThreadSafeClientConnManager.java:256)
at com.parse.ParseRequest.initialize(ParseRequest.java:118)
at com.parse.Parse.initialize(Parse.java:109)
at com.mdk.test.EventsFragment$DownloadEvents.<init>(EventsFragment.java:136)
at com.mdk.test.EventsFragment.onRefresh(EventsFragment.java:223)
at android.support.v4.widget.SwipeRefreshLayout.startRefresh(SwipeRefreshLayout.java:441)
at android.support.v4.widget.SwipeRefreshLayout.onTouchEvent(SwipeRefreshLayout.java:399)
at android.view.View.dispatchTouchEvent(View.java:8073)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2253)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1987)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2259)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2001)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2259)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2001)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2259)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2001)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2259)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2001)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2259)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2001)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2198)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1649)
at android.app.Activity.dispatchTouchEvent(Activity.java:2717)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2159)
at android.view.View.dispatchPointerEvent(View.java:8263)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4013)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3892)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3454)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3507)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3473)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3583)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3481)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3640)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3454)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3507)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3473)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3481)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3454)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5682)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5656)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5627)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5761)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
at android.view.InputEv
Parse.initialize() is in the async task constructor that gets executed in the main thread and it invokes a network operation.
Move the call to doInBackground().
It's hard to tell exactly where the problem occurs, because you didn't post the stacktrace, but this line looks suspicious:
swipeLayout.setRefreshing(true);
You can't modify any views on your doInBackground, and it looks like this might be doing just that.
Another fishy line is:
PreferencesHelper ph = new PreferencesHelper(getActivity());
Apparantly this object needs the activity, which may or may not cause a NetworkOnMainThread exception later on. You can't touch the UI in your doInBackGround method.
Just keep the doInBackground clean and only do the network stuff there, don't entangle it with other things.
event.size()
For null data will throw an exception error, however not sure if that is the exact issue you are facing.
I have some problem with Android AsyncTask. There is an Activity which contains some TextView a button and a picture. When an user entered this activity I start an asynctask to check whether the user can go toward from the activity (until the task not finish the button not active). Then I want to start another asyntask to get the picture.
So I made an inner class:
AsyncTask<String, Void, JSONObject>() authTask = new AsyncTask<String, Void, JSONObject>() {
#Override
protected JSONObject doInBackground(String... params) {
//call the rest api
}
#Override
protected void onPostExecute(JSONObject result) {
// check the result
// and make another asynctask
AsyncTask<String, Void, Bitmap> imageTask = new Async.... {
// get image
}
imageTask.execute();
}
}
and I call
authTask.execute(); from the UI thread.
I have a bad feeling about this, especially it seems doesn't work (it's ok few times but suddenly it "freeze": no exception just hanging and the progress bar is spinning. Nothing happens and the button won't be active.)
There is another way to get an information and when it's finished immediately start another task?
UDPATE:
I working with api level 10. In authTask I get some information which is needed to start imageTask (some id) so I have to call these tasks in a row. In api level 10 it's is possible?
Thanks in advance!
Br, Peter
you can use getStatus() checks whether the the AsyncTask is pending, running, or finished.and when finsh start your new task.like:
if(authTask .getStatus() == AsyncTask.Status.PENDING){
// My AsyncTask has not started yet
}
if(authTask .getStatus() == AsyncTask.Status.RUNNING){
// My AsyncTask is currently doing work in doInBackground()
}
if(authTask .getStatus() == AsyncTask.Status.FINISHED){
// START NEW TASK HERE
}
example for your app:
btn.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
if (authTask != null && authTask.getStatus() == AsyncTask.Status.FINISHED) {
//START YOUR NEW TASK HERE
}
else
{
//IGNORE BUTTON CLICK
}
}
});
1:
You could write the code for authTask and then for imageTask, one after the other, within a single doInBackground(). This single AsyncTask instance would be fire by a single execute() statement. This may or may not be practical depending on needed UI interactions.
2:
Edit: as noted by kabuku this information is mostly for HoneyComb+. Pre HoneyComb I would definitely go with option 1 above. executeOnExecutor() is api level 11+
In receent versions, execute() will send your AsyncTasks in series by default (ICS+). If you want to make sure this happens, specify the serial executor.
In your case this would be:
authTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
// Image task will only be done AFTER textViewTask is done
imageTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
And for newer versions a simple
...
// ICS+ and pre honeycomb (I think)
authTask.execute();
// Image task will only be done AFTER textViewTask is done
imageTask.execute();
...
From the AsycnTask.execute() documentation:
Note: this function schedules the task on a queue for a single
background thread or pool of threads depending on the platform
version. When first introduced, AsyncTasks were executed serially on a
single background thread. Starting with DONUT, this was changed to a
pool of threads allowing multiple tasks to operate in parallel. After
HONEYCOMB, it is planned to change this back to a single thread to
avoid common application errors caused by parallel execution.
PS:
To run tasks independent of each other you must use the AsyncTask.THREAD_POOL_EXECUTOR. That requires a different executor:
// Go parallel! (NOT what you want)
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
Its not a good design to nest AsyncTask. Do all the heavy lifting in doInBackground and simply post/update the results. In other words, combine the processing of second AsyncTask in your first one.
From the code that you showed it does not seem to make sense to spawn second task. Just get you image inside doInBackground of the first task right after authorization.
If you need to update UI in between, you can do it in progress update.
int count;
private void attemptConnect()
{
count = 0;
str_lang = "English";
str_wait = "Plaese Wait";
new AllQuestion().execute();
}
private class AllQuestion extends AsyncTask<String, String, String> {
ProgressDialog pg;
#Override
protected void onPreExecute() {
super.onPreExecute();
pg = new ProgressDialog(LanguageActivity.this);
pg.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pg.setMessage(str_wait);
pg.setCancelable(false);
pg.show();
}
#Override
protected String doInBackground(String... strings) {
try {
SoapObject soapObject = new SoapObject(AppConstant.NAMESPACE, AppConstant.QUESTION_SOAP_METHOD);
soapObject.addProperty("language", str_lang);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(soapObject);
HttpTransportSE se = new HttpTransportSE(AppConstant.webUrl);
se.call(AppConstant.QUESTION_SOAP_ACTION, envelope);
Object responce = envelope.getResponse();
Log.d("Question List:=>>", "" + responce);
return responce.toString();
} catch (Exception e) {
e.printStackTrace();
pg.dismiss();
return null;
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if (pg.isShowing()) {
pg.dismiss();
Log.i(TAG, s);
if (s != null || !s.equalsIgnoreCase("")) {
try {
JSONArray array = new JSONArray(s);
for (int i = 0; i < array.length(); i++) {
JSONObject obj = array.getJSONObject(i);
String queId = obj.getString(TAG_QID);
String que = obj.getString(TAG_QUE);
String str_Opt = obj.getString(TAG_OPT);
question = new Question(queId, que, str_lang, str_catId, str_Opt, manager.getDateTime());
helper.insertQuestion(question);
}
count++;
if (count < 5) {
if (count == 1) {
str_lang = "German";
str_wait = "bitte warte einen Moment";
new AllQuestion().execute();
}
if (count == 2) {
str_lang = "Italian";
str_wait = "per favore aspetta un momento";
new AllQuestion().execute();
}
if (count == 3) {
str_lang = "Chinese";
str_wait = "请稍候";
new AllQuestion().execute();
}
if (count == 4) {
str_lang = "French";
str_wait = "patientez s'il-vous-plait";
new AllQuestion().execute();
}
Log.d("All Question:-", question.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
}
I have an idea to make async series in just one async task:
protected Boolean doInBackground(String... params) {
if(params[0] == "taskA") {
//do somthing
params[0] = "taskB";
}
if(params[0] == "taskB") {
//do somthing
params[0] = "taskC";
}
if(params[0] == "taskC") {
//do somthing
params[0] = "taskD";
}
if(params[0] == "taskD") {
//do somthing
return true;
}
And in your main thread just call async task like this:
ShowMyProgress(); //if you like
new MyAsyncTask().execute("taskA");
And finally you can hide your progress on onPostExecute like:
protected void onPostExecute(final Boolean success) {
if (success) {
....
HideMyProgress();
}
}
I have solved this kind of problem when i had to download something from a database before login in the user into the app, with this i fixed this problem.
To use ObservableInteger you can do this
first declare it
private ObservableInteger mObsInt;
then in your onCreate you will have a listener waiting for the values of the mObsInt to change, after those values change you can do anything you want
//Listener
mObsInt = new ObservableInteger();
mObsInt.set(0);
mObsInt.setOnIntegerChangeListener(new OnIntegerChangeListener()
{
#Override
public void onIntegerChanged(int newValue)
{
if (mObsInt.get()==1)
//Do something if the first asyncTask finishes
if (mObsInt.get()==2){
//Do something if the second asyncTask finishes, in this case i just go to another activity when both asyncTasks finish
Intent mainIntent = new Intent().setClass(LoginActivity.this, Principal.class);
startActivity(mainIntent);
finish();
}
}
});
So, how it works
ObservableInteger will be looking for changes in the variable mObsInt, so lets say if mObsInt is equal to 1 it will do something, if is equal to 2 will do another thing, so, to solve this problem with 2 asynctasks is easy, when one of the asynctasks finishes mObsInt will be equal to 1 , if the other asyncTask finishes so mObsInt will be mObsInt++ , and then your mObsInt will be equal to 2, the listener will be waiting for the values, and then do what you want to do when the values match your if statment at the onCreate method
now, just in your asynctasks just put in your onPostExecute() method this line
mObsInt.set(mObsInt.get()+1);
so if the first async finish, mObsint == 1 , if the second finish mObsInt == 2, and then you handle what you want to do in your onCreate method
hope this helps for you, it helped me
You can get more info at this doc : https://developer.android.com/reference/android/databinding/ObservableInt.html
happy coding !