idanatz / oneadapter Goto Github PK
View Code? Open in Web Editor NEWA Viewholderless Adapter for RecyclerView, who supports builtin diffing, states (paging, empty...), events (clicking, swiping...), and more.
License: MIT License
A Viewholderless Adapter for RecyclerView, who supports builtin diffing, states (paging, empty...), events (clicking, swiping...), and more.
License: MIT License
The ability to use the Unique Identifier of Long Type can't satisfy every situation.
For example, the data which is Synced with Firebase (Realtime Database) can't have IDs Long values. Support Dynamic Type Support in Diffable
Diffable<Long> or Diffable<String>
Hi,
I recently discovered your API and it looks great at first look.
But I tried to implement a very basic example and impossible to get a result.
Here my files:
MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recycler = findViewById<RecyclerView>(R.id.recycler)
val oneAdapter = OneAdapter()
.attachItemModule(CardModule())
.attachTo(recycler)
val list = (0 until 100).map { CardModel("Card $it") }.toList()
oneAdapter.setItems(list)
}
}
CardModel
class CardModel(val title: String = "Title"): Diffable {
private val id: Int = Random().nextInt()
override fun areContentTheSame(other: Any): Boolean {
return other is CardModel && title == other.title
}
override fun getUniqueIdentifier(): Long {
return id.toLong()
}
}
CardModule
class CardModule: ItemModule<CardModel>() {
override fun onBind(model: CardModel, viewBinder: ViewBinder) {
viewBinder.findViewById<TextView>(R.id.card_module_title).text = model.title
}
override fun provideModuleConfig(): ItemModuleConfig = object: ItemModuleConfig() {
override fun withLayoutResource(): Int = R.layout.card_module
}
}
card_module.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/card_module_title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
activity_main.xml
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_height="0dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
There is no crash nor explicit error.
My MainActivity just stay perfectly empty.
Is there something I misunderstood ?
Hi, Is there a way to dynamically change the layout manager ?
Thank you
Hi @ironsrc,
Thanks for the library. Have been using it quite a number of my projects but have recently ran into a problem that the API response has only 10 items and the UI doesn't cover whole page and due to that the scroll event of recyclerview is not called.
Is there any way or function can make the Paging module load the next page without scrolling.
Any help would be appreciated.
Hi, it's currently not possible to implement spanSizeLookup
of GridLayoutManager
because we can't access the getItemViewType
function of the adapter. so whenever you have a list with a GridLayoutManager
the loading icon of the paginator gets fit within the grid size which looks weird
See #16
In pagination, after adding new items, you return to the top of the list and new items are added to the bottom of the list.
Hi!
I have this use case. Show admob native Ads in the recycler view. I can use multi modulo adapter, but how can i show Every 3 items of the modulo A, One item of the module B?
Thanks a lot
Maybe I am doing something wrong, but I am setting up the Adapter as explained in the documentation (I am using databinding), but when I call the method update()
of the OneAdapter instance, the recyclerview scrolls to the updated position if it is not visible.
I dont want this behavior... If it is not visible, it should stay in the same scroll position. Is this behavior expected or there is any way to avoid this?
By the way, great library! Started to using it and it seems very handy.
Hi, this is more a question than an issue, related to Room Datasource+LiveData PagedList.
I want to use selectable item feature of the OneAdapter, so i am trying to change currently working RecyclerView with PagedListAdapter.
But for OneAdapter, i need to ask PagedList from Room datasource to load next items , which i could not find how can it be done. As i understand PagedListAdapter requests next loading of items automatically by calculating Item size and recyclerview viewport size. and calls pagedlist.loadAround(Int)
. I am not sure about the Int value passed here, its probably the internally maintained enumerated index of current list. I could not find how can i request next page to load in viewmodel. Did anyone can direct me how to use Room Paging Datasource with OneAdapter.?
object OneAdapters {
fun create(recyclerView: RecyclerView, onClick:(ModelEntity)->Unit,onCurrentBind:(Int)->Unit,loadMoreCall:(Int)->Unit) =OneAdapter(recyclerView){
itemModules+=ExperimentModelItem(onClick,onCurrentBind)
pagingModule=PagingModuleImpl(loadMoreCall)
}
internal class ExperimentModelItem(onClick: (ModelEntity) -> Unit,onCurrentBind: (Int) -> Unit) : ItemModule<ModelEntity>() {
init {
config {
layoutResource = R.layout.item_tile_list
}
onBind { model, viewBinder, metadata ->
viewBinder.bindings(ItemTileListBinding::bind).run {
onCurrentBind(metadata.position)
title.text = model.modelname
model.modified_at?.let { d ->
subtitle.text = "modified ${DateFormatHelper.readable(d)}"
}
}
}
onUnbind { model, viewBinder, _ ->
}
eventHooks += ClickEventHook<ModelEntity>().apply {
onClick { model, viewBinder, _ ->
onClick(model)
}
}
}
}
internal class PagingModuleImpl(loadMoreCall:(Int)->Unit) : PagingModule() {
init {
config {
layoutResource = R.layout.item_loading_progress// can be some spinner animation
visibleThreshold = 0 // invoke onLoadMore 3 items before the end
}
onLoadMore { currentPage ->
// place your load more logic here, like asking the ViewModel to load the next page of data.
loadMoreCall(currentPage)
}
}
}
}
private var mListMaxPosition: Int = 0
private val mRecyclerAdapter: OneAdapter by lazy {
OneAdapters.create(binding.explistActivityRecylerview, onClick = {
// navigate
},
onCurrentBind = {
if (it > mListMaxPosition)
mListMaxPosition = it
},
loadMoreCall = {
viewmodel.add(VMEvent.LoadMore(mListMaxPosition))
})
}
init{
val factory =repo.getAllModelsFactory()
val config = PagedList.Config.Builder()
.setEnablePlaceholders(false) // when true, the oneadapter's internal adapter crash on validating list having null models
.setInitialLoadSizeHint(15)
.setPageSize(5).build()
val pagedListBuilder: LivePagedListBuilder<Int, ModelEntity> = LivePagedListBuilder<Int,ModelEntity>(
factory,
config
)
models=pagedListBuilder.build() // observed LiveData in activity
}
fun onLoadMore(currentPage:Int) // called from activity,
{
models.value?.let {
// it.loadAround(currentPage) // max intPosition comming from activity
//it.loadAround(it.lastKey as Int)
}
}
Hello, thanks for update.
Seems like calling oneAdapter.setItems(...) from background thread no longer supported in 2.1.0, but works fine in 2.0.2.
Is it expected behaviour?
Code:
lifecycleScope.launch(Dispatchers.Default) {
val items = ...
oneAdapter.setItems(items)
}
Result:
2021-04-05 10:48:06.193 29570-29650/a.b.c E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-2
Process: a.b.c, PID: 29570
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:8648)
at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1533)
...
Seems like this can easily be fixed with: withContext(Dispatchers.Main) { oneAdapter.setItems(items) }
, but probably this should be done on the library side for backwards compatibility?
Hi,
When I set a SelectionState in a Module with selectionTrigger set to Click, it disable any other click event that could happend on the module view.
I know for sure the issue is from the SelectionState because it works properly if I set to 'false' the 'enable' property in the SelectionState config.
Is it an expected behavior, is there a workaround ?
Thanks
btw: when a SelectionState is set in a module, the onBind method of that module is never called. So the onBind method of the SelectionState must contain all of the binding. If that's the expected bahavior, please precise it in the Readme, cost me some time.
how to create nested recyclerview to handling layoutManager orientation?
If i select an item in the recyclerview another gets highlight at the same time when scrolling. I tried the sample project and have the same result. Like this:
I thanks for this library, so I want to use ButterKnife to bind my view. I can not this.
Good day. Tell me if it is possible to somehow pre-select some elements of the list when forming the adapter elements?
The OneAdapter class is not open, and then I can't get the data from the adapter. can support a function to read the data from the adapter?
First of all thank you for this great library which makes working with RecyclerView much easier.
OneAdapter supports selection with a long click.
Unfortunately i have not yet found a way to enable selection with just a normal (short) click.
My first approach was to clone the project and implement it myself. Unfortunately the project is very complex and i couln't get it done.
Is there any way to enable/implement selection with short clicks? And is there a way to set a default selection?
Any help is appreciated.
I only know Java, please support Java as well
Hi, how to implement the select all feature?
Please add this option if you can.
I am using OneAdapter along with the Paging module to load images gradually from an API. The problem is that if I scroll the list rapidly the paging stops and no more data is loaded after 3-4 pages.
I am attaching the all the necessary code that I am using below.
HomeFragment
class HomeFragment : BaseFragment() {
private val viewModel by viewModel<HomeViewModel>() // Lazy inject ViewModel
private lateinit var homeAdapter: OneAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_home, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupRecyclerView()
observeImagesLiveData()
}
private fun setupRecyclerView() {
rvHome.layoutManager = GridLayoutManager(context, 2)
homeAdapter = OneAdapter()
.attachItemModule(HomeItem(context!!))
.attachPagingModule(HomePagingModule(viewModel))
.attachTo(rvHome)
homeAdapter.setItems(emptyList())
}
private fun observeImagesLiveData() {
viewModel.getPicsumImages(1).observe(this, Observer { result ->
when (result) {
is Result.Loading -> {
Timber.e("Loading")
}
is Result.Success<*> -> {
val imagesList = result.data as List<PicsumPhoto>
homeAdapter.add(imagesList)
}
is Result.Error -> {
Timber.e(result.errorMessage)
}
}
})
}}
ItemModule
class HomeItem(context: Context) : ItemModule<PicsumPhoto>() {
private val displayMetrics = context.resources.displayMetrics
private val columnWidth = displayMetrics.widthPixels / 2
override fun provideModuleConfig() = object : ItemModuleConfig() {
override fun withLayoutResource() = R.layout.item_home
}
override fun onBind(model: PicsumPhoto, viewBinder: ViewBinder) {
val mainImage: ImageView = viewBinder.findViewById(R.id.ivMainHomeItem)
mainImage.apply {
layoutParams.height = columnWidth
layoutParams.width = columnWidth
load(model.download_url)
}
}}
PagingModule
class HomePagingModule(private val homeViewModel: HomeViewModel) : PagingModule() {
override fun provideModuleConfig() = object : PagingModuleConfig() {
override fun withLayoutResource() = R.layout.load_more
override fun withVisibleThreshold() = 3
}
override fun onLoadMore(currentPage: Int) {
homeViewModel.getPicsumImages(currentPage + 1)
}}
First of all, thank you very much for this great library. If you start making multiple selections and then want to cancel the selection when the selected item is not visible, the invisible items remain selected. To understand whether it is my mistake, I tried it in the sample application, and I see the same issue here as well.
I am adding a video for better understanding.
https://github.com/ironSource/OneAdapter/assets/45034416/e4905816-59eb-4bc0-8652-6a51dd7c4316
Thank you
Is it possible to add retry button (and message TextView to show some error hint message) to paging module? (Like in Android Paging 3).
i use setItem(), the onBind{} not be invoke, but UI has changed a little, and then i try invoke notifyDataSetChanged() of recycleview's adapter on next line, the onBind{} is invoked. when i want to delete an item, i use the data to setItem() that has been deleted the item, but the onBind{} not working, throught i have invoke notifyDataSetChanged() on next line, like this:
oneAdapterForOther?.setItems(it)
sharedForOtherRecycler?.adapter?.notifyDataSetChanged()
Hello!
Sometimes (<1%) there is an exceptiom in onCreate with this stacktrace:
2020-12-05 18:23:07.758 14685-14685/com.sample.app E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.sample.app, PID: 14685
kotlin.TypeCastException: null cannot be cast to non-null type V
at com.idanatz.oneadapter.internal.holders.ViewBinder.findViewById(ViewBinder.kt:31)
at com.sample.app.DialogsActivity$DialogModule$2.invoke(DialogsActivity.kt:50)
at com.sample.app.DialogsActivity$DialogModule$2.invoke(DialogsActivity.kt:37)
at com.idanatz.oneadapter.internal.InternalAdapter$register$1$create$1.onBind(InternalAdapter.kt:233)
at com.idanatz.oneadapter.internal.holders.OneViewHolder.onBindViewHolder(OneViewHolder.kt:51)
at com.idanatz.oneadapter.internal.InternalAdapter.onBindViewHolder(InternalAdapter.kt:118)
at com.idanatz.oneadapter.internal.InternalAdapter.onBindViewHolder(InternalAdapter.kt:39)
at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:7065)
at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7107)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6012)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6279)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6118)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6114)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1627)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3851)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4404)
at android.view.View.layout(View.java:19692)
at android.view.ViewGroup.layout(ViewGroup.java:6057)
at androidx.coordinatorlayout.widget.CoordinatorLayout.layoutChild(CoordinatorLayout.java:1213)
at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayoutChild(CoordinatorLayout.java:899)
at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:919)
at android.view.View.layout(View.java:19692)
at android.view.ViewGroup.layout(ViewGroup.java:6057)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:19692)
at android.view.ViewGroup.layout(ViewGroup.java:6057)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:19692)
at android.view.ViewGroup.layout(ViewGroup.java:6057)
at androidx.appcompat.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:530)
at android.view.View.layout(View.java:19692)
at android.view.ViewGroup.layout(ViewGroup.java:6057)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:19692)
at android.view.ViewGroup.layout(ViewGroup.java:6057)
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:19692)
at android.view.ViewGroup.layout(ViewGroup.java:6057)
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:759)
at android.view.View.layout(View.java:19692)
at android.view.ViewGroup.layout(ViewGroup.java:6057)
2020-12-05 18:23:07.759 14685-14685/com.sample.app E/AndroidRuntime: at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2515)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2224)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1410)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6834)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:966)
at android.view.Choreographer.doCallbacks(Choreographer.java:778)
at android.view.Choreographer.doFrame(Choreographer.java:713)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:952)
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:6809)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
2020-12-05 18:23:07.761 14685-14685/com.sample.app E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.sample.app, PID: 14685
kotlin.TypeCastException: null cannot be cast to non-null type V
at com.idanatz.oneadapter.internal.holders.ViewBinder.findViewById(ViewBinder.kt:31)
at com.sample.app.DialogsActivity$DialogModule$2.invoke(DialogsActivity.kt:50)
at com.sample.app.DialogsActivity$DialogModule$2.invoke(DialogsActivity.kt:37)
at com.idanatz.oneadapter.internal.InternalAdapter$register$1$create$1.onBind(InternalAdapter.kt:233)
at com.idanatz.oneadapter.internal.holders.OneViewHolder.onBindViewHolder(OneViewHolder.kt:51)
at com.idanatz.oneadapter.internal.InternalAdapter.onBindViewHolder(InternalAdapter.kt:118)
at com.idanatz.oneadapter.internal.InternalAdapter.onBindViewHolder(InternalAdapter.kt:39)
at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:7065)
at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7107)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6012)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6279)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6118)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6114)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1627)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3851)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4404)
at android.view.View.layout(View.java:19692)
at android.view.ViewGroup.layout(ViewGroup.java:6057)
at androidx.coordinatorlayout.widget.CoordinatorLayout.layoutChild(CoordinatorLayout.java:1213)
at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayoutChild(CoordinatorLayout.java:899)
at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:919)
at android.view.View.layout(View.java:19692)
at android.view.ViewGroup.layout(ViewGroup.java:6057)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:19692)
at android.view.ViewGroup.layout(ViewGroup.java:6057)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:19692)
at android.view.ViewGroup.layout(ViewGroup.java:6057)
at androidx.appcompat.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:530)
at android.view.View.layout(View.java:19692)
at android.view.ViewGroup.layout(ViewGroup.java:6057)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:19692)
at android.view.ViewGroup.layout(ViewGroup.java:6057)
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:19692)
at android.view.ViewGroup.layout(ViewGroup.java:6057)
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:759)
at android.view.View.layout(View.java:19692)
at android.view.ViewGroup.layout(ViewGroup.java:6057)
2020-12-05 18:23:07.761 14685-14685/com.sample.app E/AndroidRuntime: at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2515)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2224)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1410)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6834)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:966)
at android.view.Choreographer.doCallbacks(Choreographer.java:778)
at android.view.Choreographer.doFrame(Choreographer.java:713)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:952)
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:6809)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
2020-12-05 18:23:07.761 14685-14685/com.sample.app D/AppTracker: App Event: crash
Code DialogsActivity.kt, line 50:
onBind { model, viewBinder, metadata ->
viewBinder.findViewById<TextView>(R.id.titleTv).text = model.name
...
}
DialogsActivity has DataBinding and ViewBinding, probably. there is some conflict between internal oneAdapter binding?
Is there any support for the sticky headers. if not, how can i add custom item decorator to extend the functionality of this library.
Thanks
Hi! very nice library
I'm trying to change programmatically text and lottieview of the emptiness module. This is my flow:
or
Thanks!
Hey there,
as of today i tried migrating an older app and now i am required to use Kotlins Android View Binding with kotlin 1.6.0.
I followed the example in the readme but i cant make it to work.
This is how my code looks:
class DiscoveredDeviceModule(
val context: Context,
private val callback: DeviceModuleCallbackListener?
) : ItemModule<DiffableDevice>() {
init {
config {
layoutResource = R.layout.component_discover_bt_list_item
firstBindAnimation = AnimatorInflater.loadAnimator(
context,
R.animator.animator_new_bt_device_discovered
)
}
onBind { item, viewBinder, _ ->
viewBinder.bindings(ComponentDiscoverBtListItemBinding::bind).run {
btListItemTitle.text = item.getReadableName(context.resources)
// PushDownAnim.setPushDownAnimTo(btListItemWrapper)
btListItemWrapper.setOnClickListener {
btListItemProgress.visibility = View.VISIBLE
callback?.onClick(item)
}
}
}
}
interface DeviceModuleCallbackListener {
fun onClick(device: DiffableDevice) {}
}
}
Everytime the onBind should have been called, nothing appears in the view.
Any help?
The version i'm using is 2.1.1
Hello, I use MVVM pattern with OneAdapter in my app. When new element added to 0 position in items list, we need to manually scroll up to see recently added element. If, for example, new element has index 1, then all work correct and there is animation of adding element.
Do you know any way to automatically scroll to top of list when new element has index 0 and old element with index 0 was visible by user before updating?
Or, probably, scroll to top of list always - it also acceptable for me)
Short code fragment to update adapter:
dialogViewModel.allDialogs.observe(this) { dialogs ->
oneAdapter.setItems(dialogs)
}
Update: When elements in the list takes smaller space then available on screen, animation of adding element with 0 index works correct, but after empty space on screen left, list just stop updating even if the user is at the very beginning of the list and expects to see new items from the top.
Because of line 12 in com.idanatz.oneadapter.internal.utils in generic.kt you can't use ItemModule with interfaces as in
class MyModule() : ItemModule<SomeInterface>
SomeInterface being
interface SomeInterface { ... }
It causes crash.
It's because you are using
if (className.startWith("class ")) { }
And class name for interface starts with "interface "
You can use abstract class tho since its class name starts with "class " but it simply will do nothing since you can have object with class name of abstract class, and thats how library indentifies types
Also im certain that what you are implementing here is just
type.typeName
The readme docs for adding event hooks show the following example code:
val oneAdapter = OneAdapter(recyclerView)
.attachItemModule(MessageModule()).addEventHook(MessageClickEvent())
...
there is a parenthese misplaced.
Correct:
val oneAdapter = OneAdapter(recyclerView)
.attachItemModule(MessageModule().addEventHook(MessageClickEvent()))
...
Hi,
since RecyclerViews can be in horizontal mode (i.e. items are laid out horizontally), it would be great to have vertical swipe directions, i.e. SwipeDirection.UP
and SwipeDirection.DOWN
.
As a matter of fact, that would be really great for me to have right now...
Thanks for reading and keep up the great work!
I followed a basic usage tutorial and I got a exception:
Process: com.example, PID: 13642
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{232efed position=2 id=-969824770, oldPos=0, pLpos:0 scrap [attachedScrap] tmpDetached no parent} androidx.recyclerview.widget.RecyclerView{3f2d670 VFED..... ......I. 0,0-1080,1516 #7f0900e6 app:id/recyclerView}, adapter:com.idanatz.oneadapter.internal.InternalAdapter@65b9de9, layout:androidx.recyclerview.widget.LinearLayoutManager@a556a6e, context:com.example.MainActivity@6c3203e
at androidx.recyclerview.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:5953)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6137)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6097)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6093)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1627)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:4066)
at androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:3515)
at android.view.View.measure(View.java:24510)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:842)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
at android.view.View.measure(View.java:24510)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:24510)
at androidx.recyclerview.widget.RecyclerView$LayoutManager.measureChildWithMargins(RecyclerView.java:9352)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1653)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4115)
at androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:3521)
at android.view.View.measure(View.java:24510)
at android.view.ViewGroup.measureChild(ViewGroup.java:6799)
at androidx.viewpager2.widget.ViewPager2.onMeasure(ViewPager2.java:482)
at android.view.View.measure(View.java:24510)
at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:735)
at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:481)
at android.view.View.measure(View.java:24510)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:842)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
at android.view.View.measure(View.java:24510)
at android.widget.ScrollView.measureChildWithMargins(ScrollView.java:1414)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.widget.ScrollView.onMeasure(ScrollView.java:452)
at android.view.View.measure(View.java:24510)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:143)
at android.view.View.measure(View.java:24510)
2019-08-13 12:33:05.879 13642-13642/com.example E/AndroidRuntime: at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:842)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
at android.view.View.measure(View.java:24510)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:24510)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:842)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
at android.view.View.measure(View.java:24510)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:736)
at android.view.View.measure(View.java:24510)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:3004)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1833)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2122)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1721)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7595)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:966)
at android.view.Choreographer.doCallbacks(Choreographer.java:790)
at android.view.Choreographer.doFrame(Choreographer.java:725)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:951)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7319)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:934)
Below you can find my classes.
Model:
class Model(private val id: Long) : Diffable {
override fun areContentTheSame(other: Any) = other is Model && other.id == id
override fun getUniqueIdentifier() = id
}
ItemModule:
class ExampleItemModule : ItemModule<Model>() {
override fun onBind(model: Model, viewBinder: ViewBinder) {
//unused for now
}
override fun provideModuleConfig(): ItemModuleConfig = object : ItemModuleConfig() {
override fun withLayoutResource() = R.layout.example_item
}
}
Adapter initialization:
recyclerView.layoutManager = LinearLayoutManager(context)
val oneAdapter = OneAdapter()
.attachItemModule(ExampleItemModule())
.attachTo(recyclerView)
oneAdapter.setItems(listOf(Model(1L), Model(2L)))
I execute all of the code on the main thread, so modification on the background thread is not the reason for the exception. I would be very grateful if you consider my request ASAP.
Hi,
I appear to have the same problem again that I have had numerous times before, plus an additional but maybe related problem. Skip to the bottom to see a summary.
2020-07-21 22:02:09.269 8841-8841/de.mariushubatschek.virtuellelehrpfade E/AndroidRuntime: FATAL EXCEPTION: main
Process: de.mariushubatschek.virtuellelehrpfade, PID: 8841
java.lang.IllegalStateException: Two different ViewHolders have the same stable ID. Stable IDs in your adapter MUST BE unique and SHOULD NOT change.
ViewHolder 1:ViewHolder{ee6663e position=8 id=-1687197900, oldPos=-1, pLpos:-1 not recyclable(1)}
View Holder 2:ViewHolder{d9b71cb position=5 id=-1687197900, oldPos=-1, pLpos:-1} androidx.recyclerview.widget.RecyclerView{c4902e4 VFED..... ......ID 0,0-733,100 #7f080130 app:id/photoRecyclerView}, adapter:com.idanatz.oneadapter.internal.InternalAdapter@a4fe34d, layout:androidx.recyclerview.widget.LinearLayoutManager@5d36e02, context:de.mariushubatschek.virtuellelehrpfade.MainActivity@d9a6051
at androidx.recyclerview.widget.RecyclerView.handleMissingPreInfoForChangeError(RecyclerView.java:4268)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep3(RecyclerView.java:4192)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3862)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4404)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1915)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1915)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1915)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
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:753)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2792)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2319)
2020-07-21 22:02:09.269 8841-8841/de.mariushubatschek.virtuellelehrpfade E/AndroidRuntime: at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1460)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7183)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:949)
at android.view.Choreographer.doCallbacks(Choreographer.java:761)
at android.view.Choreographer.doFrame(Choreographer.java:696)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:935)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
I added 4 items to a RecyclerView
backed with a OneAdapter
.
RecyclerView
and OneAdapter
in question?In the Fragment
:
val photoRecyclerView = view.findViewById<RecyclerView>(R.id.photoRecyclerView)
val layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
photoRecyclerView.layoutManager = layoutManager
val snapHelper = LinearSnapHelper()
snapHelper.attachToRecyclerView(photoRecyclerView)
photosOneAdapter = OneAdapter(photoRecyclerView)
photosOneAdapter
.attachItemModule(PhotoItemModule(requireContext()))
.attachEmptinessModule(VoiceOverEmptinessModule())
PhotoItemModule:
class PhotoItemModule (val context: Context) : ItemModule<Photo>() {
override fun onBind(item: Item<Photo>, viewBinder: ViewBinder) {
val imageView = viewBinder.findViewById<ImageView>(R.id.imageView)
val imageUri = FileStorage.getFileUri(context, item.model.imagePath)
Glide.with(context).load(imageUri).thumbnail(0.2f).override(200,100).fitCenter().diskCacheStrategy(DiskCacheStrategy.ALL).into(imageView)
}
override fun provideModuleConfig() = object : ItemModuleConfig() {
override fun withLayoutResource() = R.layout.photo_item
}
}
VoiceOverEmptinessModule:
class VoiceOverEmptinessModule : EmptinessModule() {
override fun provideModuleConfig() = object : EmptinessModuleConfig() {
override fun withLayoutResource() = R.layout.empty_recycler
}
}
The item:
public class Photo implements Diffable {
private static volatile int currentId = 0;
private static final Object lock = new Object();
private long id;
private String imagePath;
public Photo() {
//TODO: Do this differently in production?
synchronized (lock) {
id = ++currentId;
Timber.e("id is %d", id);
}
}
public void setImagePath(String imagePath) {
this.imagePath = imagePath;
}
public String getImagePath() {
return imagePath;
}
public void setId(long id) {
this.id = id;
}
public long getId() {
return id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Photo photo = (Photo) o;
return id == photo.id &&
Objects.equals(imagePath, photo.imagePath);
}
@Override
public int hashCode() {
return Objects.hash(id, imagePath);
}
@Override
public boolean areContentTheSame(@NotNull Object o) {
if (!(o instanceof Photo)) {
return false;
}
Photo other = (Photo) o;
return other.id == id && other.imagePath.equals(imagePath);
}
@Override
public long getUniqueIdentifier() {
return id;
}
}
In the Fragment
:
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
createMarkerDialogViewModel.photoListLiveData.observe(viewLifecycleOwner, Observer {
photosOneAdapter.clear() //Why is this here? See point number 1 in the questions section
photosOneAdapter.add(it)
Timber.e("item count is ${photosOneAdapter.itemCount} while size is ${it.size}")
})
}
Here, createMarkerDialogViewModel
is a ViewModel
and photoListLiveData
is a LiveData
.
The following screenshot was taken after the third item was inserted. NOTE that each pair of the picture and the "a>z"-Image consitutes one item, but we count at least five pairs, i.e. at least 5 items:
photosOneAdapter.clear()
call not seem to work?If anything is unclear or I forgot something, notify me and I'll provide the necessary information. Since this is part of a larger project at uni I can't really show the whole source, but I'll do my best to help.
public class Productadaptermodel extends ItemModule {
@NotNull
@OverRide
public ItemModuleConfig provideModuleConfig() {
return new ItemModuleConfig() {
@OverRide
public int withLayoutResource() { return R.layout.layout_category_list; }
};
}
@Override
public void onBind(@NotNull Item<Product> item, @NotNull ViewBinder viewBinder) {
LayoutCategoryListBinding binding= (LayoutCategoryListBinding) viewBinder.getDataBinding();
binding.setProduct(item.getModel());
binding.executePendingBindings();
}
}
////////
class Pagation extends PagingModule{
@Override
public void onLoadMore(int i) {
viewModel.getProductListByPaging(cat_id,String.valueOf(i)).observe(owner, new Observer<Resource<List<Product>>>() {
@Override
public void onChanged(Resource<List<Product>> listResource) {
if (listResource.status.equals(Status.SUCCESS)) {
oneAdapter.add(listResource.data);
}
}
});
}
@NotNull
@Override
public PagingModuleConfig provideModuleConfig() {
return new PagingModuleConfig() {
@Override
public int withVisibleThreshold() {
return 0;
}
@Override
public int withLayoutResource() {
return R.layout.item_progress;
}
};
}
}
public class Product implements Serializable, Diffable {
SerializedName("Unique")
@expose
public String unique;
@OverRide
public boolean areContentTheSame(@nonnull Object other) {
return other instanceof Product && unique.equals(((Product) other).unique);
}
@Override
public long getUniqueIdentifier() {
return UUID.randomUUID().getMostSignificantBits();
}
}
///////
oneAdapter = new OneAdapter(recycler_product)
.attachPagingModule(new Pagation())
.attachItemModule(new Productadaptermodel());
Hello, in version 2.1.1 there is load more intermediate progress bar when calling
oneAdapter.setItems(listOf())
or
oneAdapter.clear()
if adapter has items previously.
For example, I call this method in swipeRefreshLayout.setOnRefreshListener to clear previously loaded items (and clear onLoadMore with error), then I get two circle animation: one from swipeRefreshLayout, another one from OneAdapter - this looks bad.
Probably adapter should not try to load more items, if empty list submitted?
Hi,
Could you add support to get and set the StateRestorationPolicy? this is currently not accessible since the adapter is private.
Edit:
After peeking in OneAdapter.kt it can be done simply by adding this line:
var stateRestorationPolicy: StateRestorationPolicy
get() = internalAdapter.stateRestorationPolicy
set(value) {
internalAdapter.stateRestorationPolicy = value
}
and it would be nice if the paginator could also implement some sort of state restoring so that after a state has been restored the pagination can go on where it left off
not working to undo view
I followed the Databinding example and noticed that everytime I leave the fragment and return to it, the elements inside oneadapter redraw. Is this expected or did I miss something?
i tried to stop the swipe on left or right and it couldn't be done
thanks for amazing library
hello, first of all thanks for this library. What is the best way to filter between items in a list? remove and add back items or update method?
its not possible to make a layout where you have a list where every 1 item it has a darker background
It would be nice if I could get the item position from the ItemModule so that it would simple be:
val darkBackground = position % 2 == 1
from the onBind function
Disclaimer: I measured the execution time of this function by displaying timestamp just before and just after call. Apparently, it only takes 1ms to execute. If this function does not use different threads, the problem may not come from it.
I am trying to display some objects but it seems to be taking much longer than expected. The GUI freezes for 6~7s so I am sure it's a process executed on the Main Thread.
Here my Diffable :
class ExpansionDiffable(val expansion: Expansion): Diffable {
override fun areContentTheSame(other: Any): Boolean {
return other is ExpansionDiffable
&& other.expansion.count == expansion.count
&& other.expansion.countOwned == expansion.countOwned
&& other.expansion.price == expansion.price
&& other.expansion.priceOwned == expansion.priceOwned
&& other.expansion.body == expansion.body
}
override fun getUniqueIdentifier(): Long {
return expansion.idExpansion.toLong()
}
}
And here my Module
class ExpansionModule: ItemModule<ExpansionDiffable>() {
override fun onBind(model: ExpansionDiffable, viewBinder: ViewBinder) {
val name: TextView = viewBinder.findViewById(R.id.name)
val progress: CircleProgressView = viewBinder.findViewById(R.id.progress)
val abbreviation: TextView = viewBinder.findViewById(R.id.abbreviation)
val count: TextView = viewBinder.findViewById(R.id.count)
val worth: TextView = viewBinder.findViewById(R.id.worth)
val releaseDate: TextView = viewBinder.findViewById(R.id.releaseDate)
name.text = model.expansion.name
progress.set(model.expansion.countRatio)
abbreviation.text = model.expansion.abbreviation
releaseDate.text = model.expansion.releaseDateLimited
if (!model.expansion.isReleased)
releaseDate.textColor = context.getColor(R.color.red_A200)
else
releaseDate.textColor = context.getColor(R.color.md_black_1000)
count.text = "${model.expansion.countOwned}/${model.expansion.count}"
worth.text = model.expansion.priceOwned.toPriceString()
}
override fun provideModuleConfig(): ItemModuleConfig = object: ItemModuleConfig() {
override fun withLayoutResource(): Int = R.layout.expansion_module
}
}
For information, there are around 500 Expansions to display.
Do you think that the slowdown observed could come from your library?
Hello, thank you again for a wonderful library :)
Seems like one of fixed issue present in 2.0.2 version: #3 (comment) + fresh comment.
Issue reproduced many times (but not in 100% of case) when using OneAdapter for search result output.
When search query deleted from EditText and all elements set to adapter again, I got following crash:
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{8d1f079 position=650 id=-982111498, oldPos=0, pLpos:0 scrap [attachedScrap] tmpDetached not recyclable(1) no parent} androidx.recyclerview.widget.RecyclerView{e7fe2ea VFED..C.. ......ID 0,147-1080,1272 #7f0a01db app:id/stickerRV}, adapter:com.idanatz.oneadapter.internal.InternalAdapter@a3ef664, layout:a.b.c.ChatActivity$onCreate$layoutManager$1@13990cd, context:a.b.c.ChatActivity@1d3c1e
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{1ea3008 position=962 id=-982111498, oldPos=0, pLpos:0 scrap [attachedScrap] tmpDetached not recyclable(1) no parent} androidx.recyclerview.widget.RecyclerView{a1072c1 VFED..C.. ......ID 0,147-1080,1272 #7f0a01db app:id/stickerRV}, adapter:com.idanatz.oneadapter.internal.InternalAdapter@fcde36a, layout:a.b.c.ChatActivity$onCreate$layoutManager$1@3f0505b, context:a.b.c.ChatActivity@ce1c807
I think fast filling and changing data in the adapter can cause this error. Can you check this when you have time?
Thanks)
Hi, the library is really great due to its modular design. It really does help a lot.
Unfortunately I have encountered an issue. I will first show some code, but I do not have a small, executable example at the moment, I might add it later.
My code uses the OneAdapter as follows:
Within the fragment:
recyclerView = view.findViewById(R.id.ingredients_list);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
oneAdapter = new OneAdapter(recyclerView);
oneAdapter.attachEmptinessModule(new PantryEmptinessModule());
oneAdapter.attachPagingModule(new PantryPagingModule());
oneAdapter.attachItemModule(new PantryItemModule());
prepopulateAdapter();
Within prepopulateAdapter (on main thread):
oneAdapter.add(recipes); //recipes is an ArrayList
Within PantryPagingModule:
@Override
public PagingModuleConfig provideModuleConfig() {
return new PagingModuleConfig() {
@Override
public int withVisibleThreshold() {
return 3;
}
@Override
public int withLayoutResource() {
return R.layout.load_more_item;
}
};
}
@Override
public void onLoadMore(int i) {
//Recipes are obtained in the background...
//on main thread
oneAdapter.add(recipes); //recipes is an ArrayList
}
The item looks as follows:
@PrimaryKey
public int id;
@ColumnInfo(name = "name")
public String name;
@ColumnInfo(name = "amount")
public int amount;
@Override
public boolean areContentTheSame(@NotNull Object o) {
if (!(o instanceof Recipe)) {
return false;
}
Ingredient other = (Recipe) o;
boolean names = this.name.equals(other.name);
boolean amount = this.amount == other.amount;
return names && amount;
}
@Override
public long getUniqueIdentifier() {
return id;
}
And the error message that sometimes comes when scrolling is:
ava.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder
Now, I have no idea where this error might come from. Maybe we can find a solution to this and fix it. If any more information is needed, I'll be happy to help. Thanks in advance.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.