区块链技术博客
www.b2bchain.cn

ToastUtils-我愿称之为最强求职学习资料

D0b2wT.gif

本文介绍了ToastUtils-我愿称之为最强求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。

对技术面试,学习经验等有一些体会,在此分享。

背景

在 Android 11 上谷歌对 Toast 进行了变更,导致 Toast#getView() 返回 null,具体可以查看文档 Android 11 中消息框的更新,对此,AndroidUtilCode 在 1.30.0 版本已进行了适配,关于新版本做了哪些事情具体可以查看 1.30.0 版本日志,其中就包括重构 ToastUtils,其重构后的 APIs 如下所示:

吐司相关 -> [ToastUtils.java][toast.java] -> [Demo][toast.demo]

make                     : 制作吐司 make.setMode             : 设置模式 make.setGravity          : 设置位置 make.setBgColor          : 设置背景颜色 make.setBgResource       : 设置背景资源 make.setTextColor        : 设置字体颜色 make.setTextSize         : 设置字体大小 make.setDurationIsLong   : 设置是否长时间显示 make.setLeftIcon         : 设置左侧图标 make.setTopIcon          : 设置顶部图标 make.setRightIcon        : 设置右侧图标 make.setBottomIcon       : 设置底部图标 make.setNotUseSystemToast: 设置不使用系统吐司 make.show                : 显示吐司 getDefaultMaker          : 获取默认制作实例(控制 showShort、showLong 样式)1.30.1 新增 showShort                : 显示短时吐司 showLong                 : 显示长时吐司 cancel                   : 取消吐司显示

使用

作为工具类,基本是看完 APIs 就知道该如何使用了,我这里就做下简单的介绍,想玩 Demo 的话可以在 1.30.0 版本日志 中下载。

// 短时间显示 toast ToastUtils.showShort(xxx)  // 长时间显示 toast ToastUtils.showLong(xxx)  // 长时间显示带左侧 icon 的暗黑模式 toast ToastUtils.make().setLeftIcon(icon).setDurationIsLong(true).setMode(ToastUtils.MODE.DARK).show(xxx)  // 自定义 toast private fun show(text: CharSequence, isLong: Boolean) {     val textView = ViewUtils.layoutId2View(R.layout.toast_custom) as TextView     textView.text = text     ToastUtils.make().setDurationIsLong(isLong).show(textView) }

源码分析

系统 Toast 展示是需要有通知权限的(某些修改了 ROM 手机除外),所以如果不进行处理的话,关闭了通知权限就会导致 Toast 不显示的 BUG,针对不同版本及权限我们有不同的处理方案,下面来看下工具类中的相关代码:

// 最终 show 都会走到这个函数来处理 private static void show(@Nullable final View view, final CharSequence text, final int duration, final ToastUtils utils) {     UtilsBridge.runOnUiThread(new Runnable() {         @Override         public void run() {             cancel();             iToast = newToast(utils);             if (view != null) {                 iToast.setToastView(view);             } else {                 iToast.setToastView(text);             }             iToast.show(duration);         }     }); }  private static IToast newToast(ToastUtils toastUtils) {     if (!toastUtils.isNotUseSystemToast) {         if (NotificationManagerCompat.from(Utils.getApp()).areNotificationsEnabled()) {             if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {                 return new SystemToast(toastUtils);             }             if (!UtilsBridge.isGrantedDrawOverlays()) {                 return new SystemToast(toastUtils);             }         }     }     // not use system or notification disable     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {         return new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_TOAST);     } else if (UtilsBridge.isGrantedDrawOverlays()) {         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {             new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);         } else {             new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_PHONE);         }     }     return new ActivityToast(toastUtils); }

可以看到我们有 SystemToastWindowManagerToastActivityToast 三种类型的 Toast,它们都继承自 AbsToast,其相关源码如下所示:

static abstract class AbsToast implements IToast {      protected Toast      mToast;     protected ToastUtils mToastUtils;     protected View       mToastView;      AbsToast(ToastUtils toastUtils) {         mToast = new Toast(Utils.getApp());         mToastUtils = toastUtils;         if (mToastUtils.mGravity != -1 || mToastUtils.mXOffset != -1 || mToastUtils.mYOffset != -1) {             mToast.setGravity(mToastUtils.mGravity, mToastUtils.mXOffset, mToastUtils.mYOffset);         }     }      @Override     public void setToastView(View view) {         mToastView = view;         mToast.setView(mToastView);     }      @Override     public void setToastView(CharSequence text) {         // 当设置了 mode 或者 设置了 icon 则会使用 utils_toast_view 布局         View utilsToastView = mToastUtils.tryApplyUtilsToastView(text);         if (utilsToastView != null) {             setToastView(utilsToastView);             return;         }         // API30 getView() 为空,则使用 utils_toast_view 布局来兼容         mToastView = mToast.getView();         if (mToastView == null || mToastView.findViewById(android.R.id.message) == null) {             setToastView(UtilsBridge.layoutId2View(R.layout.utils_toast_view));         }         TextView messageTv = mToastView.findViewById(android.R.id.message);         messageTv.setText(text);         if (mToastUtils.mTextColor != COLOR_DEFAULT) {             messageTv.setTextColor(mToastUtils.mTextColor);         }         if (mToastUtils.mTextSize != -1) {             messageTv.setTextSize(mToastUtils.mTextSize);         }         setBg(messageTv);     }      protected void setBg(final TextView msgTv) {         if (mToastUtils.mBgResource != -1) {             mToastView.setBackgroundResource(mToastUtils.mBgResource);             msgTv.setBackgroundColor(Color.TRANSPARENT);         } else if (mToastUtils.mBgColor != COLOR_DEFAULT) {             Drawable toastBg = mToastView.getBackground();             Drawable msgBg = msgTv.getBackground();             if (toastBg != null && msgBg != null) {                 toastBg.mutate().setColorFilter(new PorterDuffColorFilter(mToastUtils.mBgColor, PorterDuff.Mode.SRC_IN));                 msgTv.setBackgroundColor(Color.TRANSPARENT);             } else if (toastBg != null) {                 toastBg.mutate().setColorFilter(new PorterDuffColorFilter(mToastUtils.mBgColor, PorterDuff.Mode.SRC_IN));             } else if (msgBg != null) {                 msgBg.mutate().setColorFilter(new PorterDuffColorFilter(mToastUtils.mBgColor, PorterDuff.Mode.SRC_IN));             } else {                 mToastView.setBackgroundColor(mToastUtils.mBgColor);             }         }     }      @Override     @CallSuper     public void cancel() {         if (mToast != null) {             mToast.cancel();         }         mToast = null;         mToastView = null;     } }  interface IToast {     void setToastView(View view);     void setToastView(CharSequence text);     void show(int duration);     void cancel(); }

这部分代码比较简单,很多都是做兼容处理,我就不做解释了,下面我们依次来看 SystemToastWindowManagerToastActivityToast

“`java
static final class SystemToast extends AbsToast {

SystemToast(ToastUtils toastUtils) {     super(toastUtils);     if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) {         try {             //noinspection JavaReflectionMemberAccess             Field mTNField = Toast.class.getDeclaredField("mTN");             mTNField.setAccessible(true);             Object mTN = mTNField.get(mToast);             Field mTNmHandlerField = mTNField.getType().getDeclaredField("mHandler");             mTNmHandlerField.setAccessible(true);             Handler tnHandler = (Handler) mTNmHandlerField.get(mTN);             mTNmHandlerField.set(mTN, new SafeHandler(tnHandler));         } catch (Exception ignored) {}     } }  @Override public void show(int duration) {     if (mToast == null) return;     mToast.setDuration(duration);     mToast.show(); }  static class SafeHandler extends Handler {     private Handler impl;      SafeHandler(Handler impl) {         this.impl = impl;     }      @Override     public void handleMessage(@NonNull Message msg) {         impl.handleMessage(msg);     }      @Override     public void dispatchMessage(@NonNull Message msg) {

背景

在 Android 11 上谷歌对 Toast 进行了变更,导致 Toast#getView() 返回 null,具体可以查看文档 Android 11 中消息框的更新,对此,AndroidUtilCode 在 1.30.0 版本已进行了适配,关于新版本做了哪些事情具体可以查看 1.30.0 版本日志,其中就包括重构 ToastUtils,其重构后的 APIs 如下所示:

吐司相关 -> [ToastUtils.java][toast.java] -> [Demo][toast.demo]

make                     : 制作吐司 make.setMode             : 设置模式 make.setGravity          : 设置位置 make.setBgColor          : 设置背景颜色 make.setBgResource       : 设置背景资源 make.setTextColor        : 设置字体颜色 make.setTextSize         : 设置字体大小 make.setDurationIsLong   : 设置是否长时间显示 make.setLeftIcon         : 设置左侧图标 make.setTopIcon          : 设置顶部图标 make.setRightIcon        : 设置右侧图标 make.setBottomIcon       : 设置底部图标 make.setNotUseSystemToast: 设置不使用系统吐司 make.show                : 显示吐司 getDefaultMaker          : 获取默认制作实例(控制 showShort、showLong 样式)1.30.1 新增 showShort                : 显示短时吐司 showLong                 : 显示长时吐司 cancel                   : 取消吐司显示

使用

作为工具类,基本是看完 APIs 就知道该如何使用了,我这里就做下简单的介绍,想玩 Demo 的话可以在 1.30.0 版本日志 中下载。

// 短时间显示 toast ToastUtils.showShort(xxx)  // 长时间显示 toast ToastUtils.showLong(xxx)  // 长时间显示带左侧 icon 的暗黑模式 toast ToastUtils.make().setLeftIcon(icon).setDurationIsLong(true).setMode(ToastUtils.MODE.DARK).show(xxx)  // 自定义 toast private fun show(text: CharSequence, isLong: Boolean) {     val textView = ViewUtils.layoutId2View(R.layout.toast_custom) as TextView     textView.text = text     ToastUtils.make().setDurationIsLong(isLong).show(textView) }

源码分析

系统 Toast 展示是需要有通知权限的(某些修改了 ROM 手机除外),所以如果不进行处理的话,关闭了通知权限就会导致 Toast 不显示的 BUG,针对不同版本及权限我们有不同的处理方案,下面来看下工具类中的相关代码:

// 最终 show 都会走到这个函数来处理 private static void show(@Nullable final View view, final CharSequence text, final int duration, final ToastUtils utils) {     UtilsBridge.runOnUiThread(new Runnable() {         @Override         public void run() {             cancel();             iToast = newToast(utils);             if (view != null) {                 iToast.setToastView(view);             } else {                 iToast.setToastView(text);             }             iToast.show(duration);         }     }); }  private static IToast newToast(ToastUtils toastUtils) {     if (!toastUtils.isNotUseSystemToast) {         if (NotificationManagerCompat.from(Utils.getApp()).areNotificationsEnabled()) {             if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {                 return new SystemToast(toastUtils);             }             if (!UtilsBridge.isGrantedDrawOverlays()) {                 return new SystemToast(toastUtils);             }         }     }     // not use system or notification disable     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {         return new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_TOAST);     } else if (UtilsBridge.isGrantedDrawOverlays()) {         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {             new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);         } else {             new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_PHONE);         }     }     return new ActivityToast(toastUtils); }

可以看到我们有 SystemToastWindowManagerToastActivityToast 三种类型的 Toast,它们都继承自 AbsToast,其相关源码如下所示:

static abstract class AbsToast implements IToast {      protected Toast      mToast;     protected ToastUtils mToastUtils;     protected View       mToastView;      AbsToast(ToastUtils toastUtils) {         mToast = new Toast(Utils.getApp());         mToastUtils = toastUtils;         if (mToastUtils.mGravity != -1 || mToastUtils.mXOffset != -1 || mToastUtils.mYOffset != -1) {             mToast.setGravity(mToastUtils.mGravity, mToastUtils.mXOffset, mToastUtils.mYOffset);         }     }      @Override     public void setToastView(View view) {         mToastView = view;         mToast.setView(mToastView);     }      @Override     public void setToastView(CharSequence text) {         // 当设置了 mode 或者 设置了 icon 则会使用 utils_toast_view 布局         View utilsToastView = mToastUtils.tryApplyUtilsToastView(text);         if (utilsToastView != null) {             setToastView(utilsToastView);             return;         }         // API30 getView() 为空,则使用 utils_toast_view 布局来兼容         mToastView = mToast.getView();         if (mToastView == null || mToastView.findViewById(android.R.id.message) == null) {             setToastView(UtilsBridge.layoutId2View(R.layout.utils_toast_view));         }         TextView messageTv = mToastView.findViewById(android.R.id.message);         messageTv.setText(text);         if (mToastUtils.mTextColor != COLOR_DEFAULT) {             messageTv.setTextColor(mToastUtils.mTextColor);         }         if (mToastUtils.mTextSize != -1) {             messageTv.setTextSize(mToastUtils.mTextSize);         }         setBg(messageTv);     }      protected void setBg(final TextView msgTv) {         if (mToastUtils.mBgResource != -1) {             mToastView.setBackgroundResource(mToastUtils.mBgResource);             msgTv.setBackgroundColor(Color.TRANSPARENT);         } else if (mToastUtils.mBgColor != COLOR_DEFAULT) {             Drawable toastBg = mToastView.getBackground();             Drawable msgBg = msgTv.getBackground();             if (toastBg != null && msgBg != null) {                 toastBg.mutate().setColorFilter(new PorterDuffColorFilter(mToastUtils.mBgColor, PorterDuff.Mode.SRC_IN));                 msgTv.setBackgroundColor(Color.TRANSPARENT);             } else if (toastBg != null) {                 toastBg.mutate().setColorFilter(new PorterDuffColorFilter(mToastUtils.mBgColor, PorterDuff.Mode.SRC_IN));             } else if (msgBg != null) {                 msgBg.mutate().setColorFilter(new PorterDuffColorFilter(mToastUtils.mBgColor, PorterDuff.Mode.SRC_IN));             } else {                 mToastView.setBackgroundColor(mToastUtils.mBgColor);             }         }     }      @Override     @CallSuper     public void cancel() {         if (mToast != null) {             mToast.cancel();         }         mToast = null;         mToastView = null;     } }  interface IToast {     void setToastView(View view);     void setToastView(CharSequence text);     void show(int duration);     void cancel(); }

这部分代码比较简单,很多都是做兼容处理,我就不做解释了,下面我们依次来看 SystemToastWindowManagerToastActivityToast

“`java
static final class SystemToast extends AbsToast {

SystemToast(ToastUtils toastUtils) {     super(toastUtils);     if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) {         try {             //noinspection JavaReflectionMemberAccess             Field mTNField = Toast.class.getDeclaredField("mTN");             mTNField.setAccessible(true);             Object mTN = mTNField.get(mToast);             Field mTNmHandlerField = mTNField.getType().getDeclaredField("mHandler");             mTNmHandlerField.setAccessible(true);             Handler tnHandler = (Handler) mTNmHandlerField.get(mTN);             mTNmHandlerField.set(mTN, new SafeHandler(tnHandler));         } catch (Exception ignored) {}     } }  @Override public void show(int duration) {     if (mToast == null) return;     mToast.setDuration(duration);     mToast.show(); }  static class SafeHandler extends Handler {     private Handler impl;      SafeHandler(Handler impl) {         this.impl = impl;     }      @Override     public void handleMessage(@NonNull Message msg) {         impl.handleMessage(msg);     }      @Override     public void dispatchMessage(@NonNull Message msg) {

背景

在 Android 11 上谷歌对 Toast 进行了变更,导致 Toast#getView() 返回 null,具体可以查看文档 Android 11 中消息框的更新,对此,AndroidUtilCode 在 1.30.0 版本已进行了适配,关于新版本做了哪些事情具体可以查看 1.30.0 版本日志,其中就包括重构 ToastUtils,其重构后的 APIs 如下所示:

吐司相关 -> [ToastUtils.java][toast.java] -> [Demo][toast.demo]

make                     : 制作吐司 make.setMode             : 设置模式 make.setGravity          : 设置位置 make.setBgColor          : 设置背景颜色 make.setBgResource       : 设置背景资源 make.setTextColor        : 设置字体颜色 make.setTextSize         : 设置字体大小 make.setDurationIsLong   : 设置是否长时间显示 make.setLeftIcon         : 设置左侧图标 make.setTopIcon          : 设置顶部图标 make.setRightIcon        : 设置右侧图标 make.setBottomIcon       : 设置底部图标 make.setNotUseSystemToast: 设置不使用系统吐司 make.show                : 显示吐司 getDefaultMaker          : 获取默认制作实例(控制 showShort、showLong 样式)1.30.1 新增 showShort                : 显示短时吐司 showLong                 : 显示长时吐司 cancel                   : 取消吐司显示

使用

作为工具类,基本是看完 APIs 就知道该如何使用了,我这里就做下简单的介绍,想玩 Demo 的话可以在 1.30.0 版本日志 中下载。

// 短时间显示 toast ToastUtils.showShort(xxx)  // 长时间显示 toast ToastUtils.showLong(xxx)  // 长时间显示带左侧 icon 的暗黑模式 toast ToastUtils.make().setLeftIcon(icon).setDurationIsLong(true).setMode(ToastUtils.MODE.DARK).show(xxx)  // 自定义 toast private fun show(text: CharSequence, isLong: Boolean) {     val textView = ViewUtils.layoutId2View(R.layout.toast_custom) as TextView     textView.text = text     ToastUtils.make().setDurationIsLong(isLong).show(textView) }

源码分析

系统 Toast 展示是需要有通知权限的(某些修改了 ROM 手机除外),所以如果不进行处理的话,关闭了通知权限就会导致 Toast 不显示的 BUG,针对不同版本及权限我们有不同的处理方案,下面来看下工具类中的相关代码:

// 最终 show 都会走到这个函数来处理 private static void show(@Nullable final View view, final CharSequence text, final int duration, final ToastUtils utils) {     UtilsBridge.runOnUiThread(new Runnable() {         @Override         public void run() {             cancel();             iToast = newToast(utils);             if (view != null) {                 iToast.setToastView(view);             } else {                 iToast.setToastView(text);             }             iToast.show(duration);         }     }); }  private static IToast newToast(ToastUtils toastUtils) {     if (!toastUtils.isNotUseSystemToast) {         if (NotificationManagerCompat.from(Utils.getApp()).areNotificationsEnabled()) {             if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {                 return new SystemToast(toastUtils);             }             if (!UtilsBridge.isGrantedDrawOverlays()) {                 return new SystemToast(toastUtils);             }         }     }     // not use system or notification disable     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {         return new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_TOAST);     } else if (UtilsBridge.isGrantedDrawOverlays()) {         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {             new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);         } else {             new WindowManagerToast(toastUtils, WindowManager.LayoutParams.TYPE_PHONE);         }     }     return new ActivityToast(toastUtils); }

可以看到我们有 SystemToastWindowManagerToastActivityToast 三种类型的 Toast,它们都继承自 AbsToast,其相关源码如下所示:

static abstract class AbsToast implements IToast {      protected Toast      mToast;     protected ToastUtils mToastUtils;     protected View       mToastView;      AbsToast(ToastUtils toastUtils) {         mToast = new Toast(Utils.getApp());         mToastUtils = toastUtils;         if (mToastUtils.mGravity != -1 || mToastUtils.mXOffset != -1 || mToastUtils.mYOffset != -1) {             mToast.setGravity(mToastUtils.mGravity, mToastUtils.mXOffset, mToastUtils.mYOffset);         }     }      @Override     public void setToastView(View view) {         mToastView = view;         mToast.setView(mToastView);     }      @Override     public void setToastView(CharSequence text) {         // 当设置了 mode 或者 设置了 icon 则会使用 utils_toast_view 布局         View utilsToastView = mToastUtils.tryApplyUtilsToastView(text);         if (utilsToastView != null) {             setToastView(utilsToastView);             return;         }         // API30 getView() 为空,则使用 utils_toast_view 布局来兼容         mToastView = mToast.getView();         if (mToastView == null || mToastView.findViewById(android.R.id.message) == null) {             setToastView(UtilsBridge.layoutId2View(R.layout.utils_toast_view));         }         TextView messageTv = mToastView.findViewById(android.R.id.message);         messageTv.setText(text);         if (mToastUtils.mTextColor != COLOR_DEFAULT) {             messageTv.setTextColor(mToastUtils.mTextColor);         }         if (mToastUtils.mTextSize != -1) {             messageTv.setTextSize(mToastUtils.mTextSize);         }         setBg(messageTv);     }      protected void setBg(final TextView msgTv) {         if (mToastUtils.mBgResource != -1) {             mToastView.setBackgroundResource(mToastUtils.mBgResource);             msgTv.setBackgroundColor(Color.TRANSPARENT);         } else if (mToastUtils.mBgColor != COLOR_DEFAULT) {             Drawable toastBg = mToastView.getBackground();             Drawable msgBg = msgTv.getBackground();             if (toastBg != null && msgBg != null) {                 toastBg.mutate().setColorFilter(new PorterDuffColorFilter(mToastUtils.mBgColor, PorterDuff.Mode.SRC_IN));                 msgTv.setBackgroundColor(Color.TRANSPARENT);             } else if (toastBg != null) {                 toastBg.mutate().setColorFilter(new PorterDuffColorFilter(mToastUtils.mBgColor, PorterDuff.Mode.SRC_IN));             } else if (msgBg != null) {                 msgBg.mutate().setColorFilter(new PorterDuffColorFilter(mToastUtils.mBgColor, PorterDuff.Mode.SRC_IN));             } else {                 mToastView.setBackgroundColor(mToastUtils.mBgColor);             }         }     }      @Override     @CallSuper     public void cancel() {         if (mToast != null) {             mToast.cancel();         }         mToast = null;         mToastView = null;     } }  interface IToast {     void setToastView(View view);     void setToastView(CharSequence text);     void show(int duration);     void cancel(); }

这部分代码比较简单,很多都是做兼容处理,我就不做解释了,下面我们依次来看 SystemToastWindowManagerToastActivityToast

“`java
static final class SystemToast extends AbsToast {

SystemToast(ToastUtils toastUtils) {     super(toastUtils);     if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) {         try {             //noinspection JavaReflectionMemberAccess             Field mTNField = Toast.class.getDeclaredField("mTN");             mTNField.setAccessible(true);             Object mTN = mTNField.get(mToast);             Field mTNmHandlerField = mTNField.getType().getDeclaredField("mHandler");             mTNmHandlerField.setAccessible(true);             Handler tnHandler = (Handler) mTNmHandlerField.get(mTN);             mTNmHandlerField.set(mTN, new SafeHandler(tnHandler));         } catch (Exception ignored) {}     } }  @Override public void show(int duration) {     if (mToast == null) return;     mToast.setDuration(duration);     mToast.show(); }  static class SafeHandler extends Handler {     private Handler impl;      SafeHandler(Handler impl) {         this.impl = impl;     }      @Override     public void handleMessage(@NonNull Message msg) {         impl.handleMessage(msg);     }      @Override     public void dispatchMessage(@NonNull Message msg) {

部分转自互联网,侵权删除联系

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » ToastUtils-我愿称之为最强求职学习资料
分享到: 更多 (0)
D0b2wT.gif

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们