You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Jan 10, 2025. It is now read-only.
Well, your solution is effective, but if I removed the Header in List(just PagedList+Footer),the list still automatically scrolled to the end of the loaded page when I refresh recyclerView successfully.
My answer is that add an empty layout header on top of RecyclerView which can't be seen by user(for example, layout_height = 0.1dp) as static placeholder. the issue was solved but it's not elegant solution in my opinion. 😢
This code part just explain how to set up Header, but same to Footer.
Emm....in principle, this approach is no different from yours. the difference is just where we deceive the RecyclerView to handle the update position range.😂
Hey guys @qingmei2@onlymash , I am still having this problem too and I don't know how to solve it. I fix one part but then I break another.
I have this adapter with this three ViewHolders:
class HomeAdapter @Inject
constructor(val sessionRepository: SessionRepository) :
PagedListAdapter<HomeItem, RecyclerView.ViewHolder>(userDiffCallback) {
private var networkState: NetworkState? = null
private var retryCallback: RetryCallback? = null
lateinit var recommendedAdapter: RecommendedAdapter
var feedJobListener: JobsViewHolder.Listener? = null
var questionListener: QuestionsViewHolder.Listener? = null
fun setRetryCallback(retryCallback: RetryCallback) {
this.retryCallback = retryCallback
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
R.layout.item_question -> QuestionsViewHolder.create(
parent,
sessionRepository,
questionListener
)
R.layout.view_network_state -> NetworkStateViewHolder.create(
parent,
retryCallback
)
R.layout.item_list_recommended -> RecommendedViewHolder.create(parent)
R.layout.item_feed_job -> JobFeedViewHolder.create(
parent,
feedJobListener,
sessionRepository.isLoggedUserJobSeeker()
)
else -> throw IllegalArgumentException("unknown view type")
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (getItemViewType(position)) {
R.layout.item_question -> (holder as QuestionsViewHolder)
.bindTo(getItem(position) as QuestionResponse)
R.layout.view_network_state -> (holder as NetworkStateViewHolder)
.bindTo(networkState)
R.layout.item_list_recommended -> (holder as RecommendedViewHolder)
.bindTo(getItem(position) as Recommended?, recommendedAdapter)
R.layout.item_feed_job -> (holder as JobFeedViewHolder)
.bindTo(position, getItem(position) as JobResponse)
}
}
private fun hasExtraRow(): Boolean {
return networkState != null && networkState != NetworkState.LOADED
}
override fun getItemViewType(position: Int): Int {
return if (hasExtraRow() && position == itemCount - 1) {
R.layout.view_network_state
} else if (position == 0) {
R.layout.item_list_recommended
} else if (getItem(position) is QuestionResponse) {
R.layout.item_question
} else
R.layout.item_feed_job
}
override fun getItemCount(): Int {
return super.getItemCount() + if (hasExtraRow()) 1 else 0
}
fun setNetworkState(newNetworkState: NetworkState?) {
val previousState = this.networkState
val hadExtraRow = hasExtraRow()
this.networkState = newNetworkState
val hasExtraRow = hasExtraRow()
if (hadExtraRow != hasExtraRow) {
if (hadExtraRow) {
notifyItemRemoved(super.getItemCount())
} else {
notifyItemInserted(super.getItemCount())
}
} else if (hasExtraRow && previousState !== newNetworkState) {
notifyItemChanged(itemCount - 1)
}
}
companion object {
private val userDiffCallback = object : DiffUtil.ItemCallback<HomeItem>() {
override fun areItemsTheSame(oldItem: HomeItem, newItem: HomeItem): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: HomeItem, newItem: HomeItem): Boolean {
return oldItem == newItem
}
}
}
}
If I add this lines to the adapter (the fix from qingmei2), the problem is fixed but I have a problem with the swipe refresh:
override fun registerAdapterDataObserver(observer: RecyclerView.AdapterDataObserver) {
super.registerAdapterDataObserver(AdapterDataObserverProxy(observer, 1))
}
When I swipe to refresh I get this:
2019-04-03 09:17:41.114 501-501/com.myapp.android E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.myapp.android, PID: 501
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{66c78b1 position=0 id=-1, oldPos=0, pLpos:-1 scrap [attachedScrap] tmpDetached no parent} androidx.recyclerview.widget.RecyclerView{f2f2c58 VFED.V... ......I. 0,0-1080,1665 #7f0a0198 app:id/list_main}, adapter:com.myapp.android.features.home.home.adapter.HomeAdapter@8e1e0b6, layout:androidx.recyclerview.widget.LinearLayoutManager@d6851b7, context:com.myapp.android.features.home.HomeActivity@b27dc41
at androidx.recyclerview.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:5715)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5898)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5858)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5854)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2230)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1557)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1517)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:612)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:3875)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3639)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4194)
at android.view.View.layout(View.java:20836)
at android.view.ViewGroup.layout(ViewGroup.java:6401)
at androidx.swiperefreshlayout.widget.SwipeRefreshLayout.onLayout(SwipeRefreshLayout.java:625)
at android.view.View.layout(View.java:20836)
at android.view.ViewGroup.layout(ViewGroup.java:6401)
at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1080)
at android.view.View.layout(View.java:20836)
at android.view.ViewGroup.layout(ViewGroup.java:6401)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20836)
at android.view.ViewGroup.layout(ViewGroup.java:6401)
at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1915)
at android.view.View.layout(View.java:20836)
at android.view.ViewGroup.layout(ViewGroup.java:6401)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20836)
at android.view.ViewGroup.layout(ViewGroup.java:6401)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1791)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1635)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1544)
at android.view.View.layout(View.java:20836)
at android.view.ViewGroup.layout(ViewGroup.java:6401)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20836)
at android.view.ViewGroup.layout(ViewGroup.java:6401)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1791)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1635)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1544)
at android.view.View.layout(View.java:20836)
at android.view.ViewGroup.layout(ViewGroup.java:6401)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at com.android.internal.policy.DecorView.onLayout(DecorView.java:944)
at android.view.View.layout(View.java:20836)
at android.view.ViewGroup.layout(ViewGroup.java:6401)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2948)
2019-04-03 09:17:41.115 501-501/com.myapp.android E/AndroidRuntime: at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2635)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1779)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7810)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
at android.view.Choreographer.doCallbacks(Choreographer.java:723)
at android.view.Choreographer.doFrame(Choreographer.java:658)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6938)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
I have read your code but not know clearly where was error...
I found the codes' logic is managing a dynamic row as Footer in the list, have you try make this row as static instead of dynamic managing this row added or removed( just control it Visibility or Gone)?
Maybe it is not best solution but I think it simplify the logic at least, and I always know the number of item's count:
overridefunonBindViewHolder(holder:RecyclerView.ViewHolder, position:Int) {
when (holder) {
isHeaderViewHolder-> holder.bindsHeader() // headerisFooterViewHolder-> holder.bindsFooter() // footer isStudentViewHolder-> holder.bindTo(getStudentItem(position)) // main list
}
}
privatefungetStudentItem(position:Int): Student? {
return getItem(position -1) // position = 1 means fetch first(position 0) student in pagedList.
}
overridefungetItemCount(): Int {
returnsuper.getItemCount() +2// +2 means static header and static footer
}
//callback.onResult(this, null, 2) move it after code of `networkState changed`
networkState.postValue(NetworkState.LOADED)
initialLoad.postValue(NetworkState.LOADED)
callback.onResult(this, null, 2)
I think I had the same issue and solved it by removing all "networkState.postValue()" calls from the "loadInitial()" function. Additionally this gets rid of the overlaying loading indicators.
Activity
onlymash commentedon Feb 6, 2019
Same issue is here
PostAdapter
onlymash commentedon Feb 7, 2019
I have solved my issue like this
qingmei2 commentedon Apr 2, 2019
@onlymash
Well, your solution is effective, but if I removed the Header in List(just PagedList+Footer),the list still automatically scrolled to the end of the loaded page when I refresh recyclerView successfully.
My answer is that add an empty layout header on top of RecyclerView which can't be seen by user(for example, layout_height = 0.1dp) as static placeholder. the issue was solved but it's not elegant solution in my opinion. 😢
onlymash commentedon Apr 2, 2019
@qingmei2
So your header won't scroll, the list won't be full screen
qingmei2 commentedon Apr 2, 2019
@onlymash
I am sorry for I did not explain clearly.
exactly, no, I implement a multi type PagedList with Header and Footer.
finally I was able to build it according to this post⬇️:
Android RecyclerView + Paging Library 添加头部刷新会自动滚动的问题分析及解决
Briefly summarize,the post author create a proxy class:
and override the
PagedListAdapter.registerAdapterDataObserver()
method:This code part just explain how to set up Header, but same to Footer.
Emm....in principle, this approach is no different from yours. the difference is just where we deceive the RecyclerView to handle the update position range.😂
the demo code at here(Both header and footer).
lucandr commentedon Apr 3, 2019
Hey guys @qingmei2 @onlymash , I am still having this problem too and I don't know how to solve it. I fix one part but then I break another.
I have this adapter with this three ViewHolders:
If I add this lines to the adapter (the fix from qingmei2), the problem is fixed but I have a problem with the swipe refresh:
When I swipe to refresh I get this:
How can I solve this?
qingmei2 commentedon Apr 4, 2019
hi, @lucandr :)
I have read your code but not know clearly where was error...
I found the codes' logic is managing a dynamic row as Footer in the list, have you try make this row as static instead of dynamic managing this row added or removed( just control it Visibility or Gone)?
Maybe it is not best solution but I think it simplify the logic at least, and I always know the number of item's count:
see detail here :)
"just control it Visibility or Gone" maybe like this:
Can this solve your issue? or you can try to describe your problem in detail. :)
lucandr commentedon Apr 15, 2019
@qingmei2 can u watch the video that I posted on the first post and try to run the code of this repo?
Repo
Video
parcool commentedon Aug 12, 2019
I got this issue too and is there any perfect way to fix it? Is it a big bug to so hard to do?
parcool commentedon Aug 13, 2019
Is there anyone can chekcout this repository?I try to fix it but i faild and it took more than 10 hours.
onlymash commentedon Aug 13, 2019
自动滚动的原因大概明白了。在 progressbar 也就是 footer 被移除前,添加了新的item,recyclerview 会尽可能的维持当前可见的progressbar 继续可见,于是瞬间在 footer前面插入大量的item就会造成自动滚动的效果
onlymash commentedon Aug 13, 2019
假如有一个header,便能避免自动滚动,因为在header 和 footer 之间插入新的item 时 recyclerview 会优先保证 header 的可见性,从而避免了自动滚动
onlymash commentedon Aug 13, 2019
所以解决办法是先让footer消失再向适配器发射数据
parcool commentedon Aug 13, 2019
@onlymash 太感谢了。完美!!!!
valentinilk commentedon Sep 11, 2019
I think I had the same issue and solved it by removing all "networkState.postValue()" calls from the "loadInitial()" function. Additionally this gets rid of the overlaying loading indicators.
dlam commentedon Feb 23, 2021
I believe this issue is obsolete now with the sample being rewritten in paging3 and having loadState as a built-in concept in the library.
If there are any questions about that, happy to answer, but closing this out.