Обновление пользовательского интерфейса в AsyncTask

#android #android-asynctask

#Android #android-asynctask

Вопрос:

Эй, итак, оглядевшись, кажется, что консенсус заключается в том, что использование publishProgress () было бы способом обновить пользовательский интерфейс для более длительных вычислений. Кажется, я реализовал это неправильно, потому что, когда я запускаю этот код, я получаю ANR. Можете ли вы помочь мне понять, почему?

Вот мой код:http://pastebin.com/zQNhkDJ9

http://pastebin.com/HcNZtAsx

Комментарии:

1. Я не вижу нигде в вашем коде, где вы создаете и выполняете свою AsyncTask. Это происходит в другом файле?

2. Да, я не думал, что мне нужно будет публиковать это

Ответ №1:

Вероятно, ваша проблема в том, что ваша функция doInBackground просто вызывает publishProgress. Вся ваша работа выполняется в publishProgress, который выполняется в потоке пользовательского интерфейса, так что вы все равно получите ANR таким образом. Вам нужно выполнить тяжелую работу внутри doInBackground, а затем, как только ваша обработка будет завершена, вы сможете обновить поток пользовательского интерфейса.

Комментарии:

1. Вычисление того, какого цвета должно быть представление в моем пользовательском интерфейсе, — это моя тяжелая работа. Итак, как мне предотвратить сбой пользовательского интерфейса?

2. Верно, но вы выполняете вычисления внутри вашей функции onProgressUpdate. Это должно быть выполнено внутри doInBackground, а затем вы должны обновить цвета новыми значениями внутри onProgressUpdate.

Ответ №2:

Вам нужно сделать вашу AsyncTask статическим внутренним классом, и у него есть свойство, которое является ссылкой на вашу активность. Затем вы можете просто вызывать методы для своей активности напрямую — как вы для UIupdate().

Проблема, о которой вы должны знать, заключается в том, что теперь вы должны быть ОЧЕНЬ осторожны, чтобы удалить эту ссылку на вашу активность при любых обратных вызовах onPause, иначе вы установили циклическую ссылку, и это приведет к утечке памяти.

Мой шаблон заключается в том, чтобы иметь другой базовый объект Java, обычно другой частный статический класс в Activity, который я называю «StateHolder», и его мой шлюз для обработки содержимого AsyncTask, такого как его инициализация и очистка (установка в NULL) и отмена любых выполняемых задач во время смены вращения. В вашем обратном вызове для «onRetainNonConfigurationInstance» вы можете передать свой StateHolder в качестве вашего маршалируемого объекта.

Вот несколько примерных кодов:

частный статический класс GetConnectionsStatusTask расширяет AsyncTask { mActivity private BoothActivity; причина частного исключения mReason;

 public GetConnectionsStatusTask(BoothActivity activity) {
    super();
    mActivity = activity;
}

public void setActivity(BoothActivity activity) {
    mActivity = activity;
}

@Override
protected void onPreExecute() {
    if(mActivity != null) {
        mActivity.startProgressBar("Loading", "Please wait");
    }
}

@Override
protected Connections doInBackground(Void... values) {
    try {
        App app = (App)mActivity.getApplication();
        return(app.getApp().userConnections());
    }catch(Exception e) {
        mReason = e;
        return(null);
    }
}

@Override
protected void onPostExecute(Connections status) {
    super.onPostExecute(status);
    if(mActivity != null) {
        mActivity.completedConnectionsStatusCheck(status, mReason);
    }
}       
 }
  

частный статический класс StateHolder {
private GetConnectionsStatusTask connectionsTask;

 public void cancelTasks() {
        if (connectionsTask != null) {
            connectionsTask.setActivity(null);
            connectionsTask.cancel(true);
            connectionsTask = null;
        }
}
    public void setActivityForTasks(BoothActivity activity) {
        if (connectionsTask != null) {
            connectionsTask.setActivity(activity);
        }
}

    public void startConnections(BoothActivity activity) {
        if(mIsConnectionsChecking == false) {
            mIsConnectionsChecking = true;
            connectionsTask = new GetConnectionsStatusTask(activity);
            connectionsTask.execute();              
        }
    }
  }
  

Затем в onPause у меня есть код, подобный:

         if(mStateHolder != null) {
            mStateHolder.cancelTasks();
        }
  

И в onCreate вы можете повторно увеличить свой StateHolder следующим образом:

     Object retained = getLastNonConfigurationInstance();
    if(retained != null amp;amp; retained instanceof StateHolder) {
        mStateHolder = (StateHolder) retained;
        mStateHolder.setActivityForTasks(this);
     } else {
       mStateHolder = new StateHolder();
     }
  

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

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