IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Glide源码(4.11.0)主线流程梳理(一)---with方法的内部逻辑 -> 正文阅读

[移动开发]Glide源码(4.11.0)主线流程梳理(一)---with方法的内部逻辑

本文旨在梳理代码流程

  • Glide的使用
Glide.with(this).load(imageUrl).into(view);
  • 第一步with,涉及到的几个关键的类
  1. Glide:主要做一些 init 工作,比如缓存,线程池,复用池的构建等等
  2. RequestManagerRetriever :主要是获得一个 RequestManager 请求管理类,然后绑定一个 Fragment
  3. SupportRequestManagerFragment :空白的fragment,用于管理请求的生命周期
  4. RequestManager:主要用于对请求的管理封装

with 重载方法

public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
  }

  @NonNull
  public static RequestManager with(@NonNull Activity activity) {
    return getRetriever(activity).get(activity);
  }

  @NonNull
  public static RequestManager with(@NonNull FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }

  @NonNull
  public static RequestManager with(@NonNull Fragment fragment) {
    return getRetriever(fragment.getContext()).get(fragment);
  }
  
  @SuppressWarnings("deprecation")
  @Deprecated
  @NonNull
  public static RequestManager with(@NonNull android.app.Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
  }
  @NonNull
  public static RequestManager with(@NonNull View view) {
    return getRetriever(view.getContext()).get(view);
  }

上面其实常用的就 Activity,Fragment, Context 这 3 种形式,下面我们就以 Activity 为主

  • getRetriever(activity)
  @NonNull
  private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    //...
    return Glide.get(context).getRequestManagerRetriever();
  }

Glide.get(context):这里是最简单的DCL单例模式,或者Glide对象

  @NonNull
  public static Glide get(@NonNull Context context) {
    if (glide == null) {
    // 这里拿到 @GlideModule 标识的注解处理器生成的 GeneratedAppGlideModuleImpl、                                   //GeneratedAppGlideModuleFactory ...等等。
      GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules(context.getApplicationContext());
      synchronized (Glide.class) {
        if (glide == null) {
          checkAndInitializeGlide(context, annotationGeneratedModule);
        }
      }
    }
    return glide;
  }

接着看一下glide对象的创建过程
1,checkAndInitializeGlide(context, annotationGeneratedModule);

  @GuardedBy("Glide.class")
  private static void checkAndInitializeGlide(
      @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
    if (isInitializing) {
      //如果正在初始化,这里就抛异常,不继续执行后续代码
    }
    // 开始初始化的标记
    isInitializing = true;
    // 开始初始化
    initializeGlide(context, generatedAppGlideModule);
    // 初始化结束
    isInitializing = false;
  }

2,initializeGlide(context, generatedAppGlideModule);

  @GuardedBy("Glide.class")
  private static void initializeGlide(
      @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
    //实例化一个 GlideBuilder 在进行初始化
   	//GlideBuilder 默认的一些配置信息
    initializeGlide(context, new GlideBuilder(), generatedAppGlideModule);
  }

3,initializeGlide(context, new GlideBuilder(), generatedAppGlideModule);

  @GuardedBy("Glide.class")
  @SuppressWarnings("deprecation")
  private static void initializeGlide(
      @NonNull Context context,
      @NonNull GlideBuilder builder,
      @Nullable GeneratedAppGlideModule annotationGeneratedModule) {
      //1. 拿到应用级别的上下文,这里可以避免内存泄漏,我们实际开发也可以通过这种形式拿上下文。
    Context applicationContext = context.getApplicationContext();
      // ...
      // 通过注解生成的代码拿到 RequestManagerFactory
    RequestManagerRetriever.RequestManagerFactory factory =
        annotationGeneratedModule != null
            ? annotationGeneratedModule.getRequestManagerFactory()
            : null;
    //将拿到的工厂添加到 GlideBuilder
    builder.setRequestManagerFactory(factory);
    // ...
    // 这里通过 Builder 建造者模式,构建出 Glide 实例对象
    Glide glide = builder.build(applicationContext);
    // 开始注册组件回调
    for (com.bumptech.glide.module.GlideModule module : manifestModules) {
      try {
        module.registerComponents(applicationContext, glide, glide.registry);
      } catch (AbstractMethodError e) {
        throw new IllegalStateException(
            "Attempting to register a Glide v3 module. If you see this, you or one of your"
                + " dependencies may be including Glide v3 even though you're using Glide v4."
                + " You'll need to find and remove (or update) the offending dependency."
                + " The v3 module name is: "
                + module.getClass().getName(),
            e);
      }
    }
    if (annotationGeneratedModule != null) {
      annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
    }
    applicationContext.registerComponentCallbacks(glide);
    //将构建出来的 glide 赋值给 Glide 的静态变量
    Glide.glide = glide;
  }

上面的代码可以看到是通过构建者模式创建的glide

public final class GlideBuilder {
  private final Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions = new ArrayMap<>();
  private Engine engine;//管理线程池
  //对象池(享元模式),这样做避免重复创建对象,对内存开销有一定效果
  private BitmapPool bitmapPool;
  private ArrayPool arrayPool;
  private MemoryCache memoryCache;
  //GlideExecutor 线程池
  private GlideExecutor sourceExecutor;
  private GlideExecutor diskCacheExecutor;
  //本地磁盘缓存
  private DiskCache.Factory diskCacheFactory;
  // 内存缓存
  private MemorySizeCalculator memorySizeCalculator;
  
  // ...
  
  @NonNull
  Glide build(@NonNull Context context) {
  	//实例化一个网络请求的线程池
    if (sourceExecutor == null) {
      sourceExecutor = GlideExecutor.newSourceExecutor();
    }
	//实例化一个本地磁盘缓存的线程池
    if (diskCacheExecutor == null) {
      diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
    }
	//实例化一个加载图片动画的一个线程池
    if (animationExecutor == null) {
      animationExecutor = GlideExecutor.newAnimationExecutor();
    }
	//实例化一个对图片加载到内存的一个计算
    if (memorySizeCalculator == null) {
      memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
    }
	//实例化一个默认网络连接监控的工厂
    if (connectivityMonitorFactory == null) {
      connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
    }
	//实例化一个 Bitmap 对象池
    if (bitmapPool == null) {
      int size = memorySizeCalculator.getBitmapPoolSize();
      //如果池子里还有可用的,直接加入 最近最少使用的 LruBitmap 容器里
      if (size > 0) {
        bitmapPool = new LruBitmapPool(size);
      } else {
      //如果池子已经满了,那么就装在 BitmapPoolAdapter
        bitmapPool = new BitmapPoolAdapter();
      }
    }
	//实例化一个数组对象池
    if (arrayPool == null) {
      arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
    }
	//资源内存缓存
    if (memoryCache == null) {
      memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
    }
	//磁盘缓存的工厂
    if (diskCacheFactory == null) {
      diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    }
	//构建执行缓存策略跟线程池的引擎
    if (engine == null) {
      engine =
          new Engine(
              memoryCache,
              diskCacheFactory,
              diskCacheExecutor,
              sourceExecutor,
              GlideExecutor.newUnlimitedSourceExecutor(),
              animationExecutor,
              isActiveResourceRetentionAllowed);
    }

    if (defaultRequestListeners == null) {
      defaultRequestListeners = Collections.emptyList();
    } else {
      defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
    }
	//实例化一个 RequestManagerRetriever 请求管理类
    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory);
	//实例化 Glide 的地方
    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptionsFactory,
        defaultTransitionOptions,
        defaultRequestListeners,
        isLoggingRequestOriginsEnabled,
        isImageDecoderEnabledForBitmaps);
  }
}

上面的代码中,builder 主要构建线程池、复用池、缓存策略、执行 Engine ,最后构建 Glide 实例,我们看看 Glide 怎么实例化的,主要看对应的构造函数就行了。

 Glide(
      @NonNull Context context,
      @NonNull Engine engine,
      @NonNull MemoryCache memoryCache,
      @NonNull BitmapPool bitmapPool,
      @NonNull ArrayPool arrayPool,
      @NonNull RequestManagerRetriever requestManagerRetriever,
      @NonNull ConnectivityMonitorFactory connectivityMonitorFactory,
      int logLevel,
      @NonNull RequestOptionsFactory defaultRequestOptionsFactory,
      @NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,
      @NonNull List<RequestListener<Object>> defaultRequestListeners,
      boolean isLoggingRequestOriginsEnabled,
      boolean isImageDecoderEnabledForBitmaps) {
      //将 Builder 构建的线程池,对象池,缓存池保存到 Glide 中
    this.engine = engine;
    this.bitmapPool = bitmapPool;
    this.arrayPool = arrayPool;
    this.memoryCache = memoryCache;
    this.requestManagerRetriever = requestManagerRetriever;
    this.connectivityMonitorFactory = connectivityMonitorFactory;
    this.defaultRequestOptionsFactory = defaultRequestOptionsFactory;
    
	// ... 
	
	//用于显示对应图片的工厂
    ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
    //构建一个 Glide 专属的 上下文
    glideContext =
        new GlideContext(
            context,
            arrayPool,
            registry,
            imageViewTargetFactory,
            defaultRequestOptionsFactory,
            defaultTransitionOptions,
            defaultRequestListeners,
            engine,
            isLoggingRequestOriginsEnabled,
            logLevel);
  }

上面有一个 GlideContentx 这个是什么鬼? 其实就是 Context一个级别的上下文而已

public class GlideContext extends ContextWrapper{ }

到这里我们已经知道了 缓存策略、Glide、GlideContext 怎么构建出来的了,下面我们看怎么拿到 请求管理类 RequestManager

  • getRetriever(activity).get(activity); 最终是返回 RequestManager:
    这里的 get 也有很多重载的函数,挑一个 Activity 参数的重载,着重看看:
public class RequestManagerRetriever implements Handler.Callback {
// 获取应用级别的 RequestManager,生命周期与应用程序一样
@NonNull
  private RequestManager getApplicationManager(@NonNull Context context) {
    // Either an application context or we're on a background thread.
    if (applicationManager == null) {
      synchronized (this) {
        if (applicationManager == null) {
          Glide glide = Glide.get(context.getApplicationContext());
          applicationManager =
              factory.build(
                  glide,
                  new ApplicationLifecycle(),
                  new EmptyRequestManagerTreeNode(),
                  context.getApplicationContext());
        }
      }
    }

    return applicationManager;
  }
 @NonNull
  public RequestManager get(@NonNull Context context) {
    if (context == null) {
      throw new IllegalArgumentException("You cannot start a load on a null Context");
    } else if (Util.isOnMainThread() && !(context instanceof Application)) {//如果在主线程中并且不为 Application 级别的 Context 执行
      if (context instanceof FragmentActivity) {
        return get((FragmentActivity) context);
      } else if (context instanceof Activity) {
        return get((Activity) context);
      } else if (context instanceof ContextWrapper
          && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }
    return getApplicationManager(context);
  }

  @NonNull
  public RequestManager get(@NonNull FragmentActivity activity) { ... }

  @NonNull
  public RequestManager get(@NonNull Fragment fragment) {
    ...
    }

  @SuppressWarnings("deprecation")
  @NonNull
  public RequestManager get(@NonNull Activity activity) {
    if (Util.isOnBackgroundThread()) {//判断当前是否在子线程中请求任务
    //通过 Application 级别的 Context 加载
      return get(activity.getApplicationContext());
    } else {
    //检查 Activity 是否已经销毁
      assertNotDestroyed(activity);
      //拿到当前 Activity 的 FragmentManager 
      android.app.FragmentManager fm = activity.getFragmentManager();
      //主要是生成一个 Fragment 然后绑定一个请求管理 RequestManager
      return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

  @SuppressWarnings("deprecation")
  @NonNull
  public RequestManager get(@NonNull View view) {
    ... 
  }
}

继续看下面的代码,虽然已经吐血身亡,但是还是需要坚持,看源码 靠的是谁耐得住寂寞,谁就是赢家

fragmentGet方法的实现

  @Deprecated
  @NonNull
  private RequestManager fragmentGet(
      @NonNull Context context,
      @NonNull android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    // 在当前的 Acitivty 添加一个 Fragment 用于管理请求的生命周期
    RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
    //拿到当前请求的管理类
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      //如果不存在,则创建一个请求管理者保持在当前管理生命周期的 Fragment 中,相当于 2 者进行绑定,避免内存泄漏
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    //返回当前请求的管理者
    return requestManager;
  }

通过上面的代码可知,这里用于 Fragment 管理请求的生命周期,那么我们具体来看看 Fragment 怎么添加到 Activity 中的呢
在上面的代码里,fragmentGet()里面有一行代码:

RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);

现在来看一下getRequestManagerFragment()这个方法是如何获取fragment的

  @NonNull
  private RequestManagerFragment getRequestManagerFragment(
      @NonNull final android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
      //通过 TAG 拿到已经实例化过的 Fragment ,相当于如果同一个 Activity Glide.with..多次,那么就没有必要创建多个
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {//如果在当前 Activity 中没有拿到管理请求生命周期的 Fragment ,那么就从缓存中看有没有
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {//如果缓存也没有得,就直接实例化一个 Fragment
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {//如果已经有执行的请求就开始
          current.getGlideLifecycle().onStart();
        }
        //添加到 Map 缓存中
        pendingRequestManagerFragments.put(fm, current);
        //通过当前 Activity 的 FragmentManager 开始提交添加一个 Fragment 容器
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        //添加到 FragmentManager 成功,发送清理缓存
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

我们知道,with之后,最终返回RequestManager对象, 我们需要对RequestManager对象的构建,有一个来龙去脉的学习:

// 注意:此工厂就是为了构建出 RequestManager对象 
 private static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() {
    @NonNull
    @Override
    public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle,
        @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) {
      //实例化
      return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
    }
  };

你只要敢 new RequestManager(…); 就会进入 RequestManager的构造方法:

  public RequestManager(
      @NonNull Glide glide,
      @NonNull Lifecycle lifecycle,
      @NonNull RequestManagerTreeNode treeNode,
      @NonNull Context context) {
    this(
        glide,
        lifecycle,
        treeNode,
        new RequestTracker(),
        glide.getConnectivityMonitorFactory(),
        context);
  }
  RequestManager(
      Glide glide,
      Lifecycle lifecycle,
      RequestManagerTreeNode treeNode,
      RequestTracker requestTracker,
      ConnectivityMonitorFactory factory,
      Context context) {
    this.glide = glide;
    this.lifecycle = lifecycle;
    this.treeNode = treeNode;
    this.requestTracker = requestTracker;
    this.context = context;

    connectivityMonitor =
        factory.build(
            context.getApplicationContext(),
            new RequestManagerConnectivityListener(requestTracker));

    // If we're the application level request manager, we may be created on a background thread.
    // In that case we cannot risk synchronously pausing or resuming requests, so we hack around the
    // issue by delaying adding ourselves as a lifecycle listener by posting to the main thread.
    // This should be entirely safe.
    // 添加生命周期监听
    if (Util.isOnBackgroundThread()) {
      mainHandler.post(addSelfToLifecycle);
    } else {
      lifecycle.addListener(this);
    }
    //添加网络变化的监听
    lifecycle.addListener(connectivityMonitor);

    defaultRequestListeners =
        new CopyOnWriteArrayList<>(glide.getGlideContext().getDefaultRequestListeners());
    setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());

    glide.registerRequestManager(this);
  }

到这里请求管理类 RequestManager + Fragment 已经绑定成功了,声明周期监听也设置了,那他们相互是怎么保证生命周期的传递勒,我们主要看 Fragment 生命周期方法

public class RequestManagerFragment extends Fragment {
	// 生命周期的回调
	private final ActivityFragmentLifecycle lifecycle;
	...

	
  @Override
  public void onStart() {
    super.onStart();
    lifecycle.onStart();
  }

  @Override
  public void onStop() {
    super.onStop();
    lifecycle.onStop();
  }

  @Override
  public void onDestroy() {
    super.onDestroy();
    lifecycle.onDestroy();
    unregisterFragmentWithRoot();
  }
}

这里的 lifecycle 是什么,在深入的看一下:

class ActivityFragmentLifecycle implements Lifecycle {
  private final Set<LifecycleListener> lifecycleListeners =
      Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
  private boolean isStarted;
  private boolean isDestroyed;

  /**
   * Adds the given listener to the list of listeners to be notified on each lifecycle event.
   *
   * <p>The latest lifecycle event will be called on the given listener synchronously in this
   * method. If the activity or fragment is stopped, {@link LifecycleListener#onStop()}} will be
   * called, and same for onStart and onDestroy.
   *
   * <p>Note - {@link com.bumptech.glide.manager.LifecycleListener}s that are added more than once
   * will have their lifecycle methods called more than once. It is the caller's responsibility to
   * avoid adding listeners multiple times.
   */
  @Override
  public void addListener(@NonNull LifecycleListener listener) {
    lifecycleListeners.add(listener);

    if (isDestroyed) {
      listener.onDestroy();
    } else if (isStarted) {
      listener.onStart();
    } else {
      listener.onStop();
    }
  }

  @Override
  public void removeListener(@NonNull LifecycleListener listener) {
    lifecycleListeners.remove(listener);
  }

  void onStart() {
    isStarted = true;
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
      lifecycleListener.onStart();
    }
  }

  void onStop() {
    isStarted = false;
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
      lifecycleListener.onStop();
    }
  }

  void onDestroy() {
    isDestroyed = true;
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
      lifecycleListener.onDestroy();
    }
  }
}

看到这里知道了吧,它实现的是 Glide 中的 Lifecycle 生命周期接口,注册是在刚刚我们讲解 RequestManagerFactory 工厂中实例化的 RequestManager 然后在构造函数中添加了生命周期回调监听,具体来看下

public class RequestManager implements LifecycleListener,
    ModelTypes<RequestBuilder<Drawable>> {
  ...
  @Override
  public synchronized void onStart() {
    resumeRequests();
    targetTracker.onStart();
  }

  @Override
  public synchronized void onStop() {
    pauseRequests();
    targetTracker.onStop();
  }

  @Override
  public synchronized void onDestroy() {
    targetTracker.onDestroy();
    for (Target<?> target : targetTracker.getAll()) {
      clear(target);
    }
    targetTracker.clear();
    requestTracker.clearRequests();
    lifecycle.removeListener(this);
    lifecycle.removeListener(connectivityMonitor);
    mainHandler.removeCallbacks(addSelfToLifecycle);
    glide.unregisterRequestManager(this);
  }
  ...      
}

注意:这 3 处回调就是 Fragment 传递过来的,用于实时监听请求的状态。

with总结:

根据 with 源码分析,我们知道,Glide.with(Activity) 主要做了 线程池 + 缓存 + 请求管理与生命周期绑定+其它配置初始化的构建,内部的代码其实是很庞大的

后续

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-03-10 22:41:17  更:2022-03-10 22:43:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 18:52:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码