Как я могу форсировать блокировку перерисовки элемента пользовательского интерфейса? - PullRequest
0 голосов
/ 23 июня 2019

У меня есть простая страница входа в систему, где пользователь вводит пароль, и этот пароль используется для расшифровки некоторых данных и создания основного действия.Процесс генерации ключа, вызова базы данных и создания основного действия занимает около 5 секунд, поэтому я хочу, чтобы колесо прогресса отображалось на экране входа в систему сразу после того, как пользователь нажимает кнопку входа.

К сожалению, поскольку android обрабатываетПользовательский интерфейс обновляется неблокирующим образом, индикатор выполнения не будет отображаться до запуска функции входа в систему.Кажется, я не могу найти способ принудительно обновить блокировку пользовательского интерфейса для представления в Android.invalidate() и postInvalidate() оба не будут работать, поскольку они просто уведомляют Android о том, что в какой-то момент в будущем должно произойти перерисовка.

Вот пример кода, объясняющего, что я пытаюсь выполнить:

        try {
            progressBar.setVisibility(View.VISIBLE);
            passwordEditText.setEnabled(false);

            Key key = doLogin(passwordEditText.getText()); // Long operation

            Intent intent = new Intent(getActivity(), MainActivity.class);
            intent.putExtra("Key", key);
            startActivity(intent);

            getActivity().finish();

        } catch (Exception e) {
            passwordEditText.setError(getString(R.string.login_error));
            Log.e("Login", e.getMessage());
        } finally {
            progressBar.setVisibility(View.INVISIBLE);
            passwordEditText.setEnabled(true);
        }

Если невозможно переопределить поведение по умолчанию и вызвать немедленное блокирование перерисовки, то как лучше всего реализовать колесо прогресса, пока работает метод doLogin()?

Ответы [ 2 ]

0 голосов
/ 23 июня 2019

Исправлена ​​проблема. Вот мое решение. Это может быть немного преувеличено, но я попытался сделать его легко расширяемым, чтобы его можно было применить к другим аналогичным сценариям.

AsyncTask для входа в систему:


    static class LoginTask extends AsyncTask<String, Void, LoginTask.LoginTaskResultBundle> {

        private TaskActions mActions;

        LoginTask(@NonNull TaskActions actions) {
            this.mActions = actions;
        }

        @Override
        protected void onPreExecute() {
            mActions.onPreAction();
        }

        @Override
        protected LoginTaskResultBundle doInBackground(String... args) {
            try {
                Key key = doLogin();

                return new LoginTaskResultBundle(LoginTaskResultBundle.SUCCEEDED, key);
            } catch (Exception e) {

                return new LoginTaskResultBundle(LoginTaskResultBundle.FAILED, e);
            }
        }

        @Override
        protected void onPostExecute(LoginTaskResultBundle result) {
            if (result.getStatus() == LoginTaskResultBundle.SUCCEEDED)
                mActions.onPostSuccess(result);
            else
                mActions.onPostFailure(result);
        }

        // Result Bundle

        class LoginTaskResultBundle {
            static final int FAILED = 0;
            static final int SUCCEEDED = 1;

            private int mStatus;
            private Exception mException;
            private Key mKey;

            LoginTaskResultBundle(int status, Key key) {
                mStatus = status;
                mKey = key;
                mException = null;
            }

            LoginTaskResultBundle(int status, Exception exception) {
                mStatus = status;
                mException = exception;
            }

            int getStatus() {
                return mStatus;
            }

            Exception getException() {
                return mException;
            }

            Key getKey() {
                return mKey;
            }
        }

        // Interface

        interface TaskActions {
            void onPreAction();
            void onPostSuccess(LoginTaskResultBundle bundle);
            void onPostFailure(LoginTaskResultBundle bundle);
        }
    }

Пример вызова LoginAsyncTask:

         new LoginTask(
                  new LoginTask.TaskActions() {
                    @Override
                    public void onPreAction() {
                        showProgressBar();
                    }

                    @Override
                    public void onPostSuccess(LoginTask.LoginTaskResultBundle bundle) {
                        launchMainActivity();
                    }

                    @Override
                    public void onPostFailure(LoginTask.LoginTaskResultBundle bundle) {
                        hideProgressBar();

                        passwordEditText.setError(bundle.getException().getMessage());
                        Log.e("Login", bundle.getException().getMessage());
                    }
                } )
                .execute(passwordEditText.getText().toString());
0 голосов
/ 23 июня 2019

Не получается найти способ принудительно обновить блокировку пользовательского интерфейса для представления в Android

Правильно. Это не то, как работает система просмотра Android.

тогда как лучше всего реализовать колесо прогресса, пока выполняется метод doLogin ()?

Необходимо выполнить doLogin() в фоновом потоке. Обновите пользовательский интерфейс основного потока приложения, когда фоновая работа завершится. Примите во внимание, что ваш пользовательский интерфейс может больше не существовать (например, пользователь нажал НАЗАД) или может быть заменен (например, пользователь повернул устройство или иным образом вызвал изменение конфигурации) во время этой фоновой работы.

В современной разработке приложений для Android три основных подхода для этого - использовать ViewModel и LiveData вместе с:

  • RxJava

  • Сопрограммы (для разработки приложений в Котлине)

  • Ваш собственный фоновый поток

...