更改旋转/方向后保持RecyclerView

时间:2018-07-08 21:30:57

标签: android android-studio android-fragments android-recyclerview screen-orientation

下午好,

我正在我的应用程序中使用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);
            }
        }
    }
}

非常感谢您和问候。

0 个答案:

没有答案