当前位置: 首页 > news >正文

南京网站推广营销公司哪家好程序小程序开发公司

南京网站推广营销公司哪家好,程序小程序开发公司,网站建设如何实现检索功能,网站使用协议书文章目录 介绍优点基本用法线程模式POSTINGMAINMAIN_ORDEREDBACKGROUNDASYNC 黏性事件 源码注册getDefault()registerfindSubscriberMethods小结 postpostStickyunregister 介绍 优点 简化组件之间的通信 解耦事件发送者和接收者在 Activity、Fragment 和后台线程中表现良好避… 文章目录 介绍优点基本用法线程模式POSTINGMAINMAIN_ORDEREDBACKGROUNDASYNC 黏性事件 源码注册getDefault()registerfindSubscriberMethods小结 postpostStickyunregister 介绍 优点 简化组件之间的通信 解耦事件发送者和接收者在 Activity、Fragment 和后台线程中表现良好避免复杂且容易出错的依赖关系和生命周期问题 让你的代码更简单很快很小具有高级功能如交付线程、订阅者优先级等。 基本用法 导入依赖 implementation org.greenrobot:eventbus:3.3.1定义事件 public static class MessageEvent { /* Additional fields if needed */ }准备订阅者声明并注释您的订阅方法可以选择指定线程模式 Subscribe(threadMode ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) {// Do something }注册和取消注册您的订户。例如在 Android 上活动和片段通常应根据其生命周期进行注册 Overridepublic void onStart() {super.onStart();EventBus.getDefault().register(this);}Overridepublic void onStop() {super.onStop();EventBus.getDefault().unregister(this);}发布活动 EventBus.getDefault().post(new MessageEvent());线程模式 POSTING 特点订阅者在发布事件的同一线程中被调用。优点开销最小避免了线程切换。适用场景已知任务简单且快速完成不依赖主线程。注意长时间任务可能阻塞发布线程如是主线程会导致UI卡顿。 Subscribe(threadMode ThreadMode.POSTING) public void onMessage(MessageEvent event) {log(event.message); // 快速返回的简单任务 }MAIN 特点 订阅者在主线程UI线程中被调用 如果发布线程为主线程则同步调用与 POSTING 类似 适用场景UI更新或需要在主线程完成的轻量任务。 注意避免执行耗时任务否则会阻塞主线程导致卡顿。 Subscribe(threadMode ThreadMode.MAIN) public void onMessage(MessageEvent event) {textView.setText(event.message); // 更新UI }MAIN_ORDERED 特点 在主线程中执行。按顺序执行事件会一个接一个地处理不会乱序。 适用场景依赖特定执行顺序的UI更新逻辑。注意与 MAIN 类似避免耗时任务确保任务快速返回。 Subscribe(threadMode ThreadMode.MAIN_ORDERED) public void onMessageEvent(String event) {Log.d(EventBus, Event received: event); // 按顺序更新UI }BACKGROUND 特点 如果发布线程为主线程事件处理方法会切换到后台线程。如果发布线程是非主线程事件处理方法直接在发布线程中执行。 适用场景后台任务如数据库存储、文件操作。注意快速返回避免阻塞后台线程。 Subscribe(threadMode ThreadMode.BACKGROUND) public void onMessage(MessageEvent event) {saveToDisk(event.message); // 后台存储操作 }ASYNC 特点事件处理程序始终在独立线程中调用与发布线程或主线程完全分离。适用场景耗时操作如网络请求、复杂计算。注意避免触发大量异步任务防止线程池耗尽资源。 Subscribe(threadMode ThreadMode.ASYNC) public void onMessage(MessageEvent event) {backend.send(event.message); // 异步网络请求 }黏性事件 发送事件之后再订阅也能收到该事件 Subscribe(threadMode ThreadMode.POSTING, sticky true) public void onMessageEvent(MessageEvent messageEvent) {tv.setText(messageEvent.getMessage()); }EventBus.getDefault().postSticky(new MessageEvent(SecondActivity的信息));源码 注册 getDefault() public class EventBus {// 静态变量存储唯一的 EventBus 实例// 使用 volatile 关键字确保多线程环境下变量的可见性和防止指令重排static volatile EventBus defaultInstance;public static EventBus getDefault() {// 将静态变量 defaultInstance 赋值给局部变量 instance减少对主内存的访问EventBus instance defaultInstance;// 第一次检查避免不必要的同步开销if (instance null) {// 如果实例未被初始化进入同步块synchronized (EventBus.class) {// 再次将 defaultInstance 的值赋给 instance看这个时候defaultInstance为不为空instance EventBus.defaultInstance;// 第二次检查确保实例仍未被初始化双重检查锁定if (instance null) {// 创建新的 EventBus 实例并赋值给 defaultInstance 和局部变量 instanceinstance EventBus.defaultInstance new EventBus();}}}return instance;} }public EventBus() {this(DEFAULT_BUILDER); }private static final EventBusBuilder DEFAULT_BUILDER new EventBusBuilder();EventBus(EventBusBuilder builder) {//日志logger builder.getLogger();//这个集合可以根据事件类型获取订阅者//key事件类型value订阅该事件的订阅者集合subscriptionsByEventType new HashMap();//订阅者所订阅的事件集合//key订阅者value该订阅者订阅的事件集合typesBySubscriber new HashMap();//粘性事件集合//key事件Class对象value事件对象stickyEvents new ConcurrentHashMap();//Android主线程处理事件mainThreadSupport builder.getMainThreadSupport();mainThreadPoster mainThreadSupport ! null ? mainThreadSupport.createPoster(this) : null;//Background事件发送者backgroundPoster new BackgroundPoster(this);//异步事件发送者asyncPoster new AsyncPoster(this);indexCount builder.subscriberInfoIndexes ! null ? builder.subscriberInfoIndexes.size() : 0;//订阅者订阅事件查找对象subscriberMethodFinder new SubscriberMethodFinder(builder.subscriberInfoIndexes,builder.strictMethodVerification, builder.ignoreGeneratedIndex);logSubscriberExceptions builder.logSubscriberExceptions;logNoSubscriberMessages builder.logNoSubscriberMessages;sendSubscriberExceptionEvent builder.sendSubscriberExceptionEvent;sendNoSubscriberEvent builder.sendNoSubscriberEvent;throwSubscriberException builder.throwSubscriberException;eventInheritance builder.eventInheritance;executorService builder.executorService; }这个方法内部首先通过单例模式创建一个EventBus对象在创建EventBus时最终会调用它的有参构造函数传入一个EventBus.Builder对象。在这个有参构造函数内部对属性进行初始化 register public class EventBus {public void register(Object subscriber) {// 1、通过反射获取到订阅者的Class对象Class? subscriberClass subscriber.getClass();// 2、通过subscriberMethodFinder对象获取订阅者所订阅事件的集合ListSubscriberMethod subscriberMethods subscriberMethodFinder.findSubscriberMethods(subscriberClass);synchronized (this) {// 3、遍历集合进行注册for (SubscriberMethod subscriberMethod : subscriberMethods) {subscribe(subscriber, subscriberMethod);}}}private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {// 4、获取事件类型Class? eventType subscriberMethod.eventType;// 5、封装Subscription对象Subscription newSubscription new Subscription(subscriber, subscriberMethod);// 6、通过事件类型获取该事件的订阅者集合CopyOnWriteArrayListSubscription subscriptions subscriptionsByEventType.get(eventType);// 7、如果没有订阅者订阅该事件if (subscriptions null) {// 创建集合存入subscriptionsByEventType集合中subscriptions new CopyOnWriteArrayList();subscriptionsByEventType.put(eventType, subscriptions);} else { // 8、如果有订阅者已经订阅了该事件// 判断这些订阅者中是否有重复订阅的现象if (subscriptions.contains(newSubscription)) {throw new EventBusException(Subscriber subscriber.getClass() already registered to event eventType);}}int size subscriptions.size();// 9、遍历该事件的所有订阅者for (int i 0; i size; i) {// 按照优先级高低进行插入如果优先级最低插入到集合尾部if (i size || subscriberMethod.priority subscriptions.get(i).subscriberMethod.priority) {subscriptions.add(i, newSubscription);break;}}// 10、获取该事件订阅者订阅的所有事件集合ListClass? subscribedEvents typesBySubscriber.get(subscriber);if (subscribedEvents null) {subscribedEvents new ArrayList();typesBySubscriber.put(subscriber, subscribedEvents);}// 11、将该事件加入到集合中subscribedEvents.add(eventType);// 12、判断该事件是否是粘性事件if (subscriberMethod.sticky) {if (eventInheritance) { // 13、判断事件的继承性默认是不可继承// 14、获取所有粘性事件并遍历判断继承关系SetMap.EntryClass?, Object entries stickyEvents.entrySet();for (Map.EntryClass?, Object entry : entries) {Class? candidateEventType entry.getKey();if (eventType.isAssignableFrom(candidateEventType)) {Object stickyEvent entry.getValue();// 15、调用checkPostStickyEventToSubscription方法checkPostStickyEventToSubscription(newSubscription, stickyEvent);}}} else {Object stickyEvent stickyEvents.get(eventType);checkPostStickyEventToSubscription(newSubscription, stickyEvent);}}}private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {if (stickyEvent ! null) {// 16、如果粘性事件不为空postToSubscription(newSubscription, stickyEvent, isMainThread());}}private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {// 17、根据threadMode的类型去选择是直接反射调用方法还是将事件插入队列switch (subscription.subscriberMethod.threadMode) {case POSTING:invokeSubscriber(subscription, event);break;case MAIN:if (isMainThread) {// 18、通过反射的方式调用invokeSubscriber(subscription, event);} else {// 19、将粘性事件插入到队列中// 最后还是会调用EventBus.invokeSubscriber(PendingPost pendingPost)方法。mainThreadPoster.enqueue(subscription, event);}break;case MAIN_ORDERED:if (mainThreadPoster ! null) {mainThreadPoster.enqueue(subscription, event);} else {// temporary: technically not correct as poster not decoupled from subscriberinvokeSubscriber(subscription, event);}break;case BACKGROUND:if (isMainThread) {backgroundPoster.enqueue(subscription, event);} else {invokeSubscriber(subscription, event);}break;case ASYNC:asyncPoster.enqueue(subscription, event);break;default:throw new IllegalStateException(Unknown thread mode: subscription.subscriberMethod.threadMode);}}void invokeSubscriber(PendingPost pendingPost) {Object event pendingPost.event;Subscription subscription pendingPost.subscription;PendingPost.releasePendingPost(pendingPost);if (subscription.active) {invokeSubscriber(subscription, event);}}void invokeSubscriber(Subscription subscription, Object event) {try {subscription.subscriberMethod.method.invoke(subscription.subscriber, event);} catch (InvocationTargetException e) {handleSubscriberException(subscription, event, e.getCause());} catch (IllegalAccessException e) {throw new IllegalStateException(Unexpected exception, e);}} }public class SubscriberMethod {final Method method; // 处理事件的Method对象final ThreadMode threadMode; //线程模型final Class? eventType; //事件类型final int priority; //事件优先级final boolean sticky; //是否是粘性事件String methodString; }final class Subscription {final Object subscriber;final SubscriberMethod subscriberMethod; }findSubscriberMethods class SubscriberMethodFinder {private static final int MODIFIERS_IGNORE Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;private static final MapClass?, ListSubscriberMethod METHOD_CACHE new ConcurrentHashMap();private static final int POOL_SIZE 4;private static final FindState[] FIND_STATE_POOL new FindState[POOL_SIZE];ListSubscriberMethod findSubscriberMethods(Class? subscriberClass) {// 1、先从之前缓存的集合中获取ListSubscriberMethod subscriberMethods METHOD_CACHE.get(subscriberClass);if (subscriberMethods ! null) {// 2、如果之前缓存了直接返回return subscriberMethods;}if (ignoreGeneratedIndex) { //ignoreGeneratedIndex一般为falsesubscriberMethods findUsingReflection(subscriberClass);} else {// 3、获取所有订阅方法集合subscriberMethods findUsingInfo(subscriberClass);}if (subscriberMethods.isEmpty()) {throw new EventBusException(Subscriber subscriberClass and its super classes have no public methods with the Subscribe annotation);} else {// 4、放入缓存集合中METHOD_CACHE.put(subscriberClass, subscriberMethods);return subscriberMethods;}}private ListSubscriberMethod findUsingInfo(Class? subscriberClass) {// 5、从数组中获取FindState对象// 如果有直接返回如果没有创建一个新的FindState对象FindState findState prepareFindState();// 6、根据事件订阅者初始化findStatefindState.initForSubscriber(subscriberClass);while (findState.clazz ! null) {// 7、获取subscriberInfo初始化为nullfindState.subscriberInfo getSubscriberInfo(findState);if (findState.subscriberInfo ! null) {SubscriberMethod[] array findState.subscriberInfo.getSubscriberMethods();for (SubscriberMethod subscriberMethod : array) {if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {findState.subscriberMethods.add(subscriberMethod);}}} else {// 8、通过反射的方式获取订阅者中的Method默认情况findUsingReflectionInSingleClass(findState);}findState.moveToSuperclass();}return getMethodsAndRelease(findState);}private FindState prepareFindState() {synchronized (FIND_STATE_POOL) {for (int i 0; i POOL_SIZE; i) {FindState state FIND_STATE_POOL[i];if (state ! null) {FIND_STATE_POOL[i] null;return state;}}}return new FindState();}private void findUsingReflectionInSingleClass(FindState findState) {Method[] methods;try {// 9、订阅者中所有声明的方法放入数组中methods findState.clazz.getDeclaredMethods();} catch (Throwable th) {// 10、获取订阅者中声明的public方法设置跳过父类methods findState.clazz.getMethods();findState.skipSuperClasses true;}// 遍历这些方法for (Method method : methods) {// 11、获取方法的修饰符:public、private等等int modifiers method.getModifiers();// 12、订阅方法为public同时不是abstract、staticif ((modifiers Modifier.PUBLIC) ! 0 (modifiers MODIFIERS_IGNORE) 0) {// 13、方法参数类型数组Class?[] parameterTypes method.getParameterTypes();if (parameterTypes.length 1) {// 14、获取方法的注解Subscribe subscribeAnnotation method.getAnnotation(Subscribe.class);// 15、如果有注解if (subscribeAnnotation ! null) {Class? eventType parameterTypes[0];// 16、将method和eventType放入到findState进行检查if (findState.checkAdd(method, eventType)) {// 17、获取注解中的threadMode对象ThreadMode threadMode subscribeAnnotation.threadMode();// 18、新建一个SubscriberMethod对象同时加入到findState中findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,subscribeAnnotation.priority(), subscribeAnnotation.sticky()));}}} else if (strictMethodVerification method.isAnnotationPresent(Subscribe.class)) {String methodName method.getDeclaringClass().getName() . method.getName();throw new EventBusException(Subscribe method methodName must have exactly 1 parameter but has parameterTypes.length);}} else if (strictMethodVerification method.isAnnotationPresent(Subscribe.class)) {String methodName method.getDeclaringClass().getName() . method.getName();throw new EventBusException(methodName is a illegal Subscribe method: must be public, non-static, and non-abstract);}}}// 从findState中获取订阅者所有方法并释放private ListSubscriberMethod getMethodsAndRelease(FindState findState) {// 获取订阅者所有订阅方法集合ListSubscriberMethod subscriberMethods new ArrayList(findState.subscriberMethods);// findState进行回收findState.recycle();synchronized (FIND_STATE_POOL) {for (int i 0; i POOL_SIZE; i) {if (FIND_STATE_POOL[i] null) {FIND_STATE_POOL[i] findState;break;}}}// 返回集合return subscriberMethods;} }小结 根据单例设计模式创建一个EventBus对象同时创建一个EventBus.Builder对象对EventBus进行初始化其中有三个比较重要的集合和一个SubscriberMethodFinder对象。调用register方法,首先通过反射获取到订阅者的Class对象。通过SubscriberMethodFinder对象获取订阅者中所有订阅的事件集合,它先从缓存中获取如果缓存中有直接返回如果缓存中没有通过反射的方式去遍历订阅者内部被注解的方法将这些方法放入到集合中进行返回。遍历第三步获取的集合将订阅者和事件进行绑定。在绑定之后会判断绑定的事件是否是粘性事件如果是粘性事件直接调用postToSubscription方法将之前发送的粘性事件发送给订阅者。 post public class EventBus {...public void post(Object event) {// 1、获取当前线程的PostingThreadState这是一个ThreadLocal对象PostingThreadState postingState currentPostingThreadState.get();// 2、当前线程的事件集合ListObject eventQueue postingState.eventQueue;// 3、将要发送的事件加入到集合中eventQueue.add(event);// 查看是否正在发送事件if (!postingState.isPosting) {// 判断是否是主线程postingState.isMainThread isMainThread();postingState.isPosting true;if (postingState.canceled) {throw new EventBusException(Internal error. Abort state was not reset);}try {// 4、只要事件集合中还有事件就一直发送while (!eventQueue.isEmpty()) {postSingleEvent(eventQueue.remove(0), postingState);}} finally {postingState.isPosting false;postingState.isMainThread false;}}}// currentPostingThreadState是包含了PostingThreadState的ThreadLocal对象// ThreadLocal是一个线程内部的数据存储类通过它可以在指定的线程中存储数据 并且线程之间的数据是相互独立的。// 其内部通过创建一个它包裹的泛型对象的数组不同的线程对应不同的数组索引每个线程通过get方法获取对应的线程数据。private final ThreadLocalPostingThreadState currentPostingThreadState new ThreadLocalPostingThreadState() {Overrideprotected PostingThreadState initialValue() {return new PostingThreadState();}};// 每个线程中存储的数据final static class PostingThreadState {final ListObject eventQueue new ArrayList(); // 线程的事件队列boolean isPosting; //是否正在发送中boolean isMainThread; //是否在主线程中发送Subscription subscription; //事件订阅者和订阅事件的封装Object event; //事件对象boolean canceled; //是否被取消发送}...private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {// 5、获取事件的Class对象Class? eventClass event.getClass();boolean subscriptionFound false;if (eventInheritance) { // eventInheritance一般为true// 6、 找到当前的event的所有 父类和实现的接口 的class集合ListClass? eventTypes lookupAllEventTypes(eventClass);int countTypes eventTypes.size();for (int h 0; h countTypes; h) {Class? clazz eventTypes.get(h);// 7、遍历集合发送单个事件subscriptionFound | postSingleEventForEventType(event, postingState, clazz);}} else {subscriptionFound postSingleEventForEventType(event, postingState, eventClass);}if (!subscriptionFound) {if (logNoSubscriberMessages) {logger.log(Level.FINE, No subscribers registered for event eventClass);}if (sendNoSubscriberEvent eventClass ! NoSubscriberEvent.class eventClass ! SubscriberExceptionEvent.class) {post(new NoSubscriberEvent(this, event));}}}private static ListClass? lookupAllEventTypes(Class? eventClass) {synchronized (eventTypesCache) {// 获取事件集合ListClass? eventTypes eventTypesCache.get(eventClass);if (eventTypes null) { //如果为空eventTypes new ArrayList();Class? clazz eventClass;while (clazz ! null) {eventTypes.add(clazz); //添加事件addInterfaces(eventTypes, clazz.getInterfaces()); //添加当前事件的接口classclazz clazz.getSuperclass();// 获取当前事件的父类}eventTypesCache.put(eventClass, eventTypes);}return eventTypes;}}//循环添加当前事件的接口classstatic void addInterfaces(ListClass? eventTypes, Class?[] interfaces) {for (Class? interfaceClass : interfaces) {if (!eventTypes.contains(interfaceClass)) {eventTypes.add(interfaceClass);addInterfaces(eventTypes, interfaceClass.getInterfaces());}}}private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class? eventClass) {CopyOnWriteArrayListSubscription subscriptions;synchronized (this) {// 8、根据事件获取所有订阅它的订阅者subscriptions subscriptionsByEventType.get(eventClass);}if (subscriptions ! null !subscriptions.isEmpty()) {// 9、遍历集合for (Subscription subscription : subscriptions) {postingState.event event;postingState.subscription subscription;boolean aborted false;try {// 10、将事件发送给订阅者postToSubscription(subscription, event, postingState.isMainThread);aborted postingState.canceled;} finally {// 11、重置postingStatepostingState.event null;postingState.subscription null;postingState.canceled false;}if (aborted) {break;}}return true;}return false;}private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {// 12、根据订阅方法的线程模式调用订阅方法switch (subscription.subscriberMethod.threadMode) {case POSTING: //默认类型表示发送事件操作直接调用订阅者的响应方法不需要进行线程间的切换invokeSubscriber(subscription, event);break;case MAIN: //主线程表示订阅者的响应方法在主线程进行接收事件if (isMainThread) { //如果发送者在主线程invokeSubscriber(subscription, event);//直接调用订阅者的响应方法} else { //如果事件的发送者不是主线程//添加到mainThreadPoster的队列中去在主线程中调用响应方法mainThreadPoster.enqueue(subscription, event); }break;case MAIN_ORDERED:// 主线程优先模式if (mainThreadPoster ! null) {mainThreadPoster.enqueue(subscription, event);} else {//如果不是主线程就在消息发送者的线程中进行调用响应方法invokeSubscriber(subscription, event);}break;case BACKGROUND:if (isMainThread) {// 如果事件发送者在主线程加入到backgroundPoster的队列中在线程池中调用响应方法backgroundPoster.enqueue(subscription, event);} else {// 如果不是主线程在事件发送者所在的线程调用响应方法invokeSubscriber(subscription, event);}break;case ASYNC://这里没有进行线程的判断也就是说不管是不是在主线程中都会在子线程中调用响应方法asyncPoster.enqueue(subscription, event);break;default:throw new IllegalStateException(Unknown thread mode: subscription.subscriberMethod.threadMode);}}... }获取当前线程的事件集合将要发送的事件加入到集合中。通过循环只要事件集合中还有事件就一直发送。获取事件的Class对象找到当前的event的所有父类和实现的接口的class集合。遍历这个集合调用发送单个事件的方法进行发送。根据事件获取所有订阅它的订阅者集合遍历集合将事件发送给订阅者。发送给订阅者时根据订阅方法的线程模式调用订阅方法如果需要线程切换则切换线程进行调用否则直接调用。 postSticky EventBus.getDefault().postSticky(Object event) public class EventBus {public void postSticky(Object event) {synchronized (stickyEvents) {// 1、将事件添加到粘性事件集合中stickyEvents.put(event.getClass(), event);}// 2、发送事件post(event);} }将粘性事件加入到EventBus对象的粘性事件集合中当有新的订阅者进入后如果该订阅者订阅了该粘性事件可以直接发送给订阅者。将粘性事件发送给已有的事件订阅者。 unregister EventBus.getDefault().unregister(Object subscriber) 解注册的方法。 public class EventBus {...public synchronized void unregister(Object subscriber) {// 1、获取订阅者订阅的所有事件ListClass? subscribedTypes typesBySubscriber.get(subscriber);if (subscribedTypes ! null) {// 2、遍历集合for (Class? eventType : subscribedTypes) {// 3、将该订阅者的从订阅该事件的所有订阅者集合中移除unsubscribeByEventType(subscriber, eventType);}// 4、将订阅者从集合中移除typesBySubscriber.remove(subscriber);} else {logger.log(Level.WARNING, Subscriber to unregister was not registered before: subscriber.getClass());}}private void unsubscribeByEventType(Object subscriber, Class? eventType) {// 获取该事件的所有订阅者ListSubscription subscriptions subscriptionsByEventType.get(eventType);if (subscriptions ! null) {int size subscriptions.size();// 遍历集合for (int i 0; i size; i) {Subscription subscription subscriptions.get(i);// 将订阅者从集合中移除if (subscription.subscriber subscriber) {subscription.active false;subscriptions.remove(i);i--;size--;}}}}... }1、获取订阅者的所有订阅方法遍历这些方法。然后拿到每个方法对应的所有订阅者集合将订阅者从集合中移除。 2、移除订阅者中所有的订阅方法。 参考 greenrobot/EventBus(github.com)EventBus源码解析 - 掘金 (juejin.cn)
http://www.hkea.cn/news/14368960/

相关文章:

  • 江苏省义务教育标准化建设网站主营网站建设会计记账
  • 网站备案复查 手机号码打不通哇哈哈网站建设策划书
  • 珠海自适应网站建设c2c网站类型
  • 做音频的网站屯溪网站建设
  • 江苏分销网站建设建设部工程业绩网站
  • 网站 留言板 制作wordpress 更换字体
  • 南通网站定制哪家好app线下推广怎么做
  • 了解当前各类网站建设价格网站备案符号
  • 万全网站建设wl17581网页制作软件是应用软件吗
  • 重庆做木门网站公司如何购买域名和空间
  • 市场监督局网站电子签名怎么做泰安有什么好的网络科技公司
  • 企业站群系统wordpress赞的代码
  • 做网站找个人还是找公司超实用网站
  • wordpress MU多重筛选企业网站优化培训
  • wordpress更改默认登录页面深圳seo优化培训
  • 贵阳市小程序网站开发公司做网站找沈阳横纵网络
  • 国外优秀企业网站表白网页在线生成器
  • 岳阳建设商城网站公司wordpress 皮肤
  • 企业建设网站的案例win10优化大师怎么样
  • 徐州企业制作网站asp网站打开速度慢
  • 电商平台网站镇江市精神文明建设网站
  • 长春网站制作方案定制网站你们都知道
  • asp做网站的步骤天津百度公司总部
  • 校园门户网站建设服务器租用泰海
  • 怎么给网站加代码冠县网站建设电话
  • 重庆wordpress网站建设微信代运营合作方案
  • 电商网站开发数据库设计企业如何应用网站的
  • 沈阳网站建设制作公司少女たちよ在线观看动漫4
  • 国际进出口贸易网站wordpress站点维护
  • 深圳光明新区网站建设5118站长工具