0

I've noticed a bug in a basic survey app I'm making to better learn android.

Occasionally I get a W/System.err﹕ at MainActivity.surveyAvailable(MainActivity.java:40) that points to this line of code:

button.setVisibility(View.GONE);

I've used setVisibility many times before and never had any issues.

Here's the function, this gets called when the user first enters the app, and after they finish taking a survey to check the server and see if there is another survey available for the user:

public void surveyAvailable(boolean surveyIsAvailable) {
        Log.d("MainActivity", "App survey is available? " + surveyIsAvailable );
        Button button = (Button)findViewById(R.id.takeSurveyButton);

        if (surveyIsAvailable) {
            button.setVisibility(View.VISIBLE);

            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    App.getInstance().showSurvey();
                }
            });
        } else {
            Log.d("MainActivity", "We hit here");
            button.setVisibility(View.GONE);

        }
    }

When a survey isn't available, the appropriate lines are logged - App survey is available? false and 'We hit here'. But then the button sometimes doesn't get set to View.GONE and I see the System.Err line. But sometimes it works fine and the button's visibility does change. Any idea how to fix that? Or how to get more information on what the System.Err actually means?

EDIT:

I found that by setting Button surveyButton; in my activity and then referencing the button as this.surveyButton seems to get the functionality to work more along the lines of what we'd expect (e.g. when we call button.setVisibility(View.GONE) the view is actually consistently GONE). But it still throws the System.Err line which has me hesitant that things are working correctly.

Edited Activity:

public class MainActivity extends ActionBarActivity implements SurveyListener {
    Button surveyButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        this.surveyButton = (Button)findViewById(R.id.takeSurveyButton);
    }

    public void surveyAvailable(boolean surveyIsAvailable) {
        Log.d("MainActivity", "App survey is available? " + surveyIsAvailable );

        if (surveyIsAvailable) {
            this.surveyButton.setVisibility(View.VISIBLE);

            this.surveyButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    App.getInstance().showSurvey();
                }
            });
        } else {
            Log.d("MainActivity", "We hit here");
            this.surveyButton.setVisibility(View.GONE);

        }
    }

}

The activity implements this class:

public abstract interface SurveyListener
{
    public abstract void surveyAvailable(boolean surveyAvailable);
}

Main App class that checks for surveys and calls 'surveyAvailable()`:

public class App
{
    private static App _instance;
    private SurveyListener _eventsHandler;
    private String _apiKey = "";
    private String _appuserId = "";
    private String _surveyUrl = "";
    private Activity _parentContext;
    private Boolean _surveyAvailable;

    public static App initWithApiKeyAndListener(String apiKey, SurveyListener surveyEventsHandler) {
        if (_instance == null)
        {
            _instance = new App();
            _instance._parentContext = (Activity) surveyEventsHandler;
            _instance.setSurveyListener(surveyEventsHandler);
            _instance.setApiKey(apiKey);

            String appuserId = PreferenceManager.getDefaultSharedPreferences((Activity) _instance._eventsHandler).getString(tag, "no_appuser");
            if (appuserId == "no_appuser") {
                _instance._surveyAvailable = true;
                _instance.alertAvailability(true);
            } else {
                _instance.checkForCampaigns();
            }
        }

        return _instance;

    }

    private void alertAvailability(boolean surveyAvailable) {
        App.getInstance()._eventsHandler.surveyAvailable(surveyAvailable);
    }

    private void checkForCampaigns() {
        new CampaignCheck().execute();
    }

    public static App getInstance()
    {
        if (_instance == null)
        {
            _instance = new App();
        }
        return _instance;
    }

    public void donePushed()
    {
        App.getInstance().checkForCampaigns();
    }

    private class CampaignCheck extends AsyncTask<Void, Void, Void> {
        protected Void doInBackground(Void... params) {

            Boolean surveysAvailable = false;
            try {
                surveysAvailable = new AppuserConnection().checkCampaigns();
                App.getInstance()._surveyAvailable = surveysAvailable;
                App.getInstance().alertAvailability(_surveyAvailable);

            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {

        }
    }
}
Tom Hammond
  • 5,842
  • 12
  • 52
  • 95
  • Check this link [Similar problem](http://stackoverflow.com/questions/7348150/android-why-setvisibilityview-gone-or-setvisibilityview-invisible-do-not) – CodeCody Dec 24 '15 at 20:55
  • Yea, I found that one earlier but it didn't seem to solve my problem. It also seemed that the issue there was that he was first called `View.INVISIBLE` followed by `View.GONE` whereas here I'm just doing the latter – Tom Hammond Dec 24 '15 at 21:02
  • What is calling the `surveyAvailable()` method? – RogueBaneling Dec 24 '15 at 21:12
  • check your layout xml file if you put the `button` as `INVISIBLE` instead `GONE` in the first time – Context Dec 24 '15 at 21:14
  • It's doesn't have a visibility attribute in my layout, I tried adding visible there, but the same deals happening. I'm going to add the code that calls `surveyAvailable` – Tom Hammond Dec 24 '15 at 21:24
  • how and where do you call initWithApiKeyAndListener ? – csenga Dec 24 '15 at 22:04

1 Answers1

1

You shouldn't modify the UI elements from a different thread. You are doing this by calling App.getInstance().alertAvailability(_surveyAvailable); on a background thread. Move this to the AsyncTask's onPostExecute.

RogueBaneling
  • 4,331
  • 4
  • 22
  • 33