Обновление текущего вида деятельности позади / при отображении диалогового окна загрузки - PullRequest
2 голосов
/ 29 февраля 2012

У меня есть приложение, в котором поток приложений отличается от стандарта Android:

  • Стандарт : нажатие кнопки в действии A и отображение загрузки этого действияво время загрузки данных и построения представлений о деятельности B и только затем показать следующее действие. (вызов AsyncTask для операции A, когда закончите, отправьте данные и вызовите операцию B)

  • Что мне нужно : нажмите кнопку на операции A, перейдите к действию B и, пока показывает загрузку, обновите представление действия B за загрузкой. (Перейдите от действия A к B и там вызовите AsyncTask, показывая загрузку. Когда AsyncTask завершит, обновите представление, пока загрузка идет вперед, показывая процесс обновления представления) Проблема: из-за этого значок загрузки останавливается ... и иногда отображается диалоговое окно без ответа (из-за длительного выполнения операции) и использование потока пользовательского интерфейса для изменения создаваемого представления.

    Я прочитал несколько вопросов по этому поводу: Android: как динамически обновлять пользовательский интерфейс?

    Но ни один из них не дал общего ответа.

    Если вы ответите ""это не рекомендуемое поведение "я согласен ... но это требования, поэтому я буду очень признателен за некоторую помощь: -D

Ответы [ 4 ]

4 голосов
/ 04 марта 2012

Я впервые сделал это уже год назад в проекте.У меня возникла та же проблема, потому что я пытался использовать значок, и было так много обновлений, что значок иногда зависал, поэтому я в итоге использовал Handler в паре с AsyncTask.На самом деле это очень распространенный шаблон в действиях предварительной настройки.

Это следующие шаги:

  1. Создайте диалог загрузки, разместив его в Handler объекте.Вы можете использовать что-то вроде this (диалоговое окно загрузки вместо Toast, очевидно).
  2. Начните AsyncTask, выполняя вычисления.
  3. Всякий раз, когда частииз расчета готовы, вы publishProgress.Присвойте флаги коду, чтобы точно сказать, какие части пользовательского интерфейса необходимо построить.Вы увидите, что пользовательский интерфейс строится позади, пока ваше диалоговое окно загрузки отображается и вращается.
  4. Когда все будет сделано, вы закроете диалоговое окно в onPostExecute.

Ниже приведенПример кода, который в точности соответствует тому, что вы описываете:

private void settingsAndPlaceTaskStart() {

    // loading dialog
    startLoading();

    new AsyncTask<Context, Integer, Void>() {
        @Override
        protected Void doInBackground(Context... context) {

            // check and prepare settings integrity
            Settings st = new Settings(context[0], false);
            st.checkPreferencesIntegrity();

            // set text for each view / paired object
            // this will take a long time
            do {
                // ... removed for clarity
                int code = ...;
                publishProgress(mObjects.getViewByCode(code));    
                while (mObjects.getNext());
            return null;
        }

        @Override
        protected void onPostExecute(Void void) {
            // finish stuff
        }

        @Override
        protected void onProgressUpdate(Integer... message) {
            prepareView(message[0]);
        }

    }.execute(getActivity());
}

Здесь загрузка не страдает от каких-либо заиканий, пока прогресс вращается в диалоге.Диалог остается на переднем плане до onPostExecute.Вы должны закрыть диалоговое окно там, после окончания задачи.

2 голосов
/ 07 марта 2012

A. Посмотрите на приложение Android Market (я не уверен, как оно работает в режиме «играть») - когда вы нажимаете на приложение - отображается пустое действие только с полосой цикла, а любые другие данные отображаются после полной загрузки. Вы хотите такое же поведение? Если да - сработает следующее:

Ваш макет для действия B:

<RelativeLayout>
    <common_layout_of_your_view_that_covers_all_space />
    <layout_for_progress />
</RelativeLayout>

layout_for_progress может быть любым макетом, а если вы хотите сделать его прозрачным - поставьте специальный фон.

У вас активность B, чем просто запустить поток для фоновой загрузки данных:

onCreate(...) {
    //call super
    //set content view

    new Thread(new Runnable() {
        public void run() {
            while(!downloadComplete) {
                //ask some portion of data
                ActivityB.this.runOnUIThread(new Runnable(){
                    public void run() {
                        //update your main view
                    }
                });
            }
            findViewById(R.id.layout_for_progress).setVisibility(View.GONE);
        }
    }).start();
}
2 голосов
/ 04 марта 2012

Позвольте мне убедиться, что у меня есть это право: Задание А - ваше первое, Б - ваше второе. Вам нужна кнопка на A, которая запускает 2 вещи: асинхронную загрузку данных и нажатие B в стеке Activity. Это все хорошо.

В « Что мне нужно » вы используете глагол «обновить представление в фоновом режиме». Это невозможно - вы можете обновить только представление в основном потоке пользовательского интерфейса. Кроме того, после вызова A onPause() (вызванного нажатием B), вы действительно должны считать A недоступным для обработки. Что вы можете сделать, это загрузить данные в фоновом режиме, в то время как B делает свое дело, а затем A в своем onResume() может соответствующим образом обновить свой пользовательский интерфейс.

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

UPDATE

Я не уверен, как вы будете выполнять работу с ресурсами пользовательского интерфейса Деятельности Y, находясь в пределах Деятельности X, особенно если Y еще не было onCreate()d. Я не знаю, возможно ли совместное использование ресурсов макета между операциями, хотя это может быть.

Ссылка, которую вы разместили выше, ведет к ней - я думаю, что ответ относительно использования класса Handler является частью вашего решения. Также читайте о Looper и Проектирование для отзывчивости . Короче говоря, вы захотите реализовать обработчик в своем основном потоке, который позволит вам обновлять пользовательский интерфейс небольшими порциями по 100-200 мс (как предложено в Отзывчивость ) и, с высокой степенью детализации, отправлять сообщения в этот обработчик, когда вы обрабатываете небольшие кусочки данных в фоновом потоке. Например, если вы обновляете ListView, вы сможете раздувать по одной строке за раз. Аналогично, если вы добавляете изображения в GridView. Кроме того, рассмотрите возможность pre -загрузки ресурсов, но не показывайте их, чтобы вы могли тратить меньше времени на раздувание, когда времени мало.

Это насколько мои мысли забирают меня в данный момент, но я отмечаю это как фаворит, потому что я думаю, что мне придется сделать что-то подобное через несколько недель. Держите нас в курсе, что работает для вас. Удачи!

1 голос
/ 29 февраля 2012

Вы можете запустить asyncTask в onCreate и заставить его выполнять все ваши вычисления.В то же время вы можете отобразить панель загрузки.Затем в onPostExecute вы можете обновить просмотры собранной информацией и отключить индикатор выполнения

...