user2742861
user2742861

Reputation: 340

Android button only works if clicked two times

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

Answers (3)

Sino Raj
Sino Raj

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

BrantApps
BrantApps

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

Carnal
Carnal

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

Related Questions