1

我已经读过这个:http: //developer.android.com/guide/components/fragments.html

我正在将一些活动代码移动到一个全新的片段,但发现之前在 onCreate() 中的代码存在问题。

  • 使用片段的目的:标签。

  • 每个选项卡开关上调用的代码:

    FragmentManager fm = getSupportFragmentManager();

    FragmentTransaction ft = fm.beginTransaction();

    ft.replace(R.id.tabContent, fragment1);

    ft.commit();

其中fragment1、fragment2等是activity的实例变量,在onCreate

fragment1 = new Fragment1();
//etc.
  • 我希望它们如何工作:就像活动(!)一样,意味着:创建后 - 我在其中调用我的 web 服务,并且列表第一次被初始化,没有更多的初始化,所以当我切换选项卡时,列表仍然是如何我离开了它(滚动等),当我回来时没有视图初始化或 web 服务调用,它只是再次出现。就像在活动中一样,如果我启动另一个活动,然后回来 -onCreate()将不会被调用,只有onResume(). 而且由于我只在 中进行初始化onCreate(),所以很好。

我正在调用 onCreate() 一个网络服务来获取数据以填充列表。根据片段的生命周期,有几个候选者可以放置这段代码,但没有一个是完全有效的:

  1. onCreate():在 onCreateView() 之前调用。所以视图层次结构还没有初始化,调用 web 服务是不安全的。

  2. onCreateView():当我切换标签/运行显示的代码片段时,它总是被调用。

  3. onActivityCreated():我以为只有在创建 Activity 之后才会调用它,但它总是在 Fragment.onCreateView() 之后调用

作为一个附带问题,您是否建议在片段中调用 Web 服务?在网上没有找到任何关于此的内容,但不知道为什么它不正确。

提前致谢!

4

2 回答 2

1

使用装载机:

创建 AsyncLoader 的子类并在 Fragment 的 onActivityCreated 实现中启动/初始化这些加载器:

public abstract class MyLoader extends AsyncTaskLoader<String> {
public MyLoader(Context context) {
    super(context);
}

private String result;
protected String error;

@Override
public final String loadInBackground() {
    try {
        error = null;
        // Load your data from the server using HTTP and store result as string in 'result'.
        ...
        result = ...
        ...
        return result;
    }
    catch (Exception e) {
        Logger.e("ResourceLoader", "Loading resource failed.", e);
        error = e.getMessage();
    }
    return null;
}

@Override
protected void onStartLoading() {
    if (!TextUtils.isEmpty(error)) {
        deliverResult(result);
    }

    if (takeContentChanged()) {
        forceLoad();
    }
}

@Override
public void deliverResult(String data) {
    if (isReset()) {
        return;
    }

    result = data;

    if (isStarted()) {
        try {
            super.deliverResult(data);
        }
        catch(Exception e) { 
            Log.e("ResourceLoader", "Caught exception while delivering result.", e);
        }
    }
}

public String getError() {
    return error;
}
}

在你的片段中,你可以初始化这个加载器:

public class Fragment1 extends Fragment implements LoaderCallbacks<String> {
....
....
String message;
TextView textView;

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setRetainInstance(true);
        ....
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = ....
    ...
    textView = (TextView)view.findViewById(R.id.....);
    textView.setMessage(message); // in case this Fragment1 survived an orientation change.
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    getLoaderManager().initLoader(0, getArguments(), this); // Start loading data after activity has been created.
}

@Override
public Loader<String> onCreateLoader(int id, Bundle args) {
    return new MyLoader(getActivity()); // Load data using MyLoader
}

@Override
public void onLoadFinished(Loader<String> loader, String result) {
    // Here you have the result in 'result'.
    message = result;
    if (textView != null) {
        // Update UI according to result.
        textView.setText(message);
        ....
    }
    ...
}
....
}

在 onLoadFinished 中,您将结果存储在“消息”中。如果一个简单的 String 结果不够用,您可以更改 MyLoader 和 LoaderCallbacks 以返回和处理更复杂的数据结构(例如 List<String>)。

于 2013-02-04T20:07:32.480 回答
1

对我来说,onActivityCreated似乎或多或少是匹配阶段(此时已经可以调用findViewById父活动并设置组件/在片段实例中分配字段/设置(而不是添加)侦听器。我onActivityCreated的运行它超过一次不会造成任何伤害,并且Bundle会考虑传递的参数。

说到网络服务,你可能可以从任何地方调用,但你不能从 GUI 线程调用(Android 不允许)——所以创建你自己的 therad。当对 Web 服务的某些调用处于挂起状态时,您可能不需要支持片段和活动之间的完全切换;如果您确实需要,请使用savedInstanceState捆绑包保存并在请求时恢复状态。

于 2013-02-04T18:55:44.553 回答