Ответ Phoenixblade9 верен, но чтобы сделать его полным, я добавлю одно.
Есть отличная замена AsyncTask - AsyncTaskLoader или Loaders вообще. Он управляет своим жизненным циклом в соответствии с контекстом, из которого он был вызван (Activity, Fragment), и реализует кучу слушателей, чтобы помочь вам отделить логику второго потока от потока ui. И это, как правило, невосприимчиво к протекающему контексту.
И не беспокойтесь о названии - это хорошо для сохранения данных.
Как и было обещано, я отправлю свой код для AsyncTaskLoader с возвратом нескольких объектов. Загрузчик идет что-то вроде этого:
public class ItemsLoader extends AsyncTaskLoader<HashMap<String, Object>>{
HashMap<String, Object> returned;
ArrayList<SomeItem> items;
Context cxt;
public EventsLoader(Context context) {
super(context);
//here you can initialize your vars and get your context if you need it inside
}
@Override
public HashMap<String, Object> loadInBackground() {
returned = getYourData();
return returned;
}
@Override
public void deliverResult(HashMap<String, Object> returned) {
if (isReset()) {
return;
}
this.returned = returned;
super.deliverResult(returned);
}
@Override
protected void onStartLoading() {
if (returned != null) {
deliverResult(returned);
}
if (takeContentChanged() || returned == null) {
forceLoad();
}
}
@Override
protected void onStopLoading() {
cancelLoad();
}
@Override
protected void onReset() {
super.onReset();
onStopLoading();
returned = null;
}
В функции getYourData()
я получаю как код сообщения сервера или какой-либо другой код ошибки и ArrayList<SomeItem>
. Я могу использовать их в своем фрагменте следующим образом:
public class ItemListFragment extends ListFragment implements LoaderCallbacks<HashMap<String, Object>>{
private LoaderManager lm;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
lm = getLoaderManager();
Bundle args = new Bundle();
args.putInt("someId", someId);
lm.initLoader(0, args, this);
}
@Override
public Loader<HashMap<String, Object>> onCreateLoader(int arg0, Bundle args) {
ItemsLoader loader = new ItemsLoader(getActivity(), args.getInt("someId"));
return loader;
}
@Override
public void onLoadFinished(Loader<HashMap<String, Object>> loader, HashMap<String, Object> data) {
if(data!=null){ if(data.containsKey("items")){
ArrayList<SomeItem> items = (ArrayList<EventItem>)data.get("items");
} else { //error
int error = 0;
if(data.containsKey("error")){
error = (Integer) data.get("error");
}
}
}
@Override
public void onLoaderReset(Loader<HashMap<String, Object>> arg0) {
}
Риск в этом случае, если вы сохраните ссылку на асинтезу, когда фрагмент мертв. Пользователь может сказать, делает действие, которое выталкивает фрагмент из стека. В этом случае вы обычно не хотите, чтобы состояние Фрагмента существовало больше. Если вы хотите, чтобы состояние asynctask содержало дополнительные данные, которые вы хотели использовать, он сохранил ссылку на фрагмент, даже если фрагмент больше не должен существовать. Я верю, что он будет отстранен от деятельности, так как он прошел обычный жизненный цикл, но он все равно «будет существовать». – DeeV
@DeeV: Да, это именно то, что меня беспокоило. – Matthias
Не могли бы вы просто уйти с назначением его на WeakReference и отменить AsyncTask, если Fragment станет null? – DeeV