#android #android-asynctask
#Android #android-asynctask
Вопрос:
Эй, итак, оглядевшись, кажется, что консенсус заключается в том, что использование publishProgress () было бы способом обновить пользовательский интерфейс для более длительных вычислений. Кажется, я реализовал это неправильно, потому что, когда я запускаю этот код, я получаю ANR. Можете ли вы помочь мне понять, почему?
Вот мой код:http://pastebin.com/zQNhkDJ9
Комментарии:
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();
}
Это также приведет к повторной инициализации вашего владельца состояния с текущей активностью, чтобы вы могли повторно установить любые виджеты пользовательского интерфейса, такие как обновления индикатора выполнения и т.д.
Используя этот шаблон, вы действительно можете запускать асинхронные задачи и обрабатывать изменения поворота с помощью повторной инициализации индикаторов выполнения.