@@ -176,12 +176,12 @@ public void appendMatchFeature(@NonNull Set<Object> allMatchFeatures) {
176
176
private val userInfoData = MutableLiveData <UserInfo >()
177
177
178
178
// 在adapter里监听数据变化
179
- diffAdapter.addUpdateMediator(userInfoData, object : UpdateFunction <UserInfo , ItemViewData > {
179
+ diffAdapter.addUpdateMediator(userInfoData, object : UpdatePayloadFunction <UserInfo , ItemViewData > {
180
180
override fun providerMatchFeature (input : UserInfo ): Any {
181
181
return input.uid
182
182
}
183
183
184
- override fun applyChange (input : UserInfo , originalData : ItemViewData ): ItemViewData {
184
+ override fun applyChange (input : UserInfo , originalData : ItemViewData ,, payloadKeys : MutableSet < String > ): ItemViewData {
185
185
186
186
return originalData.userInfo = input
187
187
@@ -194,17 +194,16 @@ fun asyncDataFetch(userInfo : UserInfo) {
194
194
}
195
195
196
196
```
197
- 这样当asyncDataFetch接收到数据变化的通知的时候,改变userInfoData的值,adapter里对应的Item就会更新。其中找到adapter中需要更新的Item是关键部分,主要由实现` UpdateFunction ` 来完成,实现` UpdateFunction ` 也很简单。
197
+ 这样当asyncDataFetch接收到数据变化的通知的时候,改变userInfoData的值,adapter里对应的Item就会更新。其中找到adapter中需要更新的Item是关键部分,主要由实现` UpdatePayloadFunction ` 来完成,实现` UpdatePayloadFunction ` 也很简单。
198
198
199
199
``` java
200
- interface UpdateFunction <I,R extends BaseMutableData > {
200
+ public abstract class UpdatePayloadFunction <I, R extends BaseMutableData > implements UpdateFunction< I , R > {
201
201
202
202
/**
203
203
* 匹配所有数据,及返回类型为R的所有数据
204
204
*/
205
205
Object MATCH_ALL = new Object ();
206
206
207
-
208
207
/**
209
208
* 提供一个特征,用来查找列表数据中和此特征相同的数据
210
209
* @param input 用来提供查找数据和最终改变列表的数据 ,最终匹配的是allMatchFeatures里的数据,默认情况下就是uniqueItemFeature()
@@ -213,16 +212,23 @@ interface UpdateFunction<I,R extends BaseMutableData> {
213
212
Object providerMatchFeature (@NonNull I input );
214
213
215
214
/**
216
- * 匹配到对应的数据,如果符合条件的数据有很多个,可能会被回调多次
215
+ * 匹配到对应的数据,如果符合条件的数据有很多个,可能会被回调多次,不需要新建对象,主需要根据Input把originalData改变相应的值就行了
217
216
* @param input 是数据改变的部分数据源
218
217
* @param originalData 需要改变的数据项
219
- * @return 改变后的数据项
218
+ * @param payloadKeys 用来标识改变后的数据哪些部分发生了改变,if payloadKeys is not empty ,
219
+ * {@link com.silencedut.diffadapter.holder.BaseDiffViewHolder#updatePartWithPayload(BaseMutableData, Bundle, int) }
220
+ * will be call rather than
221
+ * {@link com.silencedut.diffadapter.holder.BaseDiffViewHolder#updateItem(BaseMutableData, int) }
222
+ * @return 改变后的数据项,
223
+ *
220
224
*/
221
- R applyChange (@NonNull I input ,@NonNull R originalData );
225
+
226
+ public abstract R applyChange (@NonNull I input , @NonNull R originalData , @NonNull Set<String > payloadKeys );
222
227
223
228
}
224
229
```
225
- ` UpdateFunction ` 用来提供异步数据获取到后数据用来和列表中的数据匹配的规则和根据规则找到需要更改的对象后如果改变原对象,剩下的更新都由` diffadapter ` 来处理。如果符合条件的数据有很多个,` applyChange(@NonNull I input,@NonNull R originalData) ` 会被回调多次。如下时:
230
+ ` UpdatePayloadFunction ` 用来提供异步数据获取到后数据用来和列表中的数据匹配的规则和根据规则找到需要更改的对象后如果改变原对象,剩下的更新都由` diffadapter ` 来处理。如果符合条件的数据有很多个,` applyChange(@NonNull I input, @NonNull R originalData, @NonNull Set<String> payloadKeys) ` 会被回调多次。
231
+ 如下时:
226
232
227
233
``` java
228
234
Object providerMatchFeature(@NonNull I input) {
@@ -233,9 +239,15 @@ Object providerMatchFeature(@NonNull I input) {
233
239
234
240
如果同一种匹配规则` providerMatchFeature ` 对应多种Holder类型,` UpdateFunction<I,R> ` 的返回数据类型R就可以直接设为基类的` BaseMutableData ` ,然后再applyChange里在具体根据类型来处理不同的UI。
235
241
242
+ ` UpdateFunction ` 已废弃,` payloadKeys ` 可以用来解决payload方式更新item时每次需要new对象的问题。
243
+
236
244
### 最高效的Item局部更新方式 —— payload
237
245
238
- DiffUtil 能让一个列表中只更新部分变化的Item,payload能让同一个Item只更新需要变化的View,这种方式非常适合同一个Item有多个异步数据源的,同时又对性能有更高要求的列表。
246
+ DiffUtil 能让一个列表中只更新部分数据变化的Item,payload能让同一个Item只更新需要变化的View,这种方式非常适合同一个Item有多个异步数据源的,同时又对性能有更高要求的列表。看具体更新需求来判断是否有必要。
247
+
248
+ 有两种情况的局部更新
249
+
250
+ ** 第一种是全量数据对比的情况,也就是同一个业务可能会多次调用` diffadapter.setData(List) ` ,可使用如下的方式**
239
251
240
252
** Step 1:重写BaseMutableData的appendDiffPayload**
241
253
@@ -250,40 +262,81 @@ data class ItemViewData(var uid:Long, var userInfo: UserInfo?, var anyOtherData:
250
262
.. .
251
263
252
264
/* *
253
- * 最高效的更新方式,如果不是频繁更新的可以不实现这个方法
265
+ * 最高效的更新方式,如果不是全量频繁更新的可以不实现这个方法
254
266
*/
255
- override fun appendDiffPayload (newData : ItemViewData , diffPayloadBundle : Bundle ) {
256
- super .appendDiffPayload (newData, diffPayloadBundle )
257
- if (this .userInfo!= newData.userInfo) {
258
- diffPayloadBundle.putString( KEY_BASE_INFO , KEY_BASE_INFO )
267
+ override fun appendPayloadKeys (newData : LegendViewData , payloadKeys : MutableSet < String > ) {
268
+ super .appendPayloadKeys (newData, payloadKeys )
269
+ if (this .userInfo!= newData.userInfo) {
270
+ payloadKeys.add( KEY_BASE_INFO )
259
271
}
260
272
if (this .anyData != newData.anyData) {
261
- diffPayloadBundle.putString(KEY_ANY , KEY_ANY )
273
+ payloadKeys.add(KEY_ANY )
274
+
262
275
}
263
- .. .
276
+ .. .
264
277
}
278
+
265
279
}
266
280
```
267
281
268
282
默认用Bundle存取变化,无需存具体的数据,只需类似设置标志位,表明Item的哪部分数据发生了变化。
269
283
284
+ ** 第二种是异步动态更新一个Item的时候,比如个人资料获取,中途单个Item数据变化的情况,可使用如下的Step1**
285
+
286
+ ``` java
287
+ public R applyChange(@NonNull I input, @NonNull R originalData, @NonNull Set<String > payloadKeys){
288
+ ...
289
+ originalData. *** = input. ***
290
+ payloadKeys. add(" 自定义String类型的Key值" )
291
+ ...
292
+ }
293
+ ```
294
+ 这两种方式不是互斥的,但也没什么关联,也可以根据自己的业务场景自行选择,如果不需要payload更新,两种方式都不需要。后续的步骤两种方式相同。
295
+
270
296
** Step 2 :需要重写BaseDiffViewHolder里的` updatePartWithPayload ` **
271
297
272
298
``` kotlin
273
299
class ItemViewHolder (itemViewRoot : View , recyclerAdapter : DiffAdapter ): BaseDiffViewHolder<ItemViewData>( itemViewRoot, recyclerAdapter){
274
300
275
- override fun updatePartWithPayload (data : ItemViewData , payload : Bundle , position : Int ) {
301
+ override fun updatePartWithPayload (data : ItemViewData , payloadKeys : MutableSet < String > , position : Int ) {
276
302
277
- if (payload.getString (ItemViewData .KEY_BASE_INFO )!= null ) {
303
+ if (payloadKeys.contains (ItemViewData .KEY_BASE_INFO )) {
278
304
updateBaseInfo(data)
279
305
}
280
306
281
- if (payload.getString (ItemViewData .KEY_ANY )!= null ) {
307
+ if (payloadKeys.contains (ItemViewData .KEY_ANY )) {
282
308
updateAnyView(data)
283
309
}
284
310
}
285
311
```
286
- 根据变化的标志位,更新Item 中需要变化部分的View
312
+
313
+ ** Step 3 : 监听数据变化,更新列表,这个只是异步数据更新Item 需要也就是第二种场景,如果每次`diffadapter.setData(List )`的数据已经是是有所有的数据信息,不需要以下的动态更新方案**
314
+
315
+ ```kotlin
316
+ // 用于监听请求的异步数据,userInfoData变化时与此相关的数据
317
+ private val userInfoData = MutableLiveData <UserInfo >()
318
+
319
+ // 在adapter里监听数据变化
320
+ diffAdapter.addUpdateMediator(userInfoData, object : UpdateFunction <UserInfo , ItemViewData > {
321
+ override fun providerMatchFeature (input : UserInfo ): Any {
322
+ return input.uid
323
+ }
324
+
325
+ override fun applyChange (@NonNull I input, @NonNull R originalData, @NonNull Set <String > payloadKeys): ItemViewData {
326
+ // 不再需要新建对象
327
+ originalData.*** = input.***
328
+ payloadKeys.add(" 自定义String类型的Key值" )
329
+ return originalData
330
+
331
+ }
332
+ })
333
+
334
+ // 任何通知数据获取到的通知
335
+ fun asyncDataFetch (userInfo : UserInfo ) {
336
+ userInfoData.value = userInfo
337
+ }
338
+ ```
339
+
287
340
288
341
## More
289
342
0 commit comments