Как обновить просмотр списка во фрагменте после завершения асинхронной задачи? - PullRequest
0 голосов
/ 25 января 2019

Когда приложение запускается в основном действии USNameFragment. Этот фрагмент запускает Asynctask и после завершения Asynctask отправляет список результатов обратно фрагменту через интерфейс. Затем фрагмент возвращает этот список в onDataRetrieved () и затем должен отобразить этот список.

Hovewer после USNameFragment onCreate () просмотр списка фрагментов пуст. Но Toast в onDataRetrieved () говорит, что из 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);
}

}

EDIT Подумайте, макет фрагмента создан до получения списка в onDataRetrieved (). Может, стоит обновить список просмотра как-нибудь?

EDIT2 Проблема была в обновлении адаптера списка, а не в отправке контекста из фрагмента в asynctask.

1 Ответ

0 голосов
/ 25 января 2019

Проблема была в том, что не обновлялся адаптер ListView после завершения асинхронной задачи в onDataRetrieved () во фрагменте.

Таким образом, решение оказалось таким простым:

Добавьте это поле вUSNameFragment:

private ArrayAdapter<String> listAdapter;

Затем в onCreateView () инициализируйте этот адаптер и назначьте его списку просмотра:

@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 из onCreate () в onAttach () в USNameFragment:

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

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

}

И это все.

...