loadInBackground在改造响应之前完成

时间:2018-08-07 22:26:27

标签: android retrofit

使用asynctask从加载程序返回一些数据时遇到麻烦。

使用一些日志,我可以看到loadInBackground正在被调用,它调用了改造以加载JSON,并退出了调用liverResult。关键是当它退出时,负载尚未完成,因此它将空列表传递给deliveryResult,我也得到了一个onLoadFinished,列表大小为0。

为什么它不等待改造调用,然后用加载的数据调用liverResult?

日志(最后一个是对实际数据进行改造后得到的响应,但此时它已称为deliveryResult):

08-07 22:10:57.309 6872-6872 / com.example.butterknife V / RAG:onCreateLoader() 08-07 22:10:57.315 6872-6872 / com.example.butterknife V / RAG:GetRecipeAsyncTask onStartLoading():

08-07 22:10:57.413 6872-6889 / com.example.butterknife V / RAG:loadInBackground列表大小:0

08-07 22:10:58.533 6872-6872 / com.example.butterknife V / RAG:deliverResult数据大小:0     onLoadFinished()数据大小:0

08-07 22:10:59.734 6872-6872 / com.example.butterknife V / RAG:改造成功内的loadInBackground成功():4

感谢您的时间。

github在这里:https://github.com/rag-lab/ButterKnifeLab

具有全部功能的片段:

package com.example.rodrigoaugusto.butterknife;

import android.content.Context;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


import java.util.ArrayList;
import java.util.List;
import java.util.zip.Inflater;

import butterknife.BindView;
import butterknife.ButterKnife;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class FragmentRecipe extends Fragment implements android.support.v4.app.LoaderManager.LoaderCallbacks<List<Recipes>>{

    View v;
    private RecyclerView myrecview;
    private List<Recipes> lstRecipes = new ArrayList<>();
    private static final int thumbLoaderID= 22;
    private Bundle queryBundle = new Bundle(); //usado no loader das recipes
    private static final String SEARCH_URL = ""; //chave do bundle

    //@BindView(R.id.listRecipes_recView) RecyclerView myrecview;


    public FragmentRecipe() {
    }


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

        //ButterKnife.bind(container);

        v = inflater.inflate(R.layout.fragment_listrecipe, container, false);

        myrecview = (RecyclerView) v.findViewById(R.id.listRecipes_recView);

        Recipe_RV_Adapter listRecipe_recViewAdapter = new Recipe_RV_Adapter(container.getContext(),lstRecipes);

        myrecview.setLayoutManager(new LinearLayoutManager(getActivity()));
        myrecview.setAdapter(listRecipe_recViewAdapter);

        return v;

    }


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        LoaderManager loaderManager = getLoaderManager();
        Loader<String> thumbsLoader = loaderManager.getLoader(thumbLoaderID);

        queryBundle.putString(SEARCH_URL, Api.BASEURL);

        if (thumbsLoader == null) {
            loaderManager.initLoader(thumbLoaderID, queryBundle, this);
        } else {
            loaderManager.restartLoader(thumbLoaderID, queryBundle, this);
        }


    }


    /* method not being used*/
    private void getRecipes() {

        /*
        Steps stepItem = new Steps("12", "short desc", "description", "videourl", "thumbUrl");
        Steps[] stepItens = {stepItem,stepItem};

        Ingredients ingredient = new Ingredients("measure", "ingredient", "qtd");
        Ingredients[] ingredients = {ingredient,ingredient};


        lstRecipes.add(new Recipes("id","servings","name1","image", stepItens, ingredients));
        lstRecipes.add(new Recipes("id","servings","name2","image", stepItens, ingredients));
        lstRecipes.add(new Recipes("id","servings","name3","image", stepItens, ingredients));
        */

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Api.BASEURL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        Api api = retrofit.create(Api.class);

        Call<List<Recipes>> call = api.getRecipes();
        call.enqueue(new Callback<List<Recipes>>() {

            @Override
            public void onResponse(Call<List<Recipes>> call, Response<List<Recipes>> response) {

                //Snackbar snackbar = Snackbar
                //      .make(layout, "success", Snackbar.LENGTH_LONG);
                //snackbar.show();
                //lstRecipes = response.body();

                List<Recipes> recipes = response.body();

                for(Recipes r: recipes){

                    Recipes tmp = new Recipes(r.getId(), r.getServings(), r.getName(), r.getImage(), r.getSteps(), r.getIngredients());
                    lstRecipes.add(tmp);
                }

            }

            @Override
            public void onFailure(Call<List<Recipes>> call, Throwable t) {

                Log.v("RAG", "erro:"+t.toString());

                /*
                Snackbar snackbar = Snackbar
                        .make(layout, t.getMessage(), Snackbar.LENGTH_LONG);
                snackbar.show();
                */
            }

        });

    }


    //
    //LOADER
    //
    @Override
    public Loader<List<Recipes>> onCreateLoader(int id, final Bundle args) {

        Log.v("RAG", "onCreateLoader()");
        return new GetRecipeAsyncTask(getContext());

    }

    @Override
    public void onLoadFinished(Loader<List<Recipes>> loader, List<Recipes> data) {

        Log.v("RAG", "onLoadFinished() data size:" + data.size());
    }


    @Override
    public void onLoaderReset(Loader<List<Recipes>> loader) {
        //Log.v("RAG", "onLoaderReset()");
    }


    /*
    //END LOADER
    */



    static class GetRecipeAsyncTask extends AsyncTaskLoader<List<Recipes>>
    {

        List<Recipes> tmpLstRecipes;

        public GetRecipeAsyncTask(Context context) {
            super(context);
        }


        @Override
        protected void onStartLoading() {

            /*
            super.onStartLoading();
            forceLoad();
            */

            //if (args == null) return;
            Log.v("RAG", "GetRecipeAsyncTask onStartLoading():");

            //pega do cache ou carrega
            if (tmpLstRecipes != null) {
                deliverResult(tmpLstRecipes);
            } else {
                this.forceLoad();
            }

        }


        @Override
        public List<Recipes> loadInBackground() {

            tmpLstRecipes = new ArrayList<>();

            try {

                Retrofit retrofit = new Retrofit.Builder()
                        .baseUrl(Api.BASEURL)
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();

                Api api = retrofit.create(Api.class);

                Call<List<Recipes>> call = api.getRecipes();
                call.enqueue(new Callback<List<Recipes>>() {

                    @Override
                    public void onResponse(Call<List<Recipes>> call, Response<List<Recipes>> response) {

                        //Snackbar snackbar = Snackbar
                        //      .make(layout, "success", Snackbar.LENGTH_LONG);
                        //snackbar.show();
                        //lstRecipes = response.body();

                        List<Recipes> recipes = response.body();

                        for(Recipes r: recipes){
                            Recipes tmp = new Recipes(r.getId(), r.getServings(), r.getName(), r.getImage(), r.getSteps(), r.getIngredients());
                            tmpLstRecipes.add(tmp);
                        }

                        Log.v("RAG", "loadInBackground inside retrofit success():"+ tmpLstRecipes.size());

                    }

                    @Override
                    public void onFailure(Call<List<Recipes>> call, Throwable t) {

                        Log.v("RAG", "loadInBackground onFailure():"+ t.toString());
                        /*
                        Snackbar snackbar = Snackbar
                                .make(layout, t.getMessage(), Snackbar.LENGTH_LONG);
                        snackbar.show();
                        */
                    }

                });


            } catch (Exception e) {
                e.printStackTrace();
            }

            Log.v("RAG", "loadInBackground list size:"+tmpLstRecipes.size());

            return tmpLstRecipes;
        }



        @Override
        public void deliverResult(List<Recipes> data) {

            Log.v("RAG", "deliverResult data size:"+data.size());


            // Hold a reference to the old data so it doesn't get garbage collected.
            // We must protect it until the new data has been delivered.
            List<Recipes> oldData = tmpLstRecipes;
            tmpLstRecipes = data;

            if (isStarted()) {
                // If the Loader is in a started state, deliver the results to the
                // client. The superclass method does this for us.
                super.deliverResult(data);
            }

            // Invalidate the old data as we don't need it any more.
            if (oldData != null && oldData != data) {
                //releaseResources(oldData);
            }

        }

    }

}

1 个答案:

答案 0 :(得分:0)

从“ call.enqueue()”更改为“ call.execute.body()”。

问题是“入队”异步执行请求,并在将来准备就绪时返回响应。当执行“ loadInBackground”时,它要求改型执行一个请求,仅此而已,任务就完成了。

为确保仅在完全执行请求后退出任务,应使用“ call.execute.body”。这样,改造将同步执行您的请求,因此GetRecipeAsyncTask仅在您有响应时完成。

通常,您使用AsyncTask / AsyncTaskLoader执行同步操作异步

这里有一些链接,第一个解释了使用改进的同步/异步请求之间的区别,第二个包含了有关AsyncTask和AsyncTaskLoader的信息:

https://futurestud.io/tutorials/retrofit-synchronous-and-asynchronous-requests

https://google-developer-training.gitbooks.io/android-developer-fundamentals-course-concepts/content/en/Unit%203/71c_asynctask_and_asynctaskloader_md.html