drakeet / multitype Goto Github PK
View Code? Open in Web Editor NEWFlexible multiple types for Android RecyclerView.
License: Apache License 2.0
Flexible multiple types for Android RecyclerView.
License: Apache License 2.0
这两天看auto-value,他的一个特别好的地方是Extension API,这样就可以自己扩展类似于auto-value-gson,auto-value-parcel这样的功能了,如果MultiType也能做类似的支持,是不是能在保证纯粹性和灵活性的基础上避免一些重复造轮子的事呢?
I put forwards my implementations in pull requests. Wish this would help.
recyclerView's click event usually give a interface for you to register in activity, but i found in this library all adapter extends from MultiTypeAdapter class, I can't find any way to get this interface.
for example : if i left a interface setonTextClickListener in TextItemViewProvider , how can i register it in activity or is there any better way to do this?
这个接口是否有点鸡肋?
望解答.
FATAL EXCEPTION: main
Process: com.yunuo.ww, PID: 20664
java.lang.IndexOutOfBoundsException: Invalid index 4, size is 0
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
at java.util.ArrayList.get(ArrayList.java:308)
at com.yunuo.im.ui.activity.GroupProfileActivity$2.getSpanSize(GroupProfileActivity.java:120)
at android.support.v7.widget.GridLayoutManager.getSpanSize(GridLayoutManager.java:475)
at android.support.v7.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:518)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1353)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:574)
at android.support.v7.widget.GridLayoutManager.onLayoutChildren(GridLayoutManager.java:170)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3028)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2906)
at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3283)
at android.view.View.layout(View.java:15748)
at android.view.ViewGroup.layout(ViewGroup.java:4970)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:573)
at android.widget.FrameLayout.onLayout(FrameLayout.java:508)
at android.view.View.layout(View.java:15748)
at android.view.ViewGroup.layout(ViewGroup.java:4970)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1466)
at android.view.View.layout(View.java:15748)
at android.view.ViewGroup.layout(ViewGroup.java:4970)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:573)
at android.widget.FrameLayout.onLayout(FrameLayout.java:508)
at android.view.View.layout(View.java:15748)
at android.view.ViewGroup.layout(ViewGroup.java:4970)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1466)
at android.view.View.layout(View.java:15748)
at android.view.ViewGroup.layout(ViewGroup.java:4970)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:573)
at android.widget.FrameLayout.onLayout(FrameLayout.java:508)
at android.view.View.layout(View.java:15748)
at android.view.ViewGroup.layout(ViewGroup.java:4970)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1466)
at android.view.View.layout(View.java:15748)
at android.view.ViewGroup.layout(ViewGroup.java:4970)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:573)
at android.widget.FrameLayout.onLayout(FrameLayout.java:508)
at android.view.View.layout(View.java:15748)
at android.view.ViewGroup.layout(ViewGroup.java:4970)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2124)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1876)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1080)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5877)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
at android.view.Choreographer.doCallbacks(Choreographer.java:580)
at android.view.Choreographer.doFrame(Choreographer.java:550)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5475)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:948)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:743)。
而我的报错地方代码如下:
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@OverRide
public int getSpanSize(int position) {
Item item = items.get(position);
return (items.get(position) instanceof SendMessage
|| items.get(position) instanceof Spilt
|| items.get(position) instanceof GroupMessage
|| items.get(position) instanceof GroupTitle
|| items.get(position) instanceof GroupMute) ? SPAN_COUNT : 1;
}
});
其中SPAN是4;但是出现数组越界,我下面布局有些是重复利用的,这种现象怎么解决??
大神,这个具体怎么做啊?
我是想把他这个diff的功能,与MutiType一起用的。搞了快一天了还是搞不定啊,一直不走三个参数的onBindViewHolder();
希望大神给指点指点,最好有个小demo/ 万分感谢...
Dear Big God:
Can it support Adapter about ListView ?
RT
Recyclerview添加头部需要使用自定义的RecyclerView.Adapter,怎么使用MultiType呢?
The parent of sub-content implements Item
is appropriate and reasonable, but what about sub-content itself?
Maybe we should create a new interface naming ItemContent
or remove the Item
interface and use Object
instead.
🤔
很好的设计,感谢分享!建议在onBindViewHolder的方法里加上position这个参数吧
看了代码,实现的想法不错,
根据数据类型创建对应的ItemViewProviderd,ItemViewProviderd对ViewHolder执行了onCreateView,onBindView,这使得ViewHolder从Adapter抽离出来给多种Adapter复用.
不过感觉框架使用时代码还是比较多,
我说点自己的想法吧。
定义一个ItemViewProvider工厂接口,根据数据类型创建对应的ItemViewProvider,
代替之前的ItemTypePool.register.因为ItemTypePool.register是全局注册的,而ItemViewProviderFactory可以是使用时切换,也可以复用。
public interface ItemViewProviderFactory {
ItemViewProvider made(Object data);
}
TypeItemsAdapter构
定义一个ItemViewProvider工厂接口,根据数据类型创建对应的ItemViewProvider,
代替之前的ItemTypePool.register.因为ItemTypePool.register是全局注册的,而ItemViewProviderFactory可以是使用时切换,也可以复用。
public interface ItemViewProviderFactory {
ItemViewProvider made(Object data);
}
TypeItemsAdapter构造函数:datas 数据列表,使用者自己实现的ChatItemViewProviderFactory的ItemViewProvider工厂.
recyclerView.setAdapter(new TypeItemsAdapter(datas, new ChatItemViewProviderFactory()));
itemProvider中,onBindViewHolder中提供了当前viewholder和相关的数据类,但是我想访问上一个位置的数据,应该如何做? 问题抽象一下,就是当前item的不仅和自身状态有关,也和上一个item的数据有联系。
drakeet 你好:
sample 中提供的 BilibiliActivity ,无意中我发现了一个 bug。
for (int i = 0; i < 10; i++) {
items.add(data.category0);
items.add(data.postArray[0]);
items.add(data.postArray[1]);
items.add(data.postArray[2]);
items.add(data.postArray[3]);
items.add(data.postArray[0]);
items.add(data.postArray[1]);
items.add(new PostList(data.postList));
}
我在构造数据的地方多添加了 2 条数据,这时 RecyclerView 就会向下移动,而不是从第一条数据开始显示。
期待的效果如下图:
而实际的情况如下图:
我怀疑是水平 RecyclerView 抢占焦点导致的问题,如果你有时间的话,也可以确认一下。
根据我的理解
不知道这样理解对不对
所以我有些疑问
谢谢🙏😄
希望楼主提供一个完善的自动加载更多的功能,毕竟这个功能是跟adapter紧密联系的,
when press back key, and then restart app, it will crash.
Process: me.drakeet.multitype.sample, PID: 25781
java.lang.RuntimeException: Unable to start activity ComponentInfo{me.drakeet.multitype.sample/me.drakeet.multitype.sample.page.MainActivity}: java.lang.IllegalArgumentException: You have registered the TextItemContent type. It should not be added again.
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2359)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2422)
at android.app.ActivityThread.access$800(ActivityThread.java:159)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1319)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5313)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1116)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:809)
Caused by: java.lang.IllegalArgumentException: You have registered the TextItemContent type. It should not be added again.
at me.drakeet.multitype.ItemTypePool.register(ItemTypePool.java:38)
at me.drakeet.multitype.sample.page.MainActivity.onCreate(MainActivity.java:65)
at android.app.Activity.performCreate(Activity.java:6036)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2302)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2422)
at android.app.ActivityThread.access$800(ActivityThread.java:159)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1319)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5313)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1116)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:809)
要完善的还是有不少代码的,是不是可以实现一个跟弘扬的https://github.com/hongyangAndroid/baseAdapter这个一样的wrapadapter包裹着你的这个adapter ,这个完全解耦了,但是弘扬的那个有不少问题而且不不完善,现在也不维护了
As the issue #35 request, I began to think about this issue, a position may be more convenient.
Scheduling.
hi @drakeet 我想问一下TypeItem
的作用是什么,为什么不直接使用ItemContent
而是还要再包装一层,还有extra
这个字段的意义是什么呢? 是在onBindViewHolder
的时候用于区分?谢谢
如果要使用MultiType这个库,就必须为不同的类型建立不同的Item和对应的Provider。但是一般我们的实际开发中,使用的数据的类型也是一致的,比如说NewsItem,只是用其中的某一个字段来标识itemType,但是如果使用MultiType就不怎么好处理了,不知道你是怎么解决这个问题的?
由于 onFlattenClass(Object item) 方法过时,于是实现了MultiTypeAdapter.setFlatTypeAdapterMultiTypeAdapter() 方法,在程序运行时 crash 掉了,日志显示 assertAllRegistered() 方法下 adapter.indexOf(adapter.onFlattenClass(item)); 出错,因为onFlattenClass(item) 过时,未实现。
望改善,祝好!
Q: 如何在 ItemViewProvider 中获取到 item position? A: 从 v2.3.0 版本开始,只需要在你的 ItemViewProvider 子类里调用 getPosition() 方法即可。如果低于 v2.3.0 版本,可以调用 holder.getAdapterPosition() 获得同样结果。
在我使用 v2.3.4 时发现,他们俩并不一致
onClick: ===AdapterPosition:0===Position:1
onClick: ===AdapterPosition:1===Position:1
onClick: ===AdapterPosition:2===Position:2
onClick: ===AdapterPosition:3===Position:3
onClick: ===AdapterPosition:4===Position:4
onClick: ===AdapterPosition:5===Position:5
onClick: ===AdapterPosition:0===Position:0
onClick: ===AdapterPosition:1===Position:0
onClick: ===AdapterPosition:2===Position:0
onClick: ===AdapterPosition:2===Position:0
onClick: ===AdapterPosition:3===Position:3
onClick: ===AdapterPosition:3===Position:3
onClick: ===AdapterPosition:21===Position:22
onClick: ===AdapterPosition:22===Position:22
onClick: ===AdapterPosition:22===Position:22
onClick: ===AdapterPosition:23===Position:24
onClick: ===AdapterPosition:23===Position:24
这是我随手打印的日志
您的sample中的MultiGridActivity中item选中以后,滑动错乱,
sample‘’s Imageview replace SimpleDraweeView run project has wrong
ItemViewBinder
s in one RecyclerView
ItemViewProvider
to ItemViewBinder
(done in v2.5.0)@Deprecated
classes/methodsGlobalMultiTypePool
MultiTypeAdapter
TypePool#getContents()
to getClasses()
(#109)
类似通讯录的首字母悬停顶部的功能
抱歉,弄错了。
你好,drakeet。
我的数据是网络获取的,在一个接口获取第一个数据之后 items.add() ,
在另一个接口获取第二个数据后也 items.add(),而网络请求是异步的,
这时会出现这两个数据在界面上显示位置错乱,在不考虑网络请求嵌套的情况下,
有没有什么好的解决办法。
我现在是这样做的,网络请求之前,先 items.add(index,data) 这两个类型数据的默认值来占位,
请求成功后先 items.remove(index) 再 items.add(index, data),请求失败后 直接items.remove(index),
但是这样又会带来其他的问题。
请问你有什么好的解决方案吗?
Q: 为什么使用静态或者全局类型池?(Why we need static and single TypePool?)
A: 我不反对局部或临时类型池的设计,你可以 fork 这个项目自行实现,它们对于内存更加友好(但也只是微小优势而已),但在我看来,全局类型池在多方面更好:
因此我喜欢和坚持使用全局静态类型池,它不会带来什么问题,而且好处诸多,有人给我提交了使用反射的方法来自动获取类型连接,为了避免性能话题,我不喜欢反射,而且将类型连接变得复杂和不可见性未必是好事。我一直坚持的原则是:写简单的代码,写可读的代码,实现复杂的需求(你们看我的代码是不是感觉很自然而然而且可读性十分好?)
Maybe...
看源码中,MuliTypeAdapter中,已经通过构造器拥有了TypePool接口的对象,为什么本身还需要实现这个接口?是有额外的扩展性考虑吗?
I found a Xiaomi 2s (Android 5.1.1) mobile phone for testing the performance of global static MultiTypePool today. I registered 9999 ItemContent
classes & ItemViewProvider
instances in the Application beginning. The ItemContent
contains 12 random String
s and the ItemViewProvider.TestViewHolder
contains 12 TextView
, and I put my target type after 10000 index for test Adapter onCreateViewHolder's performance.
The results of this testing showed that:
The initialization of registering 10000 types just spend 10ms! And the memory usage is also very low because ItemViewProvider instances do not hold any other class instance actually. And the RecyclerView
which contains MultiType also perform perfectly and smoothly.
So, is there a application reach 10000 types? Do we really need a local type pool? The answer is obvious.
Chinese translated version:
找了一个小米 2s 来对 MultiType
进行测试,注入 9999 个 ItemContent
class 和 ItemViewProvider
对象,ItemContent
包含 12 个随机 String,ItemViewProvider.TestViewHolder
包含 12 个 TextView
对象,并将我们使用的 Type 排到第 10000 位以后(检索严格模式)。
测试结果表明,性能极好。初始化注册 10000 个类型,只要 10 毫秒左右!而且内存占用也极低,因为类型 class 和 provider 对象都是非常非常轻薄的对象,后者虽然是以传统实例注册(其实 class 也是实例),但 provider 层面不持有任何对象,它只提供生产方法;另外,尽管 target index 在 10000 位以后,但丝毫不会影响列表滑动流畅性,因为计算个 10000 次,对于我们的手机 CPU,简直比我们人类 1 + 1 还简单的事情。这更近坚定了我使用全局类型池的设计。
那么问题来了,即使是淘宝,有超过 10000 个 item types 吗?我们真的需要局部类型池吗?答案我想是显然的。
thanks you library.
When I met a different view of an entity when , how can I do ?
Loss sub recyclerview when recyclerview inside recyclerview in os below 5.0 use meizu mobile phone in exceple, pls to checked this issue, i look forward to reply, thx.
你好,我按照步骤在build.gradle文件添加依赖运行项目报错,
# Error:Error converting bytecode to dex:
Cause: com.android.dex.DexException: Multiple dex files define Landroid/support/v4/app/ActionBarDrawerToggleHoneycomb$SetIndicatorInfo;
请问这个问题怎么解决?
你好,我在使用 版本号为 2.4.1 过程中,遇到一个问题,想请教下。
使用场景:
对于聊天消息,每种消息都有左右样式,但左右样式的数据绑定操作是一样,因此想说继承
ItemViewProvider ,重写 onCreateViewHolder() 方法,然后在这里根据数据对象的类型(发送或接受消息)来加载左或右布局,onBindViewHolder() 方法则进行相同的数据绑定操作。
问题:
在 onCreateViewHolder() 方法获取不到当前位置对应的数据对象,无法进行判断
其他:
1.看了 TimeMachine 的消息列表实现,看到左右消息区分了不同的 Content ,Provider ,但是数据内容,数据绑定是一样,这样实现会不会冗余?
2.在 "https://gank.io/post/5823bcf6421aa90e799ec2ad" 中,看到这句"每一种消息都有左边和右边的样式,分别对应别人发来的消息和你发出的消息。如果左边算一种,右边又算一种,就是比较不好的设计了,会导致布局内容重复、冗余,修改操作都要做两遍。最好的方案是让他们视被为同一种类型,然后在 item 框层次进行左右边判断和框架相关数据绑定。"
这里的 item 框层次进行左右判断,是指?
可能是哪里愚钝,没有理解,希望指点,谢谢~~
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.