Reputation: 340
My code works perfectly but only if I click the button twice. If I click only once, it returns the "limit_customers" = 0.
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.button_to_customers:
int limit_customers = 50;
// R1 = Radiobutton > inside RadioGroup
if(r1.isChecked()){
group_id = 0;
}else{ group_id = 1;}
if(the_list.get(0).getSelected() == true){
Log.e("list:", String.valueOf(the_list.get(0).getSelected()));
// This returns true at first click (it's correct)
if(group_id == 0){
Log.e("group:", String.valueOf(group_id));
// returns 0 at first click (it's correct)
limit_customers = get_customers_count();
Log.e("limit:", String.valueOf(limit_customers));
// returns 0 at first click (it's INCORRECT)
// at second click returns 3 (it's correct)
}
}
break;
}
}
And here's the function to return the count();
public int get_customers_count(){
ExecutorService mExec = Executors.newSingleThreadExecutor();
mExec.execute(new Runnable() {
@Override
public void run() {
try{
SoapObject request = new SoapObject(NAMESPACE, "get_count_customers");
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.call(URL + "/get_count_customers", envelope);
SoapObject rep = (SoapObject) envelope.bodyIn;
JSONArray jr = new JSONArray(rep.getPropertyAsString(0));
JSONObject jb = (JSONObject) jr.get(0);
amount_customers = jb.getInt("count");
}catch (Exception e){
Log.e("Error:", e.toString());
}
}
});
return amount_customers;
}
Anyone have any idea of what could it be?
Edit: I marked all the answers as right, because all of yours answers are right and I solve my problem according to them. Thank you.
Upvotes: 1
Views: 873
Reputation: 6441
Use AsyncTask
instead of thread, because the threads are run in background, and the foreground flow didn't looks/wait for that.
Sample code,
private class GetCustomersCont extends AsyncTask<Void, Void, Void> {
private int amount_customers = 0;
private ProgressDialog dialog=null;
@Override
protected void onPreExecute() {
dialog = new ProgressDialog(this);
dialog.setCancelable(false);
dialog.setMessage("Please Wait..");
dialog.show();
}
@Override
protected Void doInBackground(Void... params) {
try{
SoapObject request = new SoapObject(NAMESPACE, "get_count_customers");
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.call(URL + "/get_count_customers", envelope);
SoapObject rep = (SoapObject) envelope.bodyIn;
JSONArray jr = new JSONArray(rep.getPropertyAsString(0));
JSONObject jb = (JSONObject) jr.get(0);
amount_customers = jb.getInt("count");
}catch (Exception e){
Log.e("Error:", e.toString());
}
return null;
}
@Override
protected void onPostExecute(Void result) {
if(dialog.isShowing())
dialog.dismiss();
Log.e("limit:", String.valueOf(limit_customers));
}
}
And change onClick()
to,
private GetCustomersCont mGetCustomersCont = null;
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.button_to_customers:
int limit_customers = 50;
// R1 = Radiobutton > inside RadioGroup
if(r1.isChecked()){
group_id = 0;
}else{ group_id = 1;}
if(the_list.get(0).getSelected() == true){
Log.e("list:", String.valueOf(the_list.get(0).getSelected()));
// This returns true at first click (it's correct)
if(group_id == 0){
Log.e("group:", String.valueOf(group_id));
mGetCustomersCont = new GetCustomersCont();
mGetCustomersCont.execute();
}
}
break;
}
}
Upvotes: 1
Reputation: 6472
The get_customers_count
method's implementation executes a asynchronous runnable to populate amount_customers
. When you click the first time the JSON parsing hasn't completed thus the class level variable amount_customers
remains as it's default value (zero). At some point between your first and second click the runnable completes and the line;
amount_customers = jb.getInt("count");
...is run. This means that the class variable is populated giving rise to the log output showing the correct value. Importantly, the second click has started another async task to repopulate the amount_customers variable the second time around which you do not see.
To get the answer directly then the call needs to be made synchronous. However, as you have correctly noted, doing synchronous calls for network communications on the I/O thread is bad news (results in ANRs). You'll probably want some sort of UI widget indicating that the value of amount_customers is being fetched. When the value is returned from the parsing task then you'll be wanting to invoke a listener method (which you passed into get_customers_count) to inform the code which is reliant of the value that it is safe to progress. During this time you'll want to disable the button press also so further (duplicate) requests are not made. A reasonable UI would look like this;
Non-pressed state... (normal button)
_____________________
| |
| Button label |
|___________________|
After click... (with spinner informing the user something is happening - button disabled)
_____________________
| |
| Button label {/} | ...{/} => spinner.
|___________________|
On result returned.... (normal button)
_____________________
| |
| Button label |
|___________________|
and then perform the action reliant on the result.
Upvotes: 1
Reputation: 22064
return amount_customers;
will be called before you have a chance to execute your code against the server (because the server call runs in a separate thread). That is why you get 0, next time you click on your button, you will get the result for the first call, third click results in result for second call etc.
Upvotes: 1