tags:

views:

52

answers:

1

I am doing a login Activity which basically has an EditText and two Buttons. It looks like this:

http://img249.imageshack.us/img249/9108/loginm.png

The EditText has a TextWatcher that validates the user with an AsyncTask that hits a webservice.

The code:

public class Login extends Activity {

    private EditText mUserNameET;
    private Drawable mCorrect;
    private Drawable mIncorrect;
    private ProgressBar mProgressBar;
    private MyApp mApp;

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

        mApp = (MyApp) getApplication();
        mUserNameET = (EditText) findViewById(R.id.user_name_et);
        mUserNameET.addTextChangedListener(new LoginValidator());

        mCorrect = getResources().getDrawable(R.drawable.correct);
        mIncorrect = getResources().getDrawable(R.drawable.incorrect);
        mProgressBar = new ProgressBar(this);
    }

    private class LoginValidator implements TextWatcher {

        private ValidateUserAsyncTask validator = new ValidateUserAsyncTask();

        @Override
        public void afterTextChanged(Editable s) {

            String value = s.toString();

            if ( value.length() == 0 )
                return;

            /* If it's running, cancel it. */
            /* Issue #2 */
            if ( AsyncTask.Status.RUNNING == validator.getStatus() ) {
                validator.cancel(true);
                validator = new ValidateUserAsyncTask();
            } else if ( AsyncTask.Status.FINISHED == validator.getStatus() ) {
                validator = new ValidateUserAsyncTask();
            }

            validator.execute(value);
            /* Issue #1 */
            mUserNameET.setCompoundDrawables(null, null, mProgressBar.getProgressDrawable(), null);
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before,
                int count) {
        }
    }

    class ValidateUserAsyncTask extends AsyncTask<String, Void, Boolean> {

        @Override
        protected void onPostExecute(Boolean result) {
            super.onPostExecute(result);

            if ( result ) {
                mUserNameET.setCompoundDrawablesWithIntrinsicBounds(null, null, mCorrect, null);
            } else {
                mUserNameET.setCompoundDrawablesWithIntrinsicBounds(null, null, mIncorrect, null);
            }
        }

        @Override
        protected Boolean doInBackground(String... params) {
            return mApp.validateUser(params[0]);
        }
    }
}

My issues:

While the AsyncTask is working I want to show a ProgressBar inside the EditText. I tried to do it using:

mUserNameET.setCompoundDrawables(null, null, mProgressBar.getProgressDrawable(), null);

but it doesn't work.

And I am also a bit worried about creating new instances of the AsyncTask. Am I leaking memory?

+1  A: 

While the AsyncTask is working I want to show a ProgressBar inside the EditText

Try creating an AnimationDrawable representing your progress indicator, and use that with setCompoundDrawables().

And I am also a bit worried about creating new instances of the AsyncTask. Am I leaking memory?

Well, you can't reuse AsyncTask instances -- they are one-and-done. Bear in mind that AsyncTask uses a thread pool, and so you may have multiple AsyncTasks executing at one time, which may or may not be what you have in mind. I would consider waiting until there has been no typing for, say, 1 second, before doing the Web service stuff.

CommonsWare
@CommonsWare: You mean I should replace the `ProgressBar` with an `AnimationDrawable` of my own?What would you use to implement the one second wait, before hitting the WebService?
Macarse
@Macarse: I don't know how you can get a `ProgressBar` *inside* an `EditText`, and certainly not via `setCompoundDrawables()`, as `ProgressBar` is a widget with a `LevelListDrawable` at its core. For the delay, I'd probably use `postDelayed()` in a fairly tight loop (e.g., 200ms). On every keystroke update a lastKeyTime value with `SystemClock.elapsedTime()`. The `Runnable` for `postDelayed()` sees if `lastKeyTime` was over 1 second -- if so, do the Web service; if not, reschedule the `Runnable`. This won't be perfect, but it beats you calling the Web service 5 times in parallel or something.
CommonsWare