下午好,
我正在我的应用程序中使用RecyclerView,该应用程序使用AsyncTaskLoader(十分之十)从API加载其数据(由于该API的局限性)。
一切正常,直到我将设备的方向从纵向更改为横向。 RecyclerView的内容将被删除,并且已被禁用,无法执行其他搜索(我已拍摄了图像,因此您知道我在说什么)。
在设备旋转后,我大惊小怪地发现,RecyclerView之前的数据负载得以维持,但即使如此,仍然无法进行更多搜索,这是不可接受的。< / p>
希望我能在我不顾一切的情况下为我提供帮助,希望找到一个解决方案,我已经阅读了几乎所有相关文章,并应用了我在StackOverflow和网络其他地方找到的一千个解决方案提案,不幸的是没有为我工作。
这是我在GitHub上的代码:https://github.com/maneletorres/SafeBitesV2
ProductsListLoader:
public class ProductsListLoader extends AsyncTaskLoader<List> {
/**
* Query URL.
*/
private final String url;
/**
* Constructs a new {@link ProductsListLoader}.
*
* @param context of the activity.
* @param url to load data from.
*/
public ProductsListLoader(Context context, String url) {
super(context);
this.url = url;
}
@Override
protected void onStartLoading() {
forceLoad();
}
/**
* This is on a background thread.
*/
@Override
public List<Product> loadInBackground() {
if (url == null) {
return null;
}
return QueryUtils.fetchProductsData(url);
}
SearchFragment:
package com.udacity.safebites.fragments;
import android.app.LoaderManager;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.AbsListView;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.squareup.picasso.Picasso;
import com.udacity.safebites.ProductActivity;
import com.udacity.safebites.R;
import com.udacity.safebites.entities.Product;
import com.udacity.safebites.loader.ProductsListLoader;
import com.udacity.safebites.utils.QueryUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class SearchFragment extends Fragment implements LoaderManager.LoaderCallbacks<List<Product>> {
/**
* Header URL of the API for all products from a specific search.
*/
private static final String header_search_url = "https://world.openfoodfacts.org/cgi/search.pl?search_terms=";
/**
* Tail URL of the API for all products from a specific search.
*/
private static final String tail_search_url = "&search_simple=1&action=process&json=1&page_size=10&page=";
/**
* Constant value for the product loader ID.
*/
private static final int PRODUCT_LOADER = 1;
/**
* Default query URL.
*/
private static String mDefaultQueryUrl;
/**
* Actual query URL.
*/
private static String mQueryUrl;
/**
* Current page for the subsequent extraction of JSON data.
*/
private static int mActualPage = 1;
/**
* EditText used to perform a search.
*/
private static EditText mSearchEditText;
/**
* Variable that controls if a new search is being performed or the loading of more data.
*/
private static boolean mNewSearch = true;
private final String RECYCLER_CONTENT = "recycler_content";
/**
* Product list.
*/
private List<Product> mProductsList = new ArrayList<>();
/**
* Product RecyclerView.
*/
private RecyclerView mRecyclerView;
/**
* Adapter for the RecyclerView.
*/
private SimpleItemRecyclerViewAdapter mSimpleItemRecyclerViewAdapter;
/**
* LinearLayoutManager associated with RecyclerView.
*/
private LinearLayoutManager mLinearLayoutManager;
/**
* TextView that is displayed when the list of products is empty.
*/
private TextView mEmptyTextView;
/**
* Pagination progress bar.
*/
private ProgressBar mPaginationProgressBar;
/**
* Search progress bar.
*/
private ProgressBar mSearchProgressBar;
/**
* Variable that controls if you are traveling through the RecyclerView.
*/
private boolean isScrolling;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.search_fragment, container, false);
mEmptyTextView = view.findViewById(R.id.empty_textView);
mSearchEditText = view.findViewById(R.id.search_edit_text);
mSearchEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
QueryUtils.hideSoftKeyboard(getActivity());
runSearch();
return true;
}
return false;
}
});
mPaginationProgressBar = view.findViewById(R.id.pagination_progress_bar);
mSearchProgressBar = view.findViewById(R.id.search_progress_bar);
mLinearLayoutManager = new LinearLayoutManager(getContext());
mSimpleItemRecyclerViewAdapter = new SimpleItemRecyclerViewAdapter(mProductsList);
mRecyclerView = view.findViewById(R.id.product_recycler);
mRecyclerView.setLayoutManager(mLinearLayoutManager);
mRecyclerView.setAdapter(mSimpleItemRecyclerViewAdapter);
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
isScrolling = true;
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int currentItems = mLinearLayoutManager.getChildCount();
int totalItems = mLinearLayoutManager.getItemCount();
int scrollOutItems = mLinearLayoutManager.findFirstVisibleItemPosition();
if (isScrolling && (currentItems + scrollOutItems == totalItems)) {
isScrolling = false;
double data_loads = Math.ceil(QueryUtils.getProducts_quantity() / QueryUtils.getPage_size() + 1);
if (mActualPage <= data_loads) {
mPaginationProgressBar.setVisibility(View.VISIBLE);
mNewSearch = true;
mQueryUrl = mDefaultQueryUrl + mActualPage++;
restartLoader();
}
}
}
});
return view;
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList(RECYCLER_CONTENT, new ArrayList<>(mSimpleItemRecyclerViewAdapter.getProducts()));
/*outState.putBoolean(NEW_SEARCH_STATE, mNewSearch);
outState.putInt(ACTUAL_PAGE_STATE, mActualPage);
outState.putBoolean(IS_SCROLLING_STATE, isScrolling);*/
}
@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
if (savedInstanceState != null) {
List<Product> products = savedInstanceState.getParcelableArrayList(RECYCLER_CONTENT);
if (products != null) {
mRecyclerView.setVisibility(View.VISIBLE);
mProductsList.addAll(products);
mSimpleItemRecyclerViewAdapter.notifyDataSetChanged();
mPaginationProgressBar.setVisibility(View.GONE);
/*mNewSearch = savedInstanceState.getBoolean(NEW_SEARCH_STATE);
mActualPage = savedInstanceState.getInt(ACTUAL_PAGE_STATE);
isScrolling = savedInstanceState.getBoolean(IS_SCROLLING_STATE);*/
}
}
}
@Override
public Loader<List<Product>> onCreateLoader(int id, Bundle args) {
if (!mNewSearch) {
mEmptyTextView.setVisibility(View.GONE);
mRecyclerView.setVisibility(View.GONE);
mSearchProgressBar.setVisibility(View.VISIBLE);
}
return new ProductsListLoader(getContext(), mQueryUrl);
}
@Override
public void onLoadFinished(Loader<List<Product>> loader, List<Product> products) {
if (products != null && !products.isEmpty() && isConnected()) {
mEmptyTextView.setVisibility(View.GONE);
mRecyclerView.setVisibility(View.VISIBLE);
if (!mNewSearch) {
mProductsList.clear();
}
mProductsList.addAll(products);
mSimpleItemRecyclerViewAdapter.notifyDataSetChanged();
mPaginationProgressBar.setVisibility(View.GONE);
} else if (isConnected() && products != null && products.isEmpty()) {
mRecyclerView.setVisibility(View.GONE);
mEmptyTextView.setVisibility(View.VISIBLE);
} else if (!isConnected()) {
mEmptyTextView.setText(R.string.no_internet_connection);
mEmptyTextView.setVisibility(View.VISIBLE);
}
mSearchProgressBar.setVisibility(View.GONE);
getActivity().getLoaderManager().destroyLoader(PRODUCT_LOADER);
}
@Override
public void onLoaderReset(Loader<List<Product>> loader) {
mQueryUrl = null;
mActualPage = 1;
}
public void restartLoader() {
getActivity().getLoaderManager().restartLoader(PRODUCT_LOADER, null, this);
}
private void runSearch() {
if (mSearchEditText != null) {
String search_text = mSearchEditText.getText().toString();
if (search_text.length() > 0) {
mActualPage = 1;
mDefaultQueryUrl = header_search_url + search_text + tail_search_url;
mQueryUrl = mDefaultQueryUrl + mActualPage++;
if (mNewSearch) {
mNewSearch = false;
getActivity().getLoaderManager().initLoader(PRODUCT_LOADER, null, this);
} else {
getActivity().getLoaderManager().restartLoader(PRODUCT_LOADER, null, this);
}
} else {
Toast.makeText(getContext(), getResources().getString(R.string.search_request), Toast.LENGTH_SHORT).show();
}
}
}
private boolean isConnected() {
ConnectivityManager connMgr = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
assert connMgr != null;
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
LoaderManager loaderManager = getActivity().getLoaderManager();
loaderManager.restartLoader(PRODUCT_LOADER, null, this);
} else {
mEmptyTextView.setText(R.string.no_internet_connection);
}
return networkInfo != null && networkInfo.isConnectedOrConnecting();
}
public static class SimpleItemRecyclerViewAdapter
extends RecyclerView.Adapter<SimpleItemRecyclerViewAdapter.ViewHolder> {
private final List<Product> products;
private final View.OnClickListener mOnClickListener;
private Context context;
{
mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
Product currentProduct = (Product) view.getTag();
context = view.getContext();
Intent intent = new Intent(context, ProductActivity.class);
intent.putExtra("product", (Serializable) currentProduct);
intent.putExtra("isFavorite", isFavorite(currentProduct, view.getContext()));
context.startActivity(intent);
}
};
}
SimpleItemRecyclerViewAdapter(List<Product> products) {
this.products = products;
}
public static boolean isFavorite(Product product, Context context) {
List<Product> favoritesProducts = FavoriteProductsFragment.loadFavoritesProducts(context);
boolean condition = false;
for (int i = 0; i < favoritesProducts.size() && !condition; i++) {
Product currentProduct = favoritesProducts.get(i);
if (currentProduct.getName().equals(product.getName())) {
condition = true;
}
}
return condition;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.products_list_item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
final Product currentProduct = products.get(position);
String image_resource = currentProduct.getImage_resource();
if (image_resource.equals("?")) {
Picasso.get().load(R.drawable.no_image_available).into(holder.product_image_view);
} else {
Picasso.get().load(image_resource).into(holder.product_image_view);
}
holder.product_name.setText(currentProduct.getName());
holder.product_extra_information.setText(currentProduct.getUpc());
holder.itemView.setTag(currentProduct);
holder.itemView.setOnClickListener(mOnClickListener);
final String favorite_condition = currentProduct.getFavorite_condition();
if (favorite_condition.equals("true")) {
holder.favorite_condition_image_button.setImageResource(R.drawable.delete);
holder.favorite_condition_image_button.setContentDescription("Delete ImageButton");
}
holder.favorite_condition_image_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (favorite_condition.equals("false")) {
QueryUtils.saveProduct(currentProduct, v.getContext());
FavoriteProductsFragment.loadFavoritesProducts(v.getContext());
} else if (favorite_condition.equals("true")) {
QueryUtils.deleteProduct(currentProduct, v.getContext());
FavoriteProductsFragment.loadFavoritesProducts(v.getContext());
}
}
});
}
public List<Product> getProducts() {
return products;
}
@Override
public int getItemCount() {
return products.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
final ImageView product_image_view;
final TextView product_name;
final TextView product_extra_information;
final ImageButton favorite_condition_image_button;
ViewHolder(View view) {
super(view);
product_image_view = view.findViewById(R.id.product_image);
product_name = view.findViewById(R.id.product_name);
product_extra_information = view.findViewById(R.id.product_extra_information);
favorite_condition_image_button = view.findViewById(R.id.favorite_condition_image_button);
}
}
}
}
非常感谢您和问候。