我在使用异步任务从加载程序返回一些数据时遇到了一些问题。
使用一些日志,我可以看到loadInBackground正在被调用,它调用修改来加载JSON,并退出调用deliverResult。问题是,当它退出时,加载还没有完成,所以它将一个空列表传递给deliverResult,我也得到了一个列表大小为0的onLoadFinished。
为什么不等待更新调用,然后用加载的数据调用deliverResult?
日志(最后一个是来自实际数据更新的响应,但此时它已经调用了deliverResult):
08-07 22:10:57.309 6872-6872/com.example.But匕首V/RAG: onCreateLoader() 08-07 22:10:57.315 6872-6872/com.example.But刀V/RAG: GetRecipeAsyncTask onStartLoading():
08-07 22:10:57.413 6872-6889/com.example.ButnieV/RAG: loadInBackground列表大小:0
08-07 22:10:58.533 6872-6872/com.example.ButnieV/RAG: deliverResult数据大小:0 onLoadFinished()数据大小:0
08-07 22:10:59.734 6872-6872
耽误您时间,实在对不起。
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);
}
}
}
}发布于 2018-08-08 00:50:10
从'call.enqueue()‘改为'call.execute.body()’。
问题是'enqueue‘异步执行请求,并在将来准备就绪时返回响应。当执行'loadInBackground‘时,它要求修改以执行请求,就这样,任务就完成了。
若要确保只在充分执行请求时退出任务,应使用“call.Execute.body”。通过这种方式,修改将同步执行您的请求,因此只有在您有响应时才能完成GetRecipeAsyncTask。
通常,您使用AsyncTask/AsyncTaskLoader执行同步操作()
这里有一些链接,第一个链接解释了使用改进的同步/异步请求之间的区别,第二个链接包含有关AsyncTask和AsyncTaskLoader的信息:
https://futurestud.io/tutorials/retrofit-synchronous-and-asynchronous-requests
https://stackoverflow.com/questions/51736270
复制相似问题