Search code examples
androiduser-interfacehandlerrunnableupdating

Android - Having button disabled after second usage


I'm having trouble finding an error, that I obviously should have somewhere. Probably a logic error that I'm not aware of.

I'm having a button, which starts a locationManager locating my position, upon click. While scanning for my location, I want my button to be disabled. I managed to do that (Yay), though after retrieving the location for the first time and clicking the button for the second time, to receive the location for a second time, the button does NOT get disabled anymore. This enables me to tap the button multiple times, starting more and more locationListeners listening for locations. That is just what I tried to prevent by disabling the button while scanning.

Here's my code. Explanation follows.

MainActivity:

public class MainActivity extends FragmentActivity {

// Setting layout dependent variables
...
private Button btn_scan;

// Setting several variables
...

// Setting default values
...

private boolean locationReceived = false;
private boolean gsmReceived = false;
private boolean isBusy = false;

private int counter = 0;
private Handler handler;
private Runnable runnable = new Runnable() {

    public void run() {

        counter ++;
        handler.postDelayed(runnable, 1000);

        if (locationReceived && gsmReceived) {

            // SAVE DATA TO DB HERE! //
            displayInformation();
            handler.removeCallbacks(runnable);

        } else if (counter >= (TIME_TO_WAIT_FOR_RESPONSE+1)) {

            displayInformation();
            handler.removeCallbacks(runnable);

        }
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Application context
    context = getApplicationContext();

    // Handler
    handler = new Handler();

    // initializing layout dependent variables
    ...
    btn_scan = (Button) findViewById(R.id.btn_scan);

    // Initialize GoogleMap
    ...

    // Get the LocationManager for checking, if providers are enabled
    locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

    // Get the PhoneStateListener and telephony service to receive the signal strength
    myListener = new MyPhoneStateListener();
    tel = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

    // Ask for the current location in here.
    locationResult = new LocationResult() {

        @Override
        public void gotLocation(final Location location) {

            // If location given, do something with it. If not, return some message.
            if (location != null) {

                updateGeoData(location);

            }

        }
    };

    btn_scan.setOnClickListener(new OnClickListener(){

        @Override
        public void onClick(View v) {

            if (!isBusy) {
                toogleButton();

                // if GPS is enabled in phone settings
                if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) && !locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {

                    postGPSAlert();
                    toogleButton();

                } else {

                    // If GPS enabled, get info
                    getInformation();
                }
            }
        }
    });
}

/*
 * wrapper method for getting informations
 */
private void getInformation() {

    // start informationfetcher. 
    runnable.run();
    // get geo location, longitude & latitude
    getGeoLocation();
    // get signal strength and its' other parameters
    getSignalStrength();
    // get internet connectivity quality string
    getConnectivityQuality();
    // get internet connectivity type
    getConnectivityType();
}

/*
 * get signal strength. only starts the listener, which does the rest of the job.
 */
public void getSignalStrength() {

    tel.listen(myListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
}

/*
 * get connectivity type and update the variable internetType
 */
private void getConnectivityType() {

   ... nothing important
}

/*
 * Gets internet quality string
 */
private void getConnectivityQuality() {

    ... nothing important
}

/*
 * Gets the geo location
 */
public void getGeoLocation() {

    MyLocation myLocation = new MyLocation(context, TIME_TO_WAIT_FOR_RESPONSE);
    if (!myLocation.getLocation(locationResult)) {
        String message = "To make use of localization, please enable GPS or mobile networking.";
        Toast.makeText(context, message, Toast.LENGTH_LONG).show();
    }
}

/*
 * Updates retrieved GeoData
 */
private void updateGeoData(Location location) {

    latitude = location.getLatitude();
    longitude = location.getLongitude();    
    locationReceived = true;
}

/*
 * Updates GUI with all received values
 */
private void displayInformation() {

    ... only updating textViews here

    if (gsmReceived) {

        ... only updating textViews here

    }

    if (locationReceived) {

        ... only updating textViews here and moving googleMapCamera to some spot

    } 

    // Post Error messages, if location and/or GSM could not be obtained.
    ... just Toasting some error messages, if no signal or GPS received.

    toogleButton();
}

/*
 * Posts an alert saying u gotta enable GPS
 */
private void postGPSAlert() {
    // Prompt alert
    AlertDialog.Builder alert = new AlertDialog.Builder(MainActivity.this);

    // Title and message values
    alert.setTitle(getString(R.string.prompt_titleProviderFail));
    alert.setMessage(getString(R.string.prompt_messageProviderFail));

    // If OK was clicked, redirect to settings to enable GPS
    alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {

        public void onClick(DialogInterface dialog, int whichButton) {

            startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
        }
    });

    // If ABORT was clicked, redirect back to activity
    alert.setNegativeButton("Abort", new DialogInterface.OnClickListener() {

        public void onClick(DialogInterface dialog, int whichButton) {

            // Canceled.
        }
    });

    // Show dialog
    alert.show();
}

/*
 * Method for disabling and enabling the button on pressure/update
 */
private void toogleButton() {

    if (btn_scan.isEnabled()) {

        isBusy = true;
        btn_scan.setText("SCANNING ...");
        btn_scan.setEnabled(false);
    } else if (!btn_scan.isEnabled()) {

        isBusy = false;
        btn_scan.setText("SCAN");
        btn_scan.setEnabled(true);
    }
}

/*
 * (non-Javadoc)
 * Listener, to listen on signalStrength of your phone. It'll set all the variables declared above and update the info you'll see.
 */
private class MyPhoneStateListener extends PhoneStateListener {

    @Override
    public void onSignalStrengthsChanged(SignalStrength signalStrength) {

        super.onSignalStrengthsChanged(signalStrength);

        ... just updating some String variables here

        gsmReceived = true;

        tel.listen(myListener, PhoneStateListener.LISTEN_NONE);
    }
}  

}

Now to the explanation: As soon as I click the button, I'm checking if I'm already having an operation running and I'm disabling the button via the method toogleButton(). So, several methods are triggered to gather some information about the network, signalStrength and my location. Gathering my location usually requires most time, but that's not important. I'm using a handler+runnable to check every second for 60 seconds, if all informations were gathered. If so, I'm displaying all information via displayInformation() on the UserInterface and enabling the button again via toogleButton(). Also, I'm setting the variable isBusy = true. If I did not gather all information and 60 seconds passed, I'm still displaying all (till then) gathered information and toogle the button again (to the enabled state).

All of this works fine, for the first time. When I push the button for the second time AFTER I received all information, the button does not get disabled anymore, though the app still gathers information as it should. The only problem here is that I can now push the button multiple times and start multiple requests to gather the information. That is not what I want. I want it one by one.

Do you know what I did wrong here?


Solution

  • Use Asynctask thread - disable button in onPreExecute , write location search code inside doInBackground() & enable button inside onPostExecude.