| /** |
| * 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 org.apache.weex.ui.component.list.template; |
| |
| |
| import android.support.v4.util.ArrayMap; |
| import android.text.TextUtils; |
| |
| import com.alibaba.fastjson.JSONArray; |
| import org.apache.weex.WXEnvironment; |
| import org.apache.weex.bridge.WXBridgeManager; |
| import org.apache.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]; |
| } |
| |
| } |