在AsyncTask中保持对Fragment的强引用是否安全?

时间:2012-05-22 19:50:30

标签: android android-asynctask android-fragments

由于不建议在任务中保持对Context的强引用(当任务仍在运行时上下文可能会被破坏,但是由任务保存在内存中),我想知道是否相同适用于碎片?

片段管理其活动参考,并支持通过setRetainInstance保留。我可以假设,例如在片段中创建非静态内部AsyncTask是否安全,不会有泄漏$this的风险?

2 个答案:

答案 0 :(得分:6)

在线程之间保持引用通常是不好的方法,AsyncTask类似于线程。

没关系,只要你确保在使用它时取消引用它。

否则,您可能会出现内存泄漏。

在这种情况下,没关系,因为Fragment位于AsyncTask的上下文中。任务完成后,它将失去该引用。

如果这是在Service中完成的,那将是一个非常糟糕的主意。

答案 1 :(得分:2)

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) {

}