janishar / PlaceHolderView

This library provides advance views for lists and stacks. Some of the views are build on top of RecyclerView and others are written in their own. Annotations are compiled by annotation processor to generate bind classes. DOCS -->
http://janishar.com/PlaceHolderView
Apache License 2.0
2.11k stars 369 forks source link

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position #34

Closed abdullo211 closed 7 years ago

abdullo211 commented 7 years ago

when Placeholderview.removeallviews() crashed, I think its recyclers' bug, but how fix this?

janishar commented 7 years ago

@abdullo211 Let me test it. Can you post the stack trace?

abdullo211 commented 7 years ago

Ok, I’ll post stack. thank u for answer

abdullo211 commented 7 years ago

FATAL EXCEPTION: main Process: com.wienerdeming.distribution, PID: 4361 java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 0(offset:0).state:20 at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5504) at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5440) at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5436) at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2224) at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1551) at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1511) at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:595) at android.support.v7.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:3534) at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3310) at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3844) at android.view.View.layout(View.java:16630) at android.view.ViewGroup.layout(ViewGroup.java:5437) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586) at android.widget.LinearLayout.onLayout(LinearLayout.java:1495) at android.view.View.layout(View.java:16630) at android.view.ViewGroup.layout(ViewGroup.java:5437) at android.support.v4.widget.SwipeRefreshLayout.onLayout(SwipeRefreshLayout.java:636) at android.view.View.layout(View.java:16630) at android.view.ViewGroup.layout(ViewGroup.java:5437) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336) at android.widget.FrameLayout.onLayout(FrameLayout.java:273) at android.view.View.layout(View.java:16630) at android.view.ViewGroup.layout(ViewGroup.java:5437) at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1795) at android.view.View.layout(View.java:16630) at android.view.ViewGroup.layout(ViewGroup.java:5437) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586) at android.widget.LinearLayout.onLayout(LinearLayout.java:1495) at android.view.View.layout(View.java:16630) at android.view.ViewGroup.layout(ViewGroup.java:5437) at android.support.design.widget.CoordinatorLayout.layoutChild(CoordinatorLayout.java:1167) at android.support.design.widget.CoordinatorLayout.onLayoutChild(CoordinatorLayout.java:852) at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:871) at android.view.View.layout(View.java:16630) at android.view.ViewGroup.layout(ViewGroup.java:5437) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336) at android.widget.FrameLayout.onLayout(FrameLayout.java:273) at android.view.View.layout(View.java:16630) at android.view.ViewGroup.layout(ViewGroup.java:5437) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743) at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1732) at android.widget.LinearLayout.onLayout(LinearLayout.java:1497) at android.view.View.layout(View.java:16630) at android.view.ViewGroup.layout(ViewGroup.java:5437) at android.support.v4.widget.SlidingPaneLayout.onLayout(SlidingPaneLayout.java:725) at android.view.View.layout(View.java:16630) at android.view.ViewGroup.layout(ViewGroup.java:5437) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336) at android.widget.FrameLayout.onLayout(FrameLayout.java:273) at android.view.View.layout(View.java:16630) at android.view.ViewGroup.layout(ViewGroup.java:5437) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586) at android.widget.LinearLayout.onLayout(LinearLayout.java:1495) at android.view.View.layout(View.java:16630) at android.view.ViewGroup.layout(ViewGroup.java:5437) at android.widg

janishar commented 7 years ago

@abdullo211 I Tested but Placeholderview.removeAllViews() worked fine. Can you provide the code where you are using removeAllViews.

abdullo211 commented 7 years ago

public class MarketsListFragment extends BaseFragment implements LoadMoreListener {

@BindView(R.id.market_list_recycler_view)
InfinitePlaceHolderView placeHolderView;

@BindView(R.id.swipe_refresh_layout)
SwipeRefreshLayout swipeRefreshLayout;

@BindView(R.id.no_connection_layout)
LinearLayout connectionLayout;

@BindView(R.id.progress)
ProgressBar progressBar;

@BindView(R.id.no_data_layout)
LinearLayout noDataLayout;

private UserPrefs prefs;

private String query="";
private ArrayList<Market> marketList = new ArrayList<>();
private boolean isLoading = false;
private boolean isLast = false;
private int currentPage = 1;

Realm realm;

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

    View rootView = inflater.inflate(R.layout.fragment_market_list, null);
    prefs = new UserPrefs(getContext());
    ButterKnife.bind(this, rootView);
    realm=Realm.getDefaultInstance();
    initDetails();
    getMarketsFromServer("");
    return rootView;
}

@Override
public void onResume() {
    showHideConnectionLayout(checkConnection());
    super.onResume();
}

void refreshList() {
    showHideConnectionLayout(checkConnection());
    clearPlaceHolderData();
    placeHolderView.setLoadMoreResolver(new LoadMoreView(getContext(),this));
    query = "";
    getMarketsFromServer(query);
}

void clearPlaceHolderData() {
    marketList.clear();
    currentPage = 1;
    placeHolderView.removeAllViews();
}

private void initDetails() {
    placeHolderView.setLoadMoreResolver(new LoadMoreView(getContext(), this));

    swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);
    swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            swipeRefreshLayout.setRefreshing(false);
            refreshList();
        }
    });
}

private void getMarketsFromServer(String query) {

    showHideLoading(true);
    App.getMarket().getMarkets(getString(R.string.version_code), prefs.getAccessToken(), query, 20, currentPage).enqueue(new Callback<MarketsResponse>() {
        @Override
        public void onResponse(Call<MarketsResponse> call, Response<MarketsResponse> response) {

            if (response.isSuccessful()) {
                if (currentPage == 1) {
                    marketList.clear();
                }
                addViews(response.body().getMarketList());
                isLast = response.body().getNextPage() == null;

                currentPage++;
            } else {
                try {
                    Log.d("errorBody", response.errorBody().string());
                } catch (IOException e) {
                    e.printStackTrace();
                }
                checkToken(response);
                Toast.makeText(getContext(), getResources().getString(R.string.message_error_occurred), Toast.LENGTH_SHORT).show();
            }
            placeHolderView.loadingDone();
            showHideLoading(false);
        }

        @Override
        public void onFailure(Call<MarketsResponse> call, Throwable t) {
            t.printStackTrace();
            placeHolderView.loadingDone();
            showHideLoading(false);
            showHideConnectionLayout(currentPage == 1);

        }
    });

}

private void showHideLoading(boolean isLoading) {
    this.isLoading = isLoading;

    progressBar.setVisibility(isLoading && currentPage == 1 ? View.VISIBLE : View.GONE);
}

private void addViews(ArrayList<Market> markets) {
    marketList.addAll(markets);
    for (final Market market : markets) {
        placeHolderView.addView(new MarketListView(getActivity(), market));
        realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                realm.insertOrUpdate(market);
            }
        });
    }

    if (isLast) {
        placeHolderView.noMoreToLoad();
    }

    showHideNoDataLayout(marketList.isEmpty());
}

private void showHideConnectionLayout(boolean isConnected) {
    connectionLayout.setVisibility(isConnected ? View.GONE : View.VISIBLE);
}

private void showHideNoDataLayout(boolean isEmpty) {
    noDataLayout.setVisibility(isEmpty ? View.VISIBLE : View.GONE);
}

@Override
public void setString(final String text) {
    if (!checkConnection()) {

    } else {
        clearPlaceHolderData();
        query = text;
        getMarketsFromServer(query);
    }
    super.setString(text);
}

@Override
public void onLoadMore() {
    if (!isLoading) {
        getMarketsFromServer(query);
    }
}

@OnClick(R.id.reload_data)
void reload() {
    if (checkConnection()) {
        refreshList();
    }
}

}

abdullo211 commented 7 years ago

@Layout(R.layout.market_list_item) public class MarketListView {

@View(R.id.magazine_item_name)
private
AppCompatTextView name;

@View(R.id.magazine_item_address)
private
AppCompatTextView address;

@View(R.id.market_image)
private
AppCompatImageView image;

@Position
int parentPosition;

private Market market;
private Activity context;

public MarketListView(Activity context, Market market) {
    this.market = market;
    this.context = context;
}

@Resolve
void onResolve() {
    name.setText(market.getName());
    address.setText(market.getAddress());

    try {
        Picasso.with(context).load(market.getImages().get(0).getUrl()).centerCrop()
                .transform(new RoundedImageTransform()).fit().error(R.drawable.shop_icon).into(image);
    }catch (Exception ignored){
        Picasso.with(context).load(R.drawable.shop_icon).centerCrop()
                .transform(new RoundedImageTransform()).fit().into(image);
    }
}

@Click(R.id.magazine_item_main_layout)
void showMarket() {
    Intent intent = new Intent(context, MarketActivity.class);
    intent.putExtra(Constants.MARKET_ID, market.getId());
    intent.putExtra(Constants.MARKET_TITLE, market.getName());
    ActivityOptionsCompat options = ActivityOptionsCompat.
            makeSceneTransitionAnimation(context, image, "profile");
    context .startActivity (intent, options.toBundle());
}

}

janishar commented 7 years ago

What is the version of RecyclerView and PlaceHolderView you are using? I tried to replicate your code scene but error was not coming. It can be a bug in RecyclerView itself as you mentioned. Provide me the RecyclerView version to test it.

abdullo211 commented 7 years ago
compile 'com.mindorks:placeholderview:0.6.2' 
compile 'com.android.support:design:25.3.1'
compile 'com.android.support:appcompat-v7:25.3.1'
janishar commented 7 years ago

@abdullo211 I am not able to regenerate this issue. If your can find how and when it get reproduced then I would be able to look into it. Thanks

ltthuc1989 commented 7 years ago

Hi janishar! I have faced the same issue with my project! Process: com.ezyplanet.thousandhands, PID: 31853 java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 0(offset:32).state:46

ltthuc1989 commented 7 years ago

Hi @janishar ! i have known why this error happened . You may be have missed call notifyItemRangeRemoved(0, oldSize) in removeAllViewBinders() of ViewAdapter class. I have edited your function like this then error disappeared. +your function before edited: protected void removeAllViewBinders(){ for(ViewBinder<T, View> viewBinder : mViewBinderList){ viewBinder.unbind(); } mViewBinderList.clear(); } +your function after edited protected void removeAllViewBinders(){ for(ViewBinder<T, View> viewBinder : mViewBinderList){ viewBinder.unbind(); } int oldSize = mViewBinderList.size(); mViewBinderList.clear(); notifyItemRangeRemoved(0, oldSize); } Please update your library if you think I am right. Thanks

janishar commented 7 years ago

@ltthuc1989 Thank you for finding the bug, I will verify it and release a new version with the fix.

janishar commented 7 years ago

@abdullo211 @ltthuc1989 I have applied the fix please use 0.6.5 version.

compile 'com.mindorks:placeholderview:0.6.5'
ltthuc1989 commented 7 years ago

Thanks so much!quickly updating 👍

janishar commented 7 years ago

Thanks :) I am closing this issue now.

abdullo211 commented 7 years ago

Thanks 👍

tw-profiforms commented 7 years ago

Thanks

EMIN3M1986 commented 6 years ago

https://stackoverflow.com/a/47324896/4468776