如何在异步任务完成后刷新片段中的列表视图?

时间:2019-01-25 15:35:04

标签: android android-fragments android-asynctask android-context

在应用程序启动时,主要活动是USNameFragment。该片段启动Asynctask,并在Asynctask完成后,将结果列表通过界面发送回片段。然后,Fragment在onDataRetrieved()中获取此列表,然后应显示此列表。

在USNameFragment onCreate()之后,片段列表视图为空。但是onDataRetrieved()中的Toast表示从Asynctask中检索了3个对象。

我确实找到了显示它的技巧,但是它不起作用。 列表项仅在更改配置(例如更改设备方向)后才显示在列表视图中,但在创建片段时不显示。

这是怎么了?感谢您的建议。

这是我在Fragment和AsyncTask之间进行通讯的界面:

public interface IActivityRef {

void onDataRetrieved(List<USDto> usDtos);
}

这是我的片段,它实现了IActivityRef接口:

public class USNameFragment extends Fragment
    implements IActivityRef {

private AsyncTask<String, Void, USResponse> usTask;
private WeakReference<IActivityRef> context;
private ListView listUSNames;
private List<String> usNames;

public USNameFragment() {
    // Required empty public constructor
    usNames = new ArrayList<>();
}

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    this.context = new WeakReference<>((IActivityRef) this);
}

@Override
public void onDetach() {
    super.onDetach();

    context = null;
}

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

    // Retain this fragment across configuration changes.
    setRetainInstance(true);

    usTask = new USTask(this);
    usTask = usTask.execute("params");
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    // Inflate the layout for this fragment
    View rootView = inflater.inflate(R.layout.fragment_us_name, container, false);

    listUSNames = rootView.findViewById(R.id.listUS);
    listUSNames.setAdapter(new ArrayAdapter<String>(
            getActivity(), R.layout.item_us_name, R.id.usName, usNames));

    return rootView;
}

@Override
public void onStop() {
    if (usTask != null && usTask.getStatus() == AsyncTask.Status.RUNNING) {
        usTask.cancel(true);
    }
    usTask = null;

    super.onStop();
}

@Override
public void onDataRetrieved(List<USDto> usDtos) {
    this.usNames = new USColumns().getUSNames(usDtos);
    Toast.makeText(getActivity(), "Data retrieved! List size = " + usDtos.size(),
            Toast.LENGTH_LONG).show();
}


}

这是Asynctask:

public class USTask extends AsyncTask<String, Void, USResponse> {

private WeakReference<IActivityRef> context;
private TwApiClient twApiClient;

public USTask(IActivityRef context) {

    this.context = new WeakReference<>(context);
}

@Override
protected void onPreExecute() {
    super.onPreExecute();
}

@Override
protected USResponse doInBackground(String... params) {

    // do http code here
}

@Override
protected void onPostExecute(USResponse usResponse) {
    super.onPostExecute(usResponse);

    if(context != null && usResponse != null) {
        IActivityRef activity = context.get();
        activity.onDataRetrieved(usResponse.getUS());
    }
}

@Override
protected void onProgressUpdate(Void... values) {
    super.onProgressUpdate(values);
}

}

编辑 认为片段布局是在onDataRetrieved()中检索列表之前创建的。也许应该刷新listview些什么?

EDIT2 问题在于刷新列表视图适配器,而不是从片段向asynctask发送上下文。

1 个答案:

答案 0 :(得分:0)

问题在于片段中的onDataRetrieved()中的asynctask完成后没有更新ListView适配器。

因此,解决方案是如此简单:

将此字段添加到USNameFragment:

private ArrayAdapter<String> listAdapter;

然后在onCreateView()中初始化此适配器并将其分配给listview:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    // Inflate the layout for this fragment
    View rootView = inflater.inflate(R.layout.fragment_us_name, container, false);

    listUSNames = rootView.findViewById(R.id.listUS);
    listAdapter = new ArrayAdapter<String>(
            getActivity(), R.layout.item_us_name, R.id.usName, usNames);
    listUSNames.setAdapter(listAdapter);

    return rootView;
}

然后在onDataRetrieved()中重新初始化此适配器:

@Override
public void onDataRetrieved(List<USDto> usDtos) {
    this.usNames = new USColumns().getUSNames(usDtos);
    listAdapter = new ArrayAdapter<String>(
            getActivity(), R.layout.item_us_name, R.id.usName, usNames);
    listUSNames.setAdapter(listAdapter);
}

还将asynctask的开始从USNameFragment中的onCreate()移到onAttach():

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    this.context = new WeakReference<>((IActivityRef) this);
    usTask = new USTask(this);
    usTask = usTask.execute("params");

}

就这样。