blob: 5b75346f1eeb5bbd8b20a2cc62c1da2969194851 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.taobao.weex.ui.component.list.template;
import android.support.v4.util.ArrayMap;
import android.text.TextUtils;
import com.alibaba.fastjson.JSONArray;
import com.taobao.weex.WXEnvironment;
import com.taobao.weex.bridge.WXBridgeManager;
import com.taobao.weex.utils.WXUtils;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* Created by furture on 2018/1/23.
* template data manager, manage data and render state
*/
public class CellDataManager {
private static final String VIRTUAL_COMPONENT_SEPRATOR = "@";
public static final String SUB_COMPONENT_TEMPLATE_ID = "@templateId";
public static final String VIRTUAL_COMPONENT_ID = "@virtualComponentId";
/**
* template list data, update should vis data manager interface, this field is read only
* */
JSONArray listData;
/**
* current template list
* */
public final WXRecyclerTemplateList templateList;
/**
* data render state for position, itemId、dirty、and other info
* */
private Map<Integer, CellRenderState> renderStates = new ArrayMap<>();
/**
* list virtual component data, rendet state
* key virtual component id, value is cell render state.
* */
private Map<String, CellRenderState> virtualComponentRenderStates;
/**
* template list data manager
* */
public CellDataManager(WXRecyclerTemplateList templateList) {
this.templateList = templateList;
}
/**
* get current render state for current position, never return null.
* */
public CellRenderState getRenderState(int position){
CellRenderState renderState = renderStates.get(position);
if(renderState == null){
renderState = new CellRenderState();
renderState.position = position;
renderStates.put(position, renderState);
}
if(position != renderState.position) {
renderState.position = position;
renderState.hasPositionChange = true;
}
return renderState;
}
/**
* @param virutalComponentId virutalComponentId
* @param data update virutalComponent's data
* update virtual component data
* */
public void updateVirtualComponentData(String virutalComponentId, Object data){
if(virtualComponentRenderStates != null){
CellRenderState cellRenderState = virtualComponentRenderStates.get(virutalComponentId);
if(cellRenderState != null){
cellRenderState.getVirtualComponentDatas().put(virutalComponentId, data);
cellRenderState.hasVirtualCompoentUpdate = true;
}else{
if(WXEnvironment.isApkDebugable()) {
throw new IllegalArgumentException("virtualComponentDatas illegal state empty render state" + virutalComponentId);
}
}
}else{
if(WXEnvironment.isApkDebugable()){
throw new IllegalArgumentException("virtualComponentDatas illegal state " + virutalComponentId);
}
}
}
/**
* @param position current position virtual component
* @param virutalComponentId virutalComponentId
* @param data update virutalComponent's data
* create virtual component data
* */
public void createVirtualComponentData(int position, String virutalComponentId, Object data){
if(virtualComponentRenderStates == null){
virtualComponentRenderStates = new HashMap<>(8);
}
CellRenderState renderState = renderStates.get(position);
renderState.getVirtualComponentDatas().put(virutalComponentId, data);
virtualComponentRenderStates.put(virutalComponentId, renderState);
}
/**
* @param listData setList data
* clear render state for current cell, and virtual component data
* */
public void setListData(JSONArray listData) {
if(this.listData != listData) {
if(this.listData != null){
if(WXUtils.getBoolean(templateList.getAttrs().get("exitDetach"), true)){
for(int i=0; i<this.listData.size(); i++){
cleanRenderState(renderStates.remove(i));
}
}
}
this.listData = listData;
renderStates.clear();
if (virtualComponentRenderStates != null) {
virtualComponentRenderStates.clear();
}
}
}
/**
* @param index insert index
* @param data data object
* insert data at current index
* */
public boolean insertData(int index, Object data){
listData.add(index, data);
boolean renderStateChange = false;
for(int i=listData.size(); i>= index; i--){
CellRenderState state = renderStates.remove(i);
if(state != null){
renderStates.put(i + 1, state);
renderStateChange = true;
}
}
return renderStateChange;
}
/**
*
* @param index insert index
* @param data data object
* insert data at current index
* */
public boolean insertRange(int index, JSONArray data){
listData.addAll(index, data);
boolean renderStateChange = false;
for(int i = listData.size()-1; i >= index; i--){
CellRenderState state = renderStates.remove(i);
if(state != null){
renderStates.put(i + 1, state);
renderStateChange = true;
}
}
return renderStateChange;
}
/**
* @param data data object
* @param index insert index
* update data, reset new render state,
* return true if only data changed, false if viewType changed
* */
public boolean updateData(Object data, int index){
boolean onlyDataChange = TextUtils.equals(templateList.getTemplateKey(index), templateList.getTemplateKey(data));
listData.set(index, data);
if(!onlyDataChange){
//structure changed, reset render state
cleanRenderState(renderStates.remove(index));
}else{
CellRenderState renderState = renderStates.get(index);
if(renderState != null){
renderState.hasDataUpdate = true;
}
}
return onlyDataChange;
}
/**
* @param index
* remove data, and its render state and virtual's data
* */
public void removeData(Integer index){
listData.remove((int)index); //remove by index
cleanRenderState(renderStates.remove(index));
int count = listData.size() + 1;
for(int i=index + 1; i < count; i++){
CellRenderState state = renderStates.remove(i);
if(state != null){
renderStates.put(i-1, state);
}
}
}
/**
* clean render state, if has virtual component, call virtual component detach lifecycle
* */
private void cleanRenderState(CellRenderState renderState){
if(renderState == null){
return;
}
if(renderState.hasVirtualComponents()){
Collection<String> virtualComponentIds = renderState.getVirtualComponentIds().values();
for(String virtualComponentId : virtualComponentIds){
if(virtualComponentRenderStates != null){
virtualComponentRenderStates.remove(virtualComponentId);
}
WXBridgeManager.getInstance().asyncCallJSEventVoidResult(WXBridgeManager.METHD_COMPONENT_HOOK_SYNC,
templateList.getInstanceId(),
null,
virtualComponentId, VirtualComponentLifecycle.LIFECYCLE, VirtualComponentLifecycle.DETACH, null);
}
}
}
/**
* create virtualComponentId
* */
public static String createVirtualComponentId(String listRef, String viewTreeKey, long itemId){
return listRef + VIRTUAL_COMPONENT_SEPRATOR + viewTreeKey + VIRTUAL_COMPONENT_SEPRATOR + itemId;
}
/**
* get list ref from virtualComponentId
* */
public static String getListRef(String virtualComponentId){
if(virtualComponentId == null){
return null;
}
return virtualComponentId.split(VIRTUAL_COMPONENT_SEPRATOR)[0];
}
}