| /* |
| * 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; |
| |
| import static com.taobao.weex.http.WXHttpUtil.KEY_USER_AGENT; |
| |
| import android.app.AlertDialog; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.graphics.Color; |
| import android.graphics.Paint; |
| import android.net.Uri; |
| import android.os.Message; |
| import android.support.annotation.NonNull; |
| import android.support.annotation.Nullable; |
| import android.support.annotation.RestrictTo; |
| import android.support.annotation.RestrictTo.Scope; |
| import android.text.TextUtils; |
| import android.util.Log; |
| import android.view.Menu; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.widget.ScrollView; |
| import com.alibaba.fastjson.JSONObject; |
| import com.taobao.weex.adapter.IDrawableLoader; |
| import com.taobao.weex.adapter.IWXHttpAdapter; |
| import com.taobao.weex.adapter.IWXImgLoaderAdapter; |
| import com.taobao.weex.adapter.IWXUserTrackAdapter; |
| import com.taobao.weex.adapter.URIAdapter; |
| import com.taobao.weex.appfram.websocket.IWebSocketAdapter; |
| import com.taobao.weex.bridge.NativeInvokeHelper; |
| import com.taobao.weex.bridge.SimpleJSCallback; |
| import com.taobao.weex.bridge.WXBridgeManager; |
| import com.taobao.weex.bridge.WXModuleManager; |
| import com.taobao.weex.common.Constants; |
| import com.taobao.weex.common.Destroyable; |
| import com.taobao.weex.common.IWXDebugProxy; |
| import com.taobao.weex.common.OnWXScrollListener; |
| import com.taobao.weex.common.WXErrorCode; |
| import com.taobao.weex.common.WXModule; |
| import com.taobao.weex.common.WXPerformance; |
| import com.taobao.weex.common.WXRefreshData; |
| import com.taobao.weex.common.WXRenderStrategy; |
| import com.taobao.weex.common.WXRequest; |
| import com.taobao.weex.common.WXResponse; |
| import com.taobao.weex.dom.DomContext; |
| import com.taobao.weex.dom.WXDomHandler; |
| import com.taobao.weex.dom.WXDomObject; |
| import com.taobao.weex.dom.WXDomTask; |
| import com.taobao.weex.dom.WXEvent; |
| import com.taobao.weex.http.WXHttpUtil; |
| import com.taobao.weex.tracing.WXTracing; |
| import com.taobao.weex.ui.component.NestedContainer; |
| import com.taobao.weex.ui.component.WXBasicComponentType; |
| import com.taobao.weex.ui.component.WXComponent; |
| import com.taobao.weex.ui.component.WXComponentFactory; |
| import com.taobao.weex.ui.flat.FlatGUIContext; |
| import com.taobao.weex.ui.view.WXScrollView; |
| import com.taobao.weex.ui.view.WXScrollView.WXScrollViewListener; |
| import com.taobao.weex.utils.Trace; |
| import com.taobao.weex.utils.WXFileUtils; |
| import com.taobao.weex.utils.WXJsonUtils; |
| import com.taobao.weex.utils.WXLogUtils; |
| import com.taobao.weex.utils.WXReflectionUtils; |
| import com.taobao.weex.utils.WXViewUtils; |
| import java.io.Serializable; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.ConcurrentHashMap; |
| |
| /** |
| * Each instance of WXSDKInstance represents an running weex instance. |
| * It can be a pure weex view, or mixed with native view |
| */ |
| public class WXSDKInstance implements IWXActivityStateListener,DomContext, View.OnLayoutChangeListener { |
| |
| //Performance |
| public boolean mEnd = false; |
| public static final String BUNDLE_URL = "bundleUrl"; |
| private IWXUserTrackAdapter mUserTrackAdapter; |
| private IWXRenderListener mRenderListener; |
| private IWXStatisticsListener mStatisticsListener; |
| /** package **/ Context mContext; |
| private final String mInstanceId; |
| private RenderContainer mRenderContainer; |
| private WXComponent mRootComp; |
| private boolean mRendered; |
| private WXRefreshData mLastRefreshData; |
| private NestedInstanceInterceptor mNestedInstanceInterceptor; |
| private String mBundleUrl = ""; |
| private boolean isDestroy=false; |
| private Map<String,Serializable> mUserTrackParams; |
| private NativeInvokeHelper mNativeInvokeHelper; |
| private boolean isCommit=false; |
| private WXGlobalEventReceiver mGlobalEventReceiver=null; |
| private boolean trackComponent; |
| private boolean enableLayerType = true; |
| private boolean mNeedValidate = false; |
| private boolean mNeedReLoad = false; |
| private static volatile int mViewPortWidth = 750; |
| private int mInstanceViewPortWidth = 750; |
| private @NonNull |
| FlatGUIContext mFlatGUIContext =new FlatGUIContext(); |
| |
| public long mRenderStartNanos; |
| public int mExecJSTraceId = WXTracing.nextId(); |
| |
| /** |
| * Render strategy. |
| */ |
| private WXRenderStrategy mRenderStrategy = WXRenderStrategy.APPEND_ASYNC; |
| /** |
| * Render start time |
| */ |
| private long mRenderStartTime; |
| /** |
| * Refresh start time |
| */ |
| private long mRefreshStartTime; |
| private WXPerformance mWXPerformance; |
| private ScrollView mScrollView; |
| private WXScrollViewListener mWXScrollViewListener; |
| |
| private List<OnWXScrollListener> mWXScrollListeners; |
| |
| /** |
| * whether we are in preRender mode |
| * */ |
| private volatile boolean isPreRenderMode; |
| |
| private LayoutFinishListener mLayoutFinishListener; |
| |
| private boolean mCurrentGround = false; |
| private ComponentObserver mComponentObserver; |
| |
| /** |
| * If anchor is created manually(etc. define a layout xml resource ), |
| * be aware do not add it to twice when {@link IWXRenderListener#onViewCreated(WXSDKInstance, View)}. |
| * @param a |
| */ |
| public void setRenderContainer(RenderContainer a){ |
| if(a != null) { |
| a.setSDKInstance(this); |
| a.addOnLayoutChangeListener(this); |
| } |
| mRenderContainer = a; |
| } |
| |
| |
| |
| private int mMaxDeepLayer; |
| |
| public boolean isTrackComponent() { |
| return trackComponent; |
| } |
| |
| public void setTrackComponent(boolean trackComponent) { |
| this.trackComponent = trackComponent; |
| } |
| |
| /** |
| * Tell whether it is enabled to change the layerType |
| * {@link android.view.View#setLayerType(int, Paint)} |
| * @return True for enable to change the layerType of component, false otherwise. The default |
| * is True |
| */ |
| public boolean isLayerTypeEnabled() { |
| return enableLayerType; |
| } |
| |
| /** |
| * Enable the ability of changing layerType. e.g. {@link android.view.View#setLayerType(int, Paint)} |
| * Disable the ability of changing layerType will have tremendous <strong>performance |
| * punishment</strong>. |
| * |
| * <strong>Do not</strong> set this to false unless you know exactly what you are doing. |
| * @param enable True for enable to change the layerType of component, false otherwise. The default |
| * is True |
| */ |
| public void enableLayerType(boolean enable) { |
| enableLayerType = enable; |
| } |
| |
| @RestrictTo(Scope.LIBRARY) |
| public @NonNull |
| FlatGUIContext getFlatUIContext(){ |
| return mFlatGUIContext; |
| } |
| |
| public boolean isNeedValidate() { |
| return mNeedValidate; |
| } |
| |
| public boolean isNeedReLoad() { |
| return mNeedReLoad; |
| } |
| |
| public void setNeedLoad(boolean load) { |
| mNeedReLoad = load; |
| } |
| /* |
| * Warning: use setInstanceViewPortWidth instead. |
| * store custom ViewPort Width |
| */ |
| @Deprecated |
| public void setViewPortWidth(int viewPortWidth) { |
| mViewPortWidth = viewPortWidth; |
| } |
| |
| /** |
| * Warning: use getInstanceViewPortWidth instead. |
| * @return |
| */ |
| @Deprecated |
| public static int getViewPortWidth() { |
| return mViewPortWidth; |
| } |
| |
| public void setInstanceViewPortWidth(int instanceViewPortWidth) { |
| this.mInstanceViewPortWidth = instanceViewPortWidth; |
| } |
| |
| public int getInstanceViewPortWidth(){ |
| return mInstanceViewPortWidth; |
| } |
| |
| public interface OnInstanceVisibleListener{ |
| void onAppear(); |
| void onDisappear(); |
| } |
| private List<OnInstanceVisibleListener> mVisibleListeners = new ArrayList<>(); |
| |
| public WXSDKInstance(Context context) { |
| mInstanceId = WXSDKManager.getInstance().generateInstanceId(); |
| init(context); |
| } |
| |
| /** |
| * For unittest only. |
| */ |
| @RestrictTo(Scope.TESTS) |
| WXSDKInstance(Context context,String id) { |
| mInstanceId = id; |
| init(context); |
| } |
| |
| |
| public WXComponent getRootComponent() { |
| return mRootComp; |
| } |
| |
| public void setNestedInstanceInterceptor(NestedInstanceInterceptor interceptor){ |
| mNestedInstanceInterceptor = interceptor; |
| } |
| |
| public final WXSDKInstance createNestedInstance(NestedContainer container){ |
| WXSDKInstance sdkInstance = newNestedInstance(); |
| if(mNestedInstanceInterceptor != null){ |
| mNestedInstanceInterceptor.onCreateNestInstance(sdkInstance,container); |
| } |
| return sdkInstance; |
| } |
| |
| protected WXSDKInstance newNestedInstance() { |
| return new WXSDKInstance(mContext); |
| } |
| |
| public void addOnInstanceVisibleListener(OnInstanceVisibleListener l){ |
| mVisibleListeners.add(l); |
| } |
| |
| public void removeOnInstanceVisibleListener(OnInstanceVisibleListener l){ |
| mVisibleListeners.remove(l); |
| } |
| |
| public void init(Context context) { |
| mContext = context; |
| mNativeInvokeHelper = new NativeInvokeHelper(mInstanceId); |
| |
| mWXPerformance = new WXPerformance(); |
| mWXPerformance.WXSDKVersion = WXEnvironment.WXSDK_VERSION; |
| mWXPerformance.JSLibInitTime = WXEnvironment.sJSLibInitTime; |
| |
| mUserTrackAdapter=WXSDKManager.getInstance().getIWXUserTrackAdapter(); |
| } |
| |
| /** |
| * Set a Observer for component. |
| * This observer will be called in each component, should not doing |
| * anything will impact render performance. |
| * |
| * @param observer |
| */ |
| public void setComponentObserver(ComponentObserver observer){ |
| mComponentObserver = observer; |
| } |
| |
| public ComponentObserver getComponentObserver(){ |
| return mComponentObserver; |
| } |
| |
| public NativeInvokeHelper getNativeInvokeHelper() { |
| return mNativeInvokeHelper; |
| } |
| |
| public void setBizType(String bizType) { |
| if (!TextUtils.isEmpty(bizType)) { |
| mWXPerformance.bizType = bizType; |
| } |
| } |
| |
| public ScrollView getScrollView() { |
| return mScrollView; |
| } |
| |
| public void setRootScrollView(ScrollView scrollView) { |
| mScrollView = scrollView; |
| if (mWXScrollViewListener != null) { |
| ((WXScrollView) mScrollView).addScrollViewListener(mWXScrollViewListener); |
| } |
| } |
| |
| @Deprecated |
| public void registerScrollViewListener(WXScrollViewListener scrollViewListener) { |
| mWXScrollViewListener = scrollViewListener; |
| } |
| |
| @Deprecated |
| public WXScrollViewListener getScrollViewListener() { |
| return mWXScrollViewListener; |
| } |
| |
| @Deprecated |
| public void setIWXUserTrackAdapter(IWXUserTrackAdapter adapter) { |
| } |
| |
| /** |
| * Render template asynchronously, use {@link WXRenderStrategy#APPEND_ASYNC} as render strategy |
| * @param template bundle js |
| * @param options os iphone/android/ipad |
| * weexversion Weex version(like 1.0.0) |
| * appversion App version(like 1.0.0) |
| * devid Device id(like Aqh9z8dRJNBhmS9drLG5BKCmXhecHUXIZoXOctKwFebH) |
| * sysversion Device system version(like 5.4.4、7.0.4, should be used with os) |
| * sysmodel Device model(like iOS:"MGA82J/A", android:"MI NOTE LTE") |
| * Time UNIX timestamp, UTC+08:00 |
| * TTID(Optional) |
| * MarkertId |
| * Appname(Optional) tm,tb,qa |
| * Bundleurl(Optional) template url |
| * @param jsonInitData Initial data for rendering |
| */ |
| public void render(String template, Map<String, Object> options, String jsonInitData) { |
| render(template, options, jsonInitData, WXRenderStrategy.APPEND_ASYNC); |
| } |
| |
| /** |
| * Render template asynchronously |
| * @param template bundle js |
| * @param options os iphone/android/ipad |
| * weexversion Weex version(like 1.0.0) |
| * appversion App version(like 1.0.0) |
| * devid Device id(like Aqh9z8dRJNBhmS9drLG5BKCmXhecHUXIZoXOctKwFebH) |
| * sysversion Device system version(like 5.4.4、7.0.4, should be used with os) |
| * sysmodel Device model(like iOS:"MGA82J/A", android:"MI NOTE LTE") |
| * Time UNIX timestamp, UTC+08:00 |
| * TTID(Optional) |
| * MarkertId |
| * Appname(Optional) tm,tb,qa |
| * Bundleurl(Optional) template url |
| * @param jsonInitData Initial data for rendering |
| * @param flag RenderStrategy {@link WXRenderStrategy} |
| */ |
| @Deprecated |
| public void render(String template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag) { |
| render(WXPerformance.DEFAULT, template, options, jsonInitData, flag); |
| } |
| |
| /** |
| * Render template asynchronously |
| * |
| * @param pageName, used for performance log. |
| * @param template bundle js |
| * @param options os iphone/android/ipad |
| * weexversion Weex version(like 1.0.0) |
| * appversion App version(like 1.0.0) |
| * devid Device id(like Aqh9z8dRJNBhmS9drLG5BKCmXhecHUXIZoXOctKwFebH) |
| * sysversion Device system version(like 5.4.4、7.0.4, should be used with os) |
| * sysmodel Device model(like iOS:"MGA82J/A", android:"MI NOTE LTE") |
| * Time UNIX timestamp, UTC+08:00 |
| * TTID(Optional) |
| * MarkertId |
| * Appname(Optional) tm,tb,qa |
| * Bundleurl(Optional) template url |
| * @param jsonInitData Initial data for rendering |
| * @param flag RenderStrategy {@link WXRenderStrategy} |
| */ |
| public void render(String pageName, String template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag) { |
| if(WXEnvironment.isApkDebugable() && WXPerformance.DEFAULT.equals(pageName)){ |
| WXLogUtils.e("WXSDKInstance", "Please set your pageName or your js bundle url !!!!!!!"); |
| |
| if (getUIContext() != null) { |
| new AlertDialog.Builder(getUIContext()) |
| .setTitle("Error: Missing pageName") |
| .setMessage("We highly recommend you to set pageName. Call" + |
| "\nWXSDKInstance#render(String pageName, String template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag)\n" + |
| "to fix it.") |
| .show(); |
| } |
| |
| return; |
| } |
| renderInternal(pageName,template,options,jsonInitData,flag); |
| } |
| |
| private void ensureRenderArchor(){ |
| if(mRenderContainer == null){ |
| if (getContext() != null) { |
| mRenderContainer = new RenderContainer(getContext()); |
| mRenderContainer.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); |
| mRenderContainer.setBackgroundColor(Color.TRANSPARENT); |
| mRenderContainer.setSDKInstance(this); |
| mRenderContainer.addOnLayoutChangeListener(this); |
| } |
| } |
| } |
| |
| private void renderInternal(String pageName, |
| String template, |
| Map<String, Object> options, |
| String jsonInitData, |
| WXRenderStrategy flag){ |
| if (mRendered || TextUtils.isEmpty(template)) { |
| return; |
| } |
| |
| WXLogUtils.d("WXSDKInstance", "Start render page: " + pageName); |
| |
| if (WXTracing.isAvailable()) { |
| WXTracing.TraceEvent traceEvent = WXTracing.newEvent("executeBundleJS", mInstanceId, -1); |
| traceEvent.traceId = mExecJSTraceId; |
| traceEvent.iid = mInstanceId; |
| traceEvent.tname = "JSThread"; |
| traceEvent.ph = "B"; |
| traceEvent.submit(); |
| mRenderStartNanos = System.nanoTime(); |
| } |
| |
| ensureRenderArchor(); |
| |
| Map<String, Object> renderOptions = options; |
| if (renderOptions == null) { |
| renderOptions = new HashMap<>(); |
| } |
| |
| if (WXEnvironment.sDynamicMode && !TextUtils.isEmpty(WXEnvironment.sDynamicUrl) && renderOptions.get("dynamicMode") == null) { |
| renderOptions.put("dynamicMode", "true"); |
| renderByUrl(pageName, WXEnvironment.sDynamicUrl, renderOptions, jsonInitData, flag); |
| return; |
| } |
| |
| mWXPerformance.pageName = pageName; |
| mWXPerformance.JSTemplateSize = template.length() / 1024f; |
| |
| mRenderStartTime = System.currentTimeMillis(); |
| mRenderStrategy = flag; |
| |
| WXSDKManager.getInstance().setCrashInfo(WXEnvironment.WEEX_CURRENT_KEY,pageName); |
| |
| WXSDKManager.getInstance().createInstance(this, template, renderOptions, jsonInitData); |
| mRendered = true; |
| |
| if (TextUtils.isEmpty(mBundleUrl)) { |
| mBundleUrl = pageName; |
| } |
| } |
| |
| private void renderByUrlInternal(String pageName, |
| final String url, |
| Map<String, Object> options, |
| final String jsonInitData, |
| final WXRenderStrategy flag) { |
| |
| ensureRenderArchor(); |
| pageName = wrapPageName(pageName, url); |
| mBundleUrl = url; |
| if(WXSDKManager.getInstance().getValidateProcessor()!=null) { |
| mNeedValidate = WXSDKManager.getInstance().getValidateProcessor().needValidate(mBundleUrl); |
| } |
| |
| Map<String, Object> renderOptions = options; |
| if (renderOptions == null) { |
| renderOptions = new HashMap<>(); |
| } |
| if (!renderOptions.containsKey(BUNDLE_URL)) { |
| renderOptions.put(BUNDLE_URL, url); |
| } |
| |
| Uri uri = Uri.parse(url); |
| if (uri != null && TextUtils.equals(uri.getScheme(), "file")) { |
| render(pageName, WXFileUtils.loadFileOrAsset(assembleFilePath(uri), mContext), renderOptions, jsonInitData, flag); |
| return; |
| } |
| |
| IWXHttpAdapter adapter = WXSDKManager.getInstance().getIWXHttpAdapter(); |
| |
| WXRequest wxRequest = new WXRequest(); |
| wxRequest.url = rewriteUri(Uri.parse(url),URIAdapter.BUNDLE).toString(); |
| if (wxRequest.paramMap == null) { |
| wxRequest.paramMap = new HashMap<String, String>(); |
| } |
| wxRequest.paramMap.put(KEY_USER_AGENT, WXHttpUtil.assembleUserAgent(mContext,WXEnvironment.getConfig())); |
| WXHttpListener httpListener = |
| new WXHttpListener(pageName, renderOptions, jsonInitData, flag, System.currentTimeMillis()); |
| httpListener.setSDKInstance(this); |
| adapter.sendRequest(wxRequest, (IWXHttpAdapter.OnHttpListener) httpListener); |
| } |
| |
| /** |
| * Use {@link #render(String, String, Map, String, WXRenderStrategy)} instead. |
| * @param pageName |
| * @param template |
| * @param options |
| * @param jsonInitData |
| * @param width |
| * @param height |
| * @param flag |
| */ |
| @Deprecated |
| public void render(String pageName, String template, Map<String, Object> options, String jsonInitData, int width, int height, WXRenderStrategy flag) { |
| render(pageName,template,options,jsonInitData,flag); |
| } |
| |
| /** |
| * Render template asynchronously, use {@link WXRenderStrategy#APPEND_ASYNC} as render strategy |
| * @param template bundle js |
| */ |
| public void render(String template) { |
| render(WXPerformance.DEFAULT, template, null, null, mRenderStrategy); |
| } |
| |
| /** |
| * Use {@link #render(String)} instead. |
| * @param template |
| * @param width |
| * @param height |
| */ |
| @Deprecated |
| public void render(String template, int width, int height) { |
| render(template); |
| } |
| |
| /** |
| * Use {@link #renderByUrl(String, String, Map, String, WXRenderStrategy)} instead. |
| * @param pageName |
| * @param url |
| * @param options |
| * @param jsonInitData |
| * @param width |
| * @param height |
| * @param flag |
| */ |
| @Deprecated |
| public void renderByUrl(String pageName, final String url, Map<String, Object> options, final String jsonInitData, final int width, final int height, final WXRenderStrategy flag){ |
| renderByUrl(pageName,url,options,jsonInitData,flag); |
| } |
| |
| public void renderByUrl(String pageName, final String url, Map<String, Object> options, final String jsonInitData, final WXRenderStrategy flag) { |
| renderByUrlInternal(pageName,url,options,jsonInitData,flag); |
| } |
| |
| private String wrapPageName(String pageName, String url) { |
| if(TextUtils.equals(pageName, WXPerformance.DEFAULT)){ |
| pageName=url; |
| try { |
| Uri uri=Uri.parse(url); |
| if(uri!=null){ |
| Uri.Builder builder=new Uri.Builder(); |
| builder.scheme(uri.getScheme()); |
| builder.authority(uri.getAuthority()); |
| builder.path(uri.getPath()); |
| pageName=builder.toString(); |
| } |
| } catch (Exception e) { |
| } |
| } |
| return pageName; |
| } |
| |
| private String assembleFilePath(Uri uri) { |
| if(uri!=null && uri.getPath()!=null){ |
| return uri.getPath().replaceFirst("/",""); |
| } |
| return ""; |
| } |
| |
| public void reloadPage(boolean reloadThis) { |
| |
| WXSDKEngine.reload(); |
| |
| if (reloadThis) { |
| // 可以发送广播吗? |
| if (mContext != null) { |
| Intent intent = new Intent(); |
| intent.setAction(IWXDebugProxy.ACTION_INSTANCE_RELOAD); |
| intent.putExtra("url", mBundleUrl); |
| mContext.sendBroadcast(intent); |
| } |
| // mRendered = false; |
| // destroy(); |
| // renderInternal(mPackage, mTemplate, mOptions, mJsonInitData, mFlag); |
| // refreshInstance("{}"); |
| } |
| } |
| /** |
| * Refresh instance asynchronously. |
| * @param data the new data |
| */ |
| public void refreshInstance(Map<String, Object> data) { |
| if (data == null) { |
| return; |
| } |
| refreshInstance(WXJsonUtils.fromObjectToJSONString(data)); |
| } |
| |
| /** |
| * Refresh instance asynchronously. |
| * @param jsonData the new data |
| */ |
| public void refreshInstance(String jsonData) { |
| if (jsonData == null) { |
| return; |
| } |
| mRefreshStartTime = System.currentTimeMillis(); |
| //cancel last refresh message |
| if (mLastRefreshData != null) { |
| mLastRefreshData.isDirty = true; |
| } |
| |
| mLastRefreshData = new WXRefreshData(jsonData, false); |
| |
| WXSDKManager.getInstance().refreshInstance(mInstanceId, mLastRefreshData); |
| } |
| |
| public WXRenderStrategy getRenderStrategy() { |
| return mRenderStrategy; |
| } |
| |
| @Override |
| public Context getUIContext() { |
| return mContext; |
| } |
| |
| public String getInstanceId() { |
| return mInstanceId; |
| } |
| |
| public Context getContext() { |
| if(mContext == null){ |
| WXLogUtils.e("WXSdkInstance mContext == null"); |
| } |
| return mContext; |
| } |
| |
| public int getWeexHeight() { |
| return mRenderContainer == null ? 0: mRenderContainer.getHeight(); |
| } |
| |
| public int getWeexWidth() { |
| return mRenderContainer == null ? 0: mRenderContainer.getWidth(); |
| } |
| |
| |
| public IWXImgLoaderAdapter getImgLoaderAdapter() { |
| return WXSDKManager.getInstance().getIWXImgLoaderAdapter(); |
| } |
| |
| public IDrawableLoader getDrawableLoader() { |
| return WXSDKManager.getInstance().getDrawableLoader(); |
| } |
| |
| public URIAdapter getURIAdapter(){ |
| return WXSDKManager.getInstance().getURIAdapter(); |
| } |
| |
| public Uri rewriteUri(Uri uri,String type){ |
| return getURIAdapter().rewrite(this,type,uri); |
| } |
| |
| public IWXHttpAdapter getWXHttpAdapter() { |
| return WXSDKManager.getInstance().getIWXHttpAdapter(); |
| } |
| |
| public IWXStatisticsListener getWXStatisticsListener() { |
| return mStatisticsListener; |
| } |
| |
| public @Nullable |
| IWebSocketAdapter getWXWebSocketAdapter() { |
| return WXSDKManager.getInstance().getIWXWebSocketAdapter(); |
| } |
| |
| @Deprecated |
| public void reloadImages() { |
| if (mScrollView == null) { |
| return; |
| } |
| } |
| |
| |
| public boolean isPreRenderMode() { |
| return this.isPreRenderMode; |
| } |
| |
| public void setPreRenderMode(final boolean isPreRenderMode) { |
| WXSDKManager.getInstance().getWXRenderManager().postOnUiThread(new Runnable() { |
| @Override |
| public void run() { |
| WXSDKInstance.this.isPreRenderMode = isPreRenderMode; |
| } |
| },0); |
| } |
| |
| public void setContext(@NonNull Context context) { |
| this.mContext = context; |
| } |
| |
| /******************************** |
| * begin register listener |
| ********************************************************/ |
| public void registerRenderListener(IWXRenderListener listener) { |
| mRenderListener = listener; |
| } |
| |
| @Deprecated |
| public void registerActivityStateListener(IWXActivityStateListener listener) { |
| |
| } |
| |
| public void registerStatisticsListener(IWXStatisticsListener listener) { |
| mStatisticsListener = listener; |
| } |
| |
| public void setLayoutFinishListener(@Nullable LayoutFinishListener listener) { |
| this.mLayoutFinishListener = listener; |
| } |
| |
| public LayoutFinishListener getLayoutFinishListener() { |
| return this.mLayoutFinishListener; |
| } |
| |
| |
| /**set render start time*/ |
| public void setRenderStartTime(long renderStartTime) { |
| this.mRenderStartTime = renderStartTime; |
| } |
| |
| /******************************** |
| * end register listener |
| ********************************************************/ |
| |
| |
| /******************************** |
| * begin hook Activity life cycle callback |
| ********************************************************/ |
| |
| @Override |
| public void onActivityCreate() { |
| |
| // module listen Activity onActivityCreate |
| WXModuleManager.onActivityCreate(getInstanceId()); |
| |
| if(mRootComp != null) { |
| mRootComp.onActivityCreate(); |
| }else{ |
| WXLogUtils.w("Warning :Component tree has not build completely,onActivityCreate can not be call!"); |
| } |
| |
| mGlobalEventReceiver=new WXGlobalEventReceiver(this); |
| getContext().registerReceiver(mGlobalEventReceiver,new IntentFilter(WXGlobalEventReceiver.EVENT_ACTION)); |
| } |
| |
| @Override |
| public void onActivityStart() { |
| |
| // module listen Activity onActivityCreate |
| WXModuleManager.onActivityStart(getInstanceId()); |
| if(mRootComp != null) { |
| mRootComp.onActivityStart(); |
| }else{ |
| WXLogUtils.w("Warning :Component tree has not build completely,onActivityStart can not be call!"); |
| } |
| |
| } |
| |
| public boolean onCreateOptionsMenu(Menu menu) { |
| |
| WXModuleManager.onCreateOptionsMenu(getInstanceId(),menu); |
| if(mRootComp != null) { |
| mRootComp.onCreateOptionsMenu(menu); |
| }else{ |
| WXLogUtils.w("Warning :Component tree has not build completely,onActivityStart can not be call!"); |
| } |
| return true; |
| } |
| |
| |
| @Override |
| public void onActivityPause() { |
| onViewDisappear(); |
| if(!isCommit){ |
| Set<String> componentTypes= WXComponentFactory.getComponentTypesByInstanceId(getInstanceId()); |
| if(componentTypes!=null && componentTypes.contains(WXBasicComponentType.SCROLLER)){ |
| mWXPerformance.useScroller=1; |
| } |
| mWXPerformance.maxDeepViewLayer=getMaxDeepLayer(); |
| if (mUserTrackAdapter != null) { |
| mUserTrackAdapter.commit(mContext, null, IWXUserTrackAdapter.LOAD, mWXPerformance, getUserTrackParams()); |
| } |
| isCommit=true; |
| } |
| // module listen Activity onActivityPause |
| WXModuleManager.onActivityPause(getInstanceId()); |
| if(mRootComp != null) { |
| mRootComp.onActivityPause(); |
| }else{ |
| WXLogUtils.w("Warning :Component tree has not build completely,onActivityPause can not be call!"); |
| } |
| |
| WXLogUtils.i("Application onActivityPause()"); |
| if (!mCurrentGround) { |
| WXLogUtils.i("Application to be in the backround"); |
| Intent intent = new Intent(WXGlobalEventReceiver.EVENT_ACTION); |
| intent.putExtra(WXGlobalEventReceiver.EVENT_NAME, Constants.Event.PAUSE_EVENT); |
| intent.putExtra(WXGlobalEventReceiver.EVENT_WX_INSTANCEID, getInstanceId()); |
| mContext.sendBroadcast(intent); |
| this.mCurrentGround = true; |
| } |
| } |
| |
| |
| @Override |
| public void onActivityResume() { |
| |
| // notify onActivityResume callback to module |
| WXModuleManager.onActivityResume(getInstanceId()); |
| |
| if(mRootComp != null) { |
| mRootComp.onActivityResume(); |
| }else{ |
| WXLogUtils.w("Warning :Component tree has not build completely, onActivityResume can not be call!"); |
| } |
| |
| if (mCurrentGround) { |
| WXLogUtils.i("Application to be in the foreground"); |
| Intent intent = new Intent(WXGlobalEventReceiver.EVENT_ACTION); |
| intent.putExtra(WXGlobalEventReceiver.EVENT_NAME, Constants.Event.RESUME_EVENT); |
| intent.putExtra(WXGlobalEventReceiver.EVENT_WX_INSTANCEID, getInstanceId()); |
| mContext.sendBroadcast(intent); |
| mCurrentGround = false; |
| } |
| |
| onViewAppear(); |
| |
| setViewPortWidth(mInstanceViewPortWidth); |
| } |
| |
| @Override |
| public void onActivityStop() { |
| |
| // notify onActivityResume callback to module |
| WXModuleManager.onActivityStop(getInstanceId()); |
| |
| if(mRootComp != null) { |
| mRootComp.onActivityStop(); |
| }else{ |
| WXLogUtils.w("Warning :Component tree has not build completely, onActivityStop can not be call!"); |
| } |
| |
| |
| } |
| |
| @Override |
| public void onActivityDestroy() { |
| WXModuleManager.onActivityDestroy(getInstanceId()); |
| |
| if(mRootComp != null) { |
| mRootComp.onActivityDestroy(); |
| }else{ |
| WXLogUtils.w("Warning :Component tree has not build completely, onActivityDestroy can not be call!"); |
| } |
| |
| destroy(); |
| } |
| |
| @Override |
| public boolean onActivityBack() { |
| |
| WXModuleManager.onActivityBack(getInstanceId()); |
| |
| if(mRootComp != null) { |
| return mRootComp.onActivityBack(); |
| }else{ |
| WXLogUtils.w("Warning :Component tree has not build completely, onActivityBack can not be call!"); |
| } |
| |
| return false; |
| } |
| |
| public boolean onBackPressed() { |
| WXComponent comp = getRootComponent(); |
| if(comp != null) { |
| WXEvent events= comp.getDomObject().getEvents(); |
| boolean hasBackPressed = events.contains(Constants.Event.CLICKBACKITEM); |
| if (hasBackPressed) { |
| fireEvent(comp.getRef(), Constants.Event.CLICKBACKITEM,null, null); |
| } |
| return hasBackPressed; |
| } |
| return false; |
| } |
| |
| public void onActivityResult(int requestCode, int resultCode, Intent data){ |
| WXModuleManager.onActivityResult(getInstanceId(),requestCode,resultCode,data); |
| |
| if(mRootComp != null) { |
| mRootComp.onActivityResult(requestCode,resultCode,data); |
| }else{ |
| WXLogUtils.w("Warning :Component tree has not build completely, onActivityResult can not be call!"); |
| } |
| } |
| |
| |
| public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { |
| |
| WXModuleManager.onRequestPermissionsResult(getInstanceId(),requestCode,permissions,grantResults); |
| |
| if(mRootComp != null) { |
| mRootComp.onRequestPermissionsResult(requestCode,permissions,grantResults); |
| }else{ |
| WXLogUtils.w("Warning :Component tree has not build completely, onRequestPermissionsResult can not be call!"); |
| } |
| } |
| |
| /******************************** |
| * end hook Activity life cycle callback |
| ********************************************************/ |
| |
| public void onViewDisappear(){ |
| WXComponent comp = getRootComponent(); |
| if(comp != null) { |
| fireEvent(comp.getRef(), Constants.Event.VIEWDISAPPEAR, null, null); |
| //call disappear of nested instances |
| for(OnInstanceVisibleListener instance:mVisibleListeners){ |
| instance.onDisappear(); |
| } |
| } |
| } |
| |
| public void onViewAppear(){ |
| WXComponent comp = getRootComponent(); |
| if(comp != null) { |
| fireEvent( comp.getRef(), Constants.Event.VIEWAPPEAR,null, null); |
| for(OnInstanceVisibleListener instance:mVisibleListeners){ |
| instance.onAppear(); |
| } |
| } |
| } |
| |
| |
| public void onCreateFinish() { |
| if (mContext != null) { |
| runOnUiThread(new Runnable() { |
| |
| @Override |
| public void run() { |
| if ( mContext != null) { |
| onViewAppear(); |
| View wxView= mRenderContainer; |
| if(WXEnvironment.isApkDebugable() && WXSDKManager.getInstance().getIWXDebugAdapter()!=null){ |
| wxView = WXSDKManager.getInstance().getIWXDebugAdapter().wrapContainer(WXSDKInstance.this,wxView); |
| } |
| if(mRenderListener != null) { |
| mRenderListener.onViewCreated(WXSDKInstance.this, wxView); |
| } |
| if (mStatisticsListener != null) { |
| mStatisticsListener.onFirstView(); |
| } |
| } |
| } |
| }); |
| } |
| } |
| |
| /** |
| * call back when update finish |
| */ |
| public void onUpdateFinish() { |
| WXLogUtils.d("Instance onUpdateSuccess"); |
| } |
| |
| |
| public void runOnUiThread(Runnable action) { |
| WXSDKManager.getInstance().postOnUiThread(action, 0); |
| } |
| |
| public void onRenderSuccess(final int width, final int height) { |
| firstScreenRenderFinished(); |
| |
| long time = System.currentTimeMillis() - mRenderStartTime; |
| WXLogUtils.renderPerformanceLog("onRenderSuccess", time); |
| WXLogUtils.renderPerformanceLog(" invokeCreateInstance",mWXPerformance.communicateTime); |
| WXLogUtils.renderPerformanceLog(" TotalCallNativeTime", mWXPerformance.callNativeTime); |
| WXLogUtils.renderPerformanceLog(" TotalJsonParseTime", mWXPerformance.parseJsonTime); |
| WXLogUtils.renderPerformanceLog(" TotalBatchTime", mWXPerformance.batchTime); |
| WXLogUtils.renderPerformanceLog(" TotalCssLayoutTime", mWXPerformance.cssLayoutTime); |
| WXLogUtils.renderPerformanceLog(" TotalApplyUpdateTime", mWXPerformance.applyUpdateTime); |
| WXLogUtils.renderPerformanceLog(" TotalUpdateDomObjTime", mWXPerformance.updateDomObjTime); |
| |
| |
| mWXPerformance.totalTime = time; |
| if(mWXPerformance.screenRenderTime<0.001){ |
| mWXPerformance.screenRenderTime = time; |
| } |
| mWXPerformance.componentCount = WXComponent.mComponentNum; |
| WXLogUtils.d(WXLogUtils.WEEX_PERF_TAG, "mComponentNum:" + WXComponent.mComponentNum); |
| |
| WXComponent.mComponentNum = 0; |
| if (mRenderListener != null && mContext != null) { |
| runOnUiThread(new Runnable() { |
| |
| @Override |
| public void run() { |
| if (mRenderListener != null && mContext != null) { |
| mRenderListener.onRenderSuccess(WXSDKInstance.this, width, height); |
| if (mUserTrackAdapter != null) { |
| WXPerformance performance=new WXPerformance(); |
| performance.errCode=WXErrorCode.WX_SUCCESS.getErrorCode(); |
| performance.args=getBundleUrl(); |
| mUserTrackAdapter.commit(mContext,null,IWXUserTrackAdapter.JS_BRIDGE,performance,getUserTrackParams()); |
| } |
| |
| WXLogUtils.d(WXLogUtils.WEEX_PERF_TAG, mWXPerformance.toString()); |
| |
| } |
| } |
| }); |
| } |
| if(!WXEnvironment.isApkDebugable()){ |
| Log.e("weex_perf",mWXPerformance.getPerfData()); |
| } |
| } |
| |
| public void onRefreshSuccess(final int width, final int height) { |
| WXLogUtils.renderPerformanceLog("onRefreshSuccess", (System.currentTimeMillis() - mRefreshStartTime)); |
| if (mRenderListener != null && mContext != null) { |
| runOnUiThread(new Runnable() { |
| |
| @Override |
| public void run() { |
| if (mRenderListener != null && mContext != null) { |
| mRenderListener.onRefreshSuccess(WXSDKInstance.this, width, height); |
| } |
| } |
| }); |
| } |
| } |
| |
| public void onRenderError(final String errCode, final String msg) { |
| if (mRenderListener != null && mContext != null) { |
| runOnUiThread(new Runnable() { |
| |
| @Override |
| public void run() { |
| if (mRenderListener != null && mContext != null) { |
| mRenderListener.onException(WXSDKInstance.this, errCode, msg); |
| } |
| } |
| }); |
| } |
| } |
| |
| public void onJSException(final String errCode, final String function, final String exception) { |
| if (mRenderListener != null && mContext != null) { |
| runOnUiThread(new Runnable() { |
| |
| @Override |
| public void run() { |
| if (mRenderListener != null && mContext != null) { |
| StringBuilder builder = new StringBuilder(); |
| builder.append(function); |
| builder.append(exception); |
| mRenderListener.onException(WXSDKInstance.this, errCode, builder.toString()); |
| } |
| } |
| }); |
| } |
| } |
| |
| |
| @Override |
| public final void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int |
| oldTop, int oldRight, int oldBottom) { |
| if (left != oldLeft || top != oldTop || right != oldRight || bottom != oldBottom) { |
| onLayoutChange(v); |
| } |
| } |
| |
| /** |
| * Subclass should override this method to get notifications of layout change of GodView. |
| * @param godView the godView. |
| */ |
| public void onLayoutChange(View godView) { |
| |
| } |
| |
| private boolean mCreateInstance =true; |
| public void firstScreenCreateInstanceTime(long time) { |
| if(mCreateInstance) { |
| mWXPerformance.firstScreenJSFExecuteTime = time -mRenderStartTime; |
| mCreateInstance =false; |
| } |
| } |
| |
| public void callNativeTime(long time) { |
| mWXPerformance.callNativeTime += time; |
| } |
| |
| public void jsonParseTime(long time) { |
| mWXPerformance.parseJsonTime += time; |
| } |
| |
| public void firstScreenRenderFinished() { |
| if(mEnd == true) |
| return; |
| |
| mEnd = true; |
| |
| if (mStatisticsListener != null && mContext != null) { |
| runOnUiThread(new Runnable() { |
| @Override |
| public void run() { |
| if (mStatisticsListener != null && mContext != null) { |
| Trace.beginSection("onFirstScreen"); |
| mStatisticsListener.onFirstScreen(); |
| Trace.endSection(); |
| } |
| } |
| }); |
| } |
| |
| mWXPerformance.screenRenderTime = System.currentTimeMillis() - mRenderStartTime; |
| WXLogUtils.renderPerformanceLog("firstScreenRenderFinished", mWXPerformance.screenRenderTime); |
| WXLogUtils.renderPerformanceLog(" firstScreenJSFExecuteTime", mWXPerformance.firstScreenJSFExecuteTime); |
| WXLogUtils.renderPerformanceLog(" firstScreenCallNativeTime", mWXPerformance.callNativeTime); |
| WXLogUtils.renderPerformanceLog(" firstScreenJsonParseTime", mWXPerformance.parseJsonTime); |
| WXLogUtils.renderPerformanceLog(" firstScreenBatchTime", mWXPerformance.batchTime); |
| WXLogUtils.renderPerformanceLog(" firstScreenCssLayoutTime", mWXPerformance.cssLayoutTime); |
| WXLogUtils.renderPerformanceLog(" firstScreenApplyUpdateTime", mWXPerformance.applyUpdateTime); |
| WXLogUtils.renderPerformanceLog(" firstScreenUpdateDomObjTime", mWXPerformance.updateDomObjTime); |
| } |
| |
| public void batchTime(long time) { |
| mWXPerformance.batchTime += time; |
| } |
| public void cssLayoutTime(long time) { |
| mWXPerformance.cssLayoutTime += time; |
| } |
| |
| public void applyUpdateTime(long time) { |
| mWXPerformance.applyUpdateTime += time; |
| } |
| |
| public void updateDomObjTime(long time) { |
| mWXPerformance.updateDomObjTime += time; |
| } |
| |
| |
| public void createInstanceFinished(long time) { |
| if (time > 0) { |
| mWXPerformance.communicateTime = time; |
| } |
| } |
| |
| /** |
| * UserTrack Log |
| */ |
| public void commitUTStab(final String type, final WXErrorCode errorCode) { |
| if (TextUtils.isEmpty(type) || errorCode == null) { |
| return; |
| } |
| |
| runOnUiThread(new Runnable() { |
| @Override |
| public void run() { |
| // Record exception if a render error happened. |
| if (mStatisticsListener != null && errorCode != WXErrorCode.WX_SUCCESS) { |
| mStatisticsListener.onException(mInstanceId, |
| errorCode.getErrorCode(), |
| errorCode.getErrorMsg()); |
| } |
| |
| WXPerformance performance = new WXPerformance(); |
| performance.errCode = errorCode.getErrorCode(); |
| performance.args = errorCode.getArgs(); |
| if (errorCode != WXErrorCode.WX_SUCCESS) { |
| performance.errMsg = errorCode.getErrorMsg(); |
| if (WXEnvironment.isApkDebugable()) { |
| WXLogUtils.d(performance.toString()); |
| } |
| } |
| if( mUserTrackAdapter!= null) { |
| mUserTrackAdapter.commit(mContext, null, type, performance, getUserTrackParams()); |
| } |
| } |
| }); |
| } |
| |
| private void destroyView(View rootView) { |
| try { |
| if (rootView instanceof ViewGroup) { |
| ViewGroup cViewGroup = ((ViewGroup) rootView); |
| for (int index = 0; index < cViewGroup.getChildCount(); index++) { |
| destroyView(cViewGroup.getChildAt(index)); |
| } |
| |
| cViewGroup.removeViews(0, ((ViewGroup) rootView).getChildCount()); |
| // Ensure that the viewgroup's status to be normal |
| WXReflectionUtils.setValue(rootView, "mChildrenCount", 0); |
| |
| } |
| if(rootView instanceof Destroyable){ |
| ((Destroyable)rootView).destroy(); |
| } |
| } catch (Exception e) { |
| WXLogUtils.e("WXSDKInstance destroyView Exception: ", e); |
| } |
| } |
| |
| public synchronized void destroy() { |
| if(!isDestroy()) { |
| WXSDKManager.getInstance().destroyInstance(mInstanceId); |
| WXComponentFactory.removeComponentTypesByInstanceId(getInstanceId()); |
| |
| if (mGlobalEventReceiver != null) { |
| getContext().unregisterReceiver(mGlobalEventReceiver); |
| mGlobalEventReceiver = null; |
| } |
| if (mRootComp != null) { |
| mRootComp.destroy(); |
| destroyView(mRenderContainer); |
| mRootComp = null; |
| } |
| |
| if (mGlobalEvents != null) { |
| mGlobalEvents.clear(); |
| } |
| |
| if (mComponentObserver != null) { |
| mComponentObserver = null; |
| } |
| |
| getFlatUIContext().destroy(); |
| mFlatGUIContext = null; |
| |
| mWXScrollListeners = null; |
| mRenderContainer = null; |
| mNestedInstanceInterceptor = null; |
| mUserTrackAdapter = null; |
| mScrollView = null; |
| mContext = null; |
| mRenderListener = null; |
| isDestroy = true; |
| mStatisticsListener = null; |
| } |
| } |
| |
| public boolean isDestroy(){ |
| return isDestroy; |
| } |
| |
| /** |
| * @return If you use render () the return value may be empty |
| */ |
| public @Nullable String getBundleUrl() { |
| return mBundleUrl; |
| } |
| |
| public View getRootView() { |
| return mRootComp.getRealView(); |
| } |
| |
| public View getContainerView() { |
| return mRenderContainer; |
| } |
| |
| @Deprecated |
| public void setBundleUrl(String url){ |
| mBundleUrl = url; |
| if(WXSDKManager.getInstance().getValidateProcessor()!=null) { |
| mNeedValidate = WXSDKManager.getInstance().getValidateProcessor().needValidate(mBundleUrl); |
| } |
| } |
| |
| public void onRootCreated(WXComponent root) { |
| this.mRootComp = root; |
| mRenderContainer.addView(root.getHostView()); |
| setSize(mRenderContainer.getWidth(),mRenderContainer.getHeight()); |
| } |
| |
| /** |
| * Move fixed view to container ,except it's already moved. |
| * @param fixedChild |
| */ |
| public void moveFixedView(View fixedChild){ |
| if(mRenderContainer != null) { |
| ViewGroup parent; |
| if((parent = (ViewGroup) fixedChild.getParent()) != null){ |
| if (parent != mRenderContainer) { |
| parent.removeView(fixedChild); |
| mRenderContainer.addView(fixedChild); |
| } |
| }else{ |
| mRenderContainer.addView(fixedChild); |
| } |
| } |
| } |
| |
| public void removeFixedView(View fixedChild){ |
| if(mRenderContainer != null) { |
| mRenderContainer.removeView(fixedChild); |
| } |
| } |
| |
| public synchronized List<OnWXScrollListener> getWXScrollListeners() { |
| return mWXScrollListeners; |
| } |
| |
| public synchronized void registerOnWXScrollListener(OnWXScrollListener wxScrollListener) { |
| if(mWXScrollListeners==null){ |
| mWXScrollListeners=new ArrayList<>(); |
| } |
| mWXScrollListeners.add(wxScrollListener); |
| } |
| |
| private void updateRootComponentStyle(JSONObject style) { |
| Message message = Message.obtain(); |
| WXDomTask task = new WXDomTask(); |
| task.instanceId = getInstanceId(); |
| if (task.args == null) { |
| task.args = new ArrayList<>(); |
| } |
| task.args.add(WXDomObject.ROOT); |
| task.args.add(style); |
| message.obj = task; |
| message.what = WXDomHandler.MsgType.WX_DOM_UPDATE_STYLE; |
| WXSDKManager.getInstance().getWXDomManager().sendMessage(message); |
| } |
| |
| public void setSize(int width, int height) { |
| if (width < 0 || height < 0 || isDestroy || !mRendered) { |
| return; |
| } |
| float realWidth = WXViewUtils.getWebPxByWidth(width,getInstanceViewPortWidth()); |
| float realHeight = WXViewUtils.getWebPxByWidth(height,getInstanceViewPortWidth()); |
| |
| View godView = mRenderContainer; |
| if (godView != null) { |
| ViewGroup.LayoutParams layoutParams = godView.getLayoutParams(); |
| if (layoutParams != null) { |
| if(godView.getWidth() != width || godView.getHeight() != height) { |
| layoutParams.width = width; |
| layoutParams.height = height; |
| godView.setLayoutParams(layoutParams); |
| } |
| |
| JSONObject style = new JSONObject(); |
| WXComponent rootComponent = mRootComp; |
| |
| if(rootComponent == null){ |
| return; |
| } |
| style.put(Constants.Name.DEFAULT_WIDTH, realWidth); |
| style.put(Constants.Name.DEFAULT_HEIGHT, realHeight); |
| updateRootComponentStyle(style); |
| } |
| } |
| } |
| |
| /*Global Event*/ |
| private HashMap<String, List<String>> mGlobalEvents = new HashMap<>(); |
| |
| public void fireGlobalEventCallback(String eventName, Map<String,Object> params){ |
| List<String> callbacks=mGlobalEvents.get(eventName); |
| if(callbacks!=null){ |
| for(String callback:callbacks){ |
| WXSDKManager.getInstance().callback(mInstanceId,callback,params,true); |
| } |
| } |
| } |
| |
| /** |
| * Fire event callback on a element. |
| * @param elementRef |
| * @param type |
| * @param data |
| * @param domChanges |
| */ |
| public void fireEvent(String elementRef,final String type, final Map<String, Object> data,final Map<String, Object> domChanges, List<Object> eventArgs){ |
| WXBridgeManager.getInstance().fireEventOnNode(getInstanceId(),elementRef,type,data,domChanges, eventArgs); |
| } |
| /** |
| * Fire event callback on a element. |
| * @param elementRef |
| * @param type |
| * @param data |
| * @param domChanges |
| */ |
| public void fireEvent(String elementRef,final String type, final Map<String, Object> data,final Map<String, Object> domChanges){ |
| fireEvent(elementRef, type, data, domChanges, null); |
| } |
| |
| public void fireEvent(String elementRef,final String type, final Map<String, Object> data){ |
| fireEvent(elementRef,type,data,null); |
| } |
| |
| public void fireEvent(String ref, String type){ |
| fireEvent(ref,type,new HashMap<String, Object>()); |
| } |
| |
| protected void addEventListener(String eventName, String callback) { |
| if (TextUtils.isEmpty(eventName) || TextUtils.isEmpty(callback)) { |
| return; |
| } |
| List<String> callbacks = mGlobalEvents.get(eventName); |
| if (callbacks == null) { |
| callbacks = new ArrayList<>(); |
| mGlobalEvents.put(eventName, callbacks); |
| } |
| callbacks.add(callback); |
| } |
| protected void removeEventListener(String eventName, String callback) { |
| if (TextUtils.isEmpty(eventName) || TextUtils.isEmpty(callback)) { |
| return; |
| } |
| List<String> callbacks = mGlobalEvents.get(eventName); |
| if (callbacks != null) { |
| callbacks.remove(callback); |
| } |
| } |
| |
| protected void removeEventListener(String eventName) { |
| if (TextUtils.isEmpty(eventName)) { |
| return; |
| } |
| mGlobalEvents.remove(eventName); |
| } |
| |
| /** |
| * Notifies WEEX that this event has occurred |
| * @param eventName WEEX register event |
| * @param module Events occur in this Module |
| * @param params The parameters to be notified to WEEX are required |
| */ |
| public void fireModuleEvent(String eventName, WXModule module,Map<String, Object> params) { |
| if (TextUtils.isEmpty(eventName) || module == null) { |
| return; |
| } |
| |
| Map<String, Object> event = new HashMap<>(); |
| event.put("type", eventName); |
| event.put("module", module.getModuleName()); |
| event.put("data", params); |
| |
| List<String> callbacks = module.getEventCallbacks(eventName); |
| if (callbacks != null) { |
| for (String callback : callbacks) { |
| SimpleJSCallback jsCallback = new SimpleJSCallback(mInstanceId, callback); |
| if (module.isOnce(callback)) { |
| jsCallback.invoke(event); |
| } else { |
| jsCallback.invokeAndKeepAlive(event); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Check whether the current module registered the event |
| * @param eventName EventName register in weex |
| * @param module Events occur in this Module |
| * @return boolean true |
| */ |
| public boolean checkModuleEventRegistered(String eventName,WXModule module) { |
| if (module != null) { |
| List<String> events = module.getEventCallbacks(eventName); |
| if (events != null && events.size() > 0) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public WXPerformance getWXPerformance(){ |
| return mWXPerformance; |
| } |
| |
| public Map<String, Serializable> getUserTrackParams() { |
| return mUserTrackParams; |
| } |
| |
| public void addUserTrackParameter(String key,Serializable value){ |
| if(this.mUserTrackParams == null){ |
| this.mUserTrackParams = new ConcurrentHashMap<>(); |
| } |
| mUserTrackParams.put(key,value); |
| } |
| |
| public void clearUserTrackParameters(){ |
| if(this.mUserTrackParams != null){ |
| this.mUserTrackParams.clear(); |
| } |
| } |
| |
| public void removeUserTrackParameter(String key){ |
| if(this.mUserTrackParams != null){ |
| this.mUserTrackParams.remove(key); |
| } |
| } |
| |
| public int getMaxDeepLayer() { |
| return mMaxDeepLayer; |
| } |
| |
| public void setMaxDeepLayer(int maxDeepLayer) { |
| mMaxDeepLayer = maxDeepLayer; |
| } |
| |
| /** |
| * load bundle js listener |
| */ |
| class WXHttpListener implements IWXHttpAdapter.OnHttpListener { |
| |
| private String pageName; |
| private Map<String, Object> options; |
| private String jsonInitData; |
| private WXRenderStrategy flag; |
| private WXSDKInstance instance; |
| private long startRequestTime; |
| private int traceId; |
| |
| private WXHttpListener(String pageName, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag, long startRequestTime) { |
| this.pageName = pageName; |
| this.options = options; |
| this.jsonInitData = jsonInitData; |
| this.flag = flag; |
| this.startRequestTime = startRequestTime; |
| this.traceId = WXTracing.nextId(); |
| |
| if (WXTracing.isAvailable()) { |
| WXTracing.TraceEvent event = WXTracing.newEvent("downloadBundleJS", mInstanceId, -1); |
| event.iid = mInstanceId; |
| event.tname = "Network"; |
| event.ph = "B"; |
| event.traceId = traceId; |
| event.submit(); |
| } |
| } |
| |
| public void setSDKInstance(WXSDKInstance instance) { |
| this.instance = instance; |
| } |
| |
| @Override |
| public void onHttpStart() { |
| if (this.instance != null |
| && this.instance.getWXStatisticsListener() != null) { |
| this.instance.getWXStatisticsListener().onHttpStart(); |
| } |
| } |
| |
| @Override |
| public void onHeadersReceived(int statusCode,Map<String,List<String>> headers) { |
| if (this.instance != null |
| && this.instance.getWXStatisticsListener() != null) { |
| this.instance.getWXStatisticsListener().onHeadersReceived(); |
| } |
| } |
| |
| @Override |
| public void onHttpUploadProgress(int uploadProgress) { |
| |
| } |
| |
| @Override |
| public void onHttpResponseProgress(int loadedLength) { |
| |
| } |
| |
| @Override |
| public void onHttpFinish(WXResponse response) { |
| if (this.instance != null |
| && this.instance.getWXStatisticsListener() != null) { |
| this.instance.getWXStatisticsListener().onHttpFinish(); |
| } |
| |
| if (WXTracing.isAvailable()) { |
| WXTracing.TraceEvent event = WXTracing.newEvent("downloadBundleJS", mInstanceId, -1); |
| event.traceId = traceId; |
| event.tname = "Network"; |
| event.ph = "E"; |
| event.extParams = new HashMap<>(); |
| if (response != null && response.originalData != null) { |
| event.extParams.put("BundleSize", response.originalData.length); |
| } |
| event.submit(); |
| } |
| |
| mWXPerformance.networkTime = System.currentTimeMillis() - startRequestTime; |
| if(response.extendParams!=null){ |
| Object actualNetworkTime=response.extendParams.get("actualNetworkTime"); |
| mWXPerformance.actualNetworkTime=actualNetworkTime instanceof Long?(long)actualNetworkTime:0; |
| WXLogUtils.renderPerformanceLog("actualNetworkTime", mWXPerformance.actualNetworkTime); |
| |
| Object pureNetworkTime=response.extendParams.get("pureNetworkTime"); |
| mWXPerformance.pureNetworkTime=pureNetworkTime instanceof Long?(long)pureNetworkTime:0; |
| WXLogUtils.renderPerformanceLog("pureNetworkTime", mWXPerformance.pureNetworkTime); |
| |
| Object connectionType=response.extendParams.get("connectionType"); |
| mWXPerformance.connectionType=connectionType instanceof String?(String)connectionType:""; |
| |
| Object packageSpendTime=response.extendParams.get("packageSpendTime"); |
| mWXPerformance.packageSpendTime=packageSpendTime instanceof Long ?(long)packageSpendTime:0; |
| |
| Object syncTaskTime=response.extendParams.get("syncTaskTime"); |
| mWXPerformance.syncTaskTime=syncTaskTime instanceof Long ?(long)syncTaskTime:0; |
| |
| Object requestType=response.extendParams.get("requestType"); |
| mWXPerformance.requestType=requestType instanceof String?(String)requestType:""; |
| |
| if("network".equals(requestType) && mUserTrackAdapter!=null){ |
| WXPerformance performance=new WXPerformance(); |
| if(!TextUtils.isEmpty(mBundleUrl)){ |
| try { |
| performance.args= Uri.parse(mBundleUrl).buildUpon().clearQuery().toString(); |
| } catch (Exception e) { |
| performance.args=pageName; |
| } |
| } |
| if(!"200".equals(response.statusCode)){ |
| performance.errCode=WXErrorCode.WX_ERR_JSBUNDLE_DOWNLOAD.getErrorCode(); |
| performance.appendErrMsg(response.errorCode); |
| performance.appendErrMsg("|"); |
| performance.appendErrMsg(response.errorMsg); |
| }else if("200".equals(response.statusCode) && (response.originalData==null || response.originalData.length<=0)){ |
| performance.errCode=WXErrorCode.WX_ERR_JSBUNDLE_DOWNLOAD.getErrorCode(); |
| performance.appendErrMsg(response.statusCode); |
| performance.appendErrMsg("|template is null!"); |
| }else { |
| performance.errCode=WXErrorCode.WX_SUCCESS.getErrorCode(); |
| } |
| if (mUserTrackAdapter != null) { |
| mUserTrackAdapter.commit(getContext(), null, IWXUserTrackAdapter.JS_DOWNLOAD, performance, null); |
| } |
| } |
| } |
| WXLogUtils.renderPerformanceLog("networkTime", mWXPerformance.networkTime); |
| if (response!=null && response.originalData!=null && TextUtils.equals("200", response.statusCode)) { |
| String template = new String(response.originalData); |
| render(pageName, template, options, jsonInitData, flag); |
| } else if (TextUtils.equals(WXRenderErrorCode.WX_USER_INTERCEPT_ERROR, response.statusCode)) { |
| WXLogUtils.d("user intercept"); |
| onRenderError(WXRenderErrorCode.WX_USER_INTERCEPT_ERROR,response.errorMsg); |
| } else { |
| onRenderError(WXRenderErrorCode.WX_NETWORK_ERROR, response.errorMsg); |
| } |
| } |
| } |
| |
| public interface NestedInstanceInterceptor { |
| void onCreateNestInstance(WXSDKInstance instance, NestedContainer container); |
| } |
| } |