最近我将recyclerview-v7:23
升级为recyclerview-v7:24.2.0
。我的应用程序有一个无尽的滚动列表。当我将加载视图添加到notifyItemInserted
时,错误消息指向行RecyclerView
(null对象表示加载,id 0为空,-1表示页面结束)并且之前工作正常(recyclerview) -v7:23)但突然间我得到了这样的错误,不知怎的,我的加载出现了两次然后当它移除了一个时,顶部仍然可以看到一个加载。
W/RecyclerView: Cannot call this method in a scroll callback. Scroll callbacks might be run during a measure & layout pass where you cannot change the RecyclerView data. Any method call that might change the structure of the RecyclerView or the adapter contents should be postponed to the next frame.java.lang.IllegalStateException:
at android.support.v7.widget.RecyclerView.assertNotInLayoutOrScroll(RecyclerView.java:2403)
at android.support.v7.widget.RecyclerView$RecyclerViewDataObserver.onItemRangeInserted(RecyclerView.java:4631)
at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyItemRangeInserted(RecyclerView.java:10469)
at android.support.v7.widget.RecyclerView$Adapter.notifyItemInserted(RecyclerView.java:6211)
at com.sketchproject.infogue.fragments.MessageFragment.loadMessages(MessageFragment.java:109)
at com.sketchproject.infogue.fragments.MessageFragment.access$100(MessageFragment.java:42)
at com.sketchproject.infogue.fragments.MessageFragment$1.onLoadMore(MessageFragment.java:87)
at com.sketchproject.infogue.modules.EndlessRecyclerViewScrollListener.onScrolled(EndlessRecyclerViewScrollListener.java:74)
当我删除部分错误(添加加载)时,它再次正常工作,我不知道为什么,更新版本的recyclerview会阻止将数据添加到适配器中太快,或者是否存在“measure& amp”时触发的回调函数; recyclerview的“布局”已完成,这是我的代码
private void loadArticles(final int page) {
if (!isEndOfPage && apiArticleUrl != null) {
if (swipeRefreshLayout == null || !swipeRefreshLayout.isRefreshing()) {
allArticles.add(null);
articleAdapter.notifyItemInserted(allArticles.size() - 1); // error here
}
JsonObjectRequest articleRequest = new JsonObjectRequest(Request.Method.GET, apiArticleUrl, null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
String status = response.getString("status");
JSONObject articles = response.getJSONObject("articles");
String nextUrl = articles.getString("next_page_url");
int currentPage = articles.getInt("current_page");
int lastPage = articles.getInt("last_page");
JSONArray data = articles.optJSONArray("data");
apiArticleUrl = nextUrl;
if (status.equals(APIBuilder.REQUEST_SUCCESS)) {
if (swipeRefreshLayout == null || !swipeRefreshLayout.isRefreshing()) {
allArticles.remove(allArticles.size() - 1);
articleAdapter.notifyItemRemoved(allArticles.size());
} else {
swipeRefreshLayout.setRefreshing(false);
int total = allArticles.size();
for (int i = 0; i < total; i++) {
allArticles.remove(0);
}
articleAdapter.notifyItemRangeRemoved(0, total);
}
List<Article> moreArticles = new ArrayList<>();
if (data != null) {
for (int i = 0; i < data.length(); i++) {
JSONObject articleData = data.getJSONObject(i);
Article article = new Article();
article.setId(articleData.getInt(Article.ID));
article.setSlug(articleData.getString(Article.SLUG));
article.setTitle(articleData.getString(Article.TITLE));
article.setFeatured(articleData.getString(Article.FEATURED_REF));
article.setCategoryId(articleData.getInt(Article.CATEGORY_ID));
article.setCategory(articleData.getString(Article.CATEGORY));
article.setSubcategoryId(articleData.getInt(Article.SUBCATEGORY_ID));
article.setSubcategory(articleData.getString(Article.SUBCATEGORY));
article.setContent(articleData.getString(Article.CONTENT));
article.setContentUpdate(articleData.getString(Article.CONTENT_UPDATE));
article.setPublishedAt(articleData.getString(Article.PUBLISHED_AT));
article.setView(articleData.getInt(Article.VIEW));
article.setRating(articleData.getInt(Article.RATING_TOTAL));
article.setStatus(articleData.getString(Article.STATUS));
moreArticles.add(article);
}
}
int curSize = articleAdapter.getItemCount();
allArticles.addAll(moreArticles);
if (allArticles.size() <= 0) {
Log.i("INFOGUE/Article", "Empty on page " + page);
isEndOfPage = true;
Article emptyArticle = new Article(0, null, "Empty page");
allArticles.add(emptyArticle);
} else if (currentPage >= lastPage) {
Log.i("INFOGUE/Article", "End on page " + page);
isEndOfPage = true;
Article endArticle = new Article(-1, null, "End of page");
allArticles.add(endArticle);
}
articleAdapter.notifyItemRangeInserted(curSize, allArticles.size() - 1);
} else {
Log.i("INFOGUE/Article", "Error on page " + page);
Helper.toastColor(getContext(), R.string.error_unknown, R.color.color_warning_transparent);
isEndOfPage = true;
Article failureArticle = new Article();
failureArticle.setId(-2);
failureArticle.setTitle(getString(R.string.error_unknown));
allArticles.add(failureArticle);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
if (swipeRefreshLayout != null && swipeRefreshLayout.isRefreshing()) {
swipeRefreshLayout.setRefreshing(false);
}
// remove last loading
allArticles.remove(allArticles.size() - 1);
articleAdapter.notifyItemRemoved(allArticles.size());
String errorMessage = getString(R.string.error_unknown);
NetworkResponse networkResponse = error.networkResponse;
if (networkResponse == null) {
if (error.getClass().equals(TimeoutError.class)) {
errorMessage = getString(R.string.error_timeout);
} else if (error.getClass().equals(NoConnectionError.class)) {
errorMessage = getString(R.string.error_no_connection);
}
} else {
if (networkResponse.statusCode == 404) {
errorMessage = getString(R.string.error_not_found);
} else if (networkResponse.statusCode == 500) {
errorMessage = getString(R.string.error_server);
} else if (networkResponse.statusCode == 503) {
errorMessage = getString(R.string.error_maintenance);
}
}
Helper.toastColor(getContext(), errorMessage, R.color.color_danger_transparent);
// add error view holder
isEndOfPage = true;
Article errorArticle = new Article();
errorArticle.setId(-2);
errorArticle.setTitle(errorMessage);
allArticles.add(errorArticle);
}
}
);
articleRequest.setTag("articles");
articleRequest.setRetryPolicy(new DefaultRetryPolicy(
APIBuilder.TIMEOUT_SHORT,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
VolleySingleton.getInstance(getContext()).addToRequestQueue(articleRequest);
}
}
该代码是从onCreate方法
调用的 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_article_list, container, false);
// Set the adapter
if (view instanceof RecyclerView) {
Context context = view.getContext();
recyclerView = (RecyclerView) view;
// determine column of list
LinearLayoutManager linearLayoutManager;
if (mColumnCount <= 1) {
linearLayoutManager = new LinearLayoutManager(context);
} else {
linearLayoutManager = new GridLayoutManager(context, mColumnCount);
}
// if article list authored by logged user then prefer editable view holder
if (mMyArticle) {
articleAdapter = new ArticleRecyclerViewAdapter(allArticles, mArticleListListener, mArticleEditableListener);
} else {
articleAdapter = new ArticleRecyclerViewAdapter(allArticles, mArticleListListener, hasHeader);
}
// set the adapter and attach custom scroll listener that triggered onLoadMore() and onReachTop()
recyclerView.setAdapter(articleAdapter);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.addOnScrollListener(new EndlessRecyclerViewScrollListener(linearLayoutManager) {
@Override
public void onLoadMore(final int page, int totalItemsCount) {
if (!isFirstCall) {
loadArticles(page);
}
}
@Override
public void onReachTop(boolean isFirst) {
// activate swipe function when list reach top only, find out where do fragment attached
if (getActivity() instanceof ArticleActivity) {
((ArticleActivity) getActivity()).setSwipeEnable(isFirst);
} else if (getActivity() instanceof ApplicationActivity) {
((ApplicationActivity) getActivity()).setSwipeEnable(isFirst);
}
}
});
if (isFirstCall) {
isFirstCall = false;
loadArticles(0);
}
}
return view;
}
我的问题是:
RecyclerView
的新版本? notifyItemInserted
是不对的?它以前工作过。更新
when I logged the code inside first call and scroll,
09-12 03:49:10.078 7046-7046/com.sketchproject.infogue I/Infogue/Contributor: Followers URL http://192.168.43.141:8000/api/contributor/support/followers?contributor_id=1
09-12 03:49:26.421 7046-7046/com.sketchproject.infogue I/Infogue/Contributor: Followers first call
09-12 03:49:26.421 7046-7046/com.sketchproject.infogue I/Infogue/Contributor: Followers URL http://192.168.43.141:8000/api/contributor/support/followers?contributor_id=1
09-12 03:49:26.617 7046-7046/com.sketchproject.infogue I/Infogue/Contributor: Followers second call (scroll)
09-12 03:49:26.618 7046-7046/com.sketchproject.infogue I/Infogue/Contributor: Followers URL http://192.168.43.141:8000/api/contributor/support/followers?contributor_id=1
09-12 03:49:27.365 7046-7046/com.sketchproject.infogue I/Infogue/Contributor: Followers second call (scroll)
第一次加载时,它们被调用两次,第一次调用后添加加载视图以某种方式触发滚动并再次调用。
答案 0 :(得分:95)
您也可以使用视图发布。
recyclerView.post(new Runnable() {
public void run() {
articleAdapter.notifyItemInserted(allArticles.size() - 1);
}
});
答案 1 :(得分:31)
2&amp; 3.您在设置时无法更改项目(通过调用onBindViewHolder)。在这种情况下,您必须通过调用Handler.post()
在当前循环结束时调用notifyItemInsertedHandler handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
articleAdapter.notifyItemInserted(allArticles.size() - 1);
}
};
handler.post(r);
我希望,它能解决你的问题。
答案 2 :(得分:3)
您还可以使用Google Play服务的Tasks API
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets:[ 'es2015', 'react', 'stage-2' ]
}
}
]
}
答案 3 :(得分:0)
在某些情况下,onScrollStateChanged可能就足够了
override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
adapter.notifyDataSetChanged()
}