【跟Z学开发】前言和准备工作

zcxsythenew UID.911687
2017-07-24 发表

本帖最后由 zcxsythenew 于 2017-7-24 21:00 编辑

注意:虽然此文章的标题是“前言”,但其实际上安排在课时1.4的后面。请先看完课时1.1到1.4的内容,确认没有问题了以后,再来阅读此文章。

1.关于本系列

本系列与其它开发教程的不同之处是:其它开发教程大都喜欢分好类别,类似于工具书,按需查阅;而本系列是不按内容分类的,但是有阅读顺序。后面的内容会反复提及到前面的内容,包括这篇前言。因此,你需要从前往后阅读这些文章。

2.关于专题一

我们已经做了一个极其简陋的播放器,并且马上就要写一个很简单的UI界面。1.1和1.2分别介绍了单进程和双进程的后台媒体播放。单进程模型可以大大减少代码量,但是也会绕过一些比较重要的内容。我们这个系列的主要目的是学习与交流,因此从1.5开始,我们会不厌其烦地用双进程模型来学习写这个播放器。

3.源代码管理

在1.2里面,光是注册个后台任务,就用了30行;在1.4里面发送个通知(方案4),又用了20行。在后面,这样长的函数我们还要写很多个,为了方便管理,一方面要善用1.4讲过的提取方法,一方面要善用注释,还有一方面,我们可以用源代码管理,在一个阶段的工作完成之后记录一个“还原点”,以便在自己不小心搞砸了整个App之后进行恢复。这不是必需的,但是我建议你这样做。

这里以微软的Visual Studio Team Services为例。这套系统主要目的是团队合作,不过对于我们来说,只要用到它的“历史记录”功能就可以了。

准备好源代码管理

第1步 到***链接停止解析***,用Microsoft账户登录,然后完善你的个人信息。
第2步 打开Visual Studio。如果你没有登录到Visual Studio,现在登录。
第3步 在起始页中,点击“新建项目”下的“创建新项目…”。
第4步 勾选“新建Git存储库”。

***附件停止解析***

第5步 确认新建项目。选择版本时,如果你想要学习选学内容,则在目标版本选择Windows 10 Insider Preview。其他同学,在目标版本选择15063。建议最低版本不要选择Insider Preview,否则这个解决方案将不能部署到手机上。
第6步 点击“团队资源管理器”>“同步”,然后如图所示,推送到Visual Studio Team Services。

***附件停止解析***

***附件停止解析***

***附件停止解析***

现在你的源代码管理已经准备好了。点击“请在Web上查看”,然后将这个地址放入收藏夹。虽然是英文界面,但是也不必担心,我们只用到Files和History两个功能,我相信这点英文应该还是没有问题的。

***附件停止解析***

及时提交你的代码
每一次提交之后,都会在这里留下你的记录。每当你完成了一段你认为重要的代码之后,我建议你提交一次。在“团队资源管理器”中,点击“更改”,输入你的提交信息(例如“处理了应用预启动”),然后点击下拉框>“全部提交并推送”,就可以把代码上传到服务器。(如果点击“全部提交”,只会把提交暂时存到本地。)

***附件停止解析***

4.应用生命周期

我们在1.1到1.4中,故意绕过了很多内容。我们用App.Current.Exit绕过了XAML代码。其实,我们不仅绕过了XAML,还绕过了必须掌握的应用生命周期的管理。我们简单地了解了后台任务的启动条件,知道后台任务会被系统强制停止,停止时会触发OnCanceled事件。我们的播放源选择了在线直播的网络电台,因此当后台任务被系统忍无可忍地终止的时候,直接用def.Complete,因为一个直播的网络电台实在没有什么需要处理的。我们还简单地了解了前台应用的启动和预启动,知道Windows 10 1511会给所有的应用准备预启动,1607开始改为必须手动申请预启动。但是也仅此而已了,因为应用还来不及处理其它事情,我们已经用App.Current.Exit把它暴力“解决”了。

但是引入了前台UI以后,事情就会变得非常复杂。我们亟需在这方面补一补课。事实上,商店里面的很多个应用,也需要补一补课。例如网易云音乐,虽然整体不错,但是在应用生命周期的处理上,并不算好。

应用预启动

当应用申请加入预启动,而且系统资源充足的时候,Windows会自动在后台静悄悄地启动你的应用。

但是,并不是每一位开发者(也不是每一个“大佬”App的开发者)都知道有预启动这个东西。尤其是目前,只有申请过的应用才能预启动,那么我们要“抓住机遇”,“抢占先机”。申请预启动的代码如下:

CoreApplication.EnablePrelaunch(true);

把这行代码放在OnLaunched的下一行(不计大括号)。

应用启动和两种运行状态

应用启动之后,首先在后台运行。然后移到前台运行。当用户最小化(电脑)或切换到其它应用(其他设备)的时候,应用又会移到后台运行。

我们可以利用这点做一些有趣的事。比如说,当播放到下一首歌的时候,如果应用不在前台,是不是可以发送一条静音的通知,显示歌名?

当然理论上来说,更重要的是释放内存。我们做的这个应用依然很简单,好像没有什么内存可以释放的。我在后面会演示一次如何释放内存。

应用可以在前台和后台移来移去,每次移动,都会触发一次事件。我们可以处理它:

this.EnteredBackground +=App_EnteredBackground;
this.LeavingBackground +=App_LeavingBackground;

这两行代码放在App的初始化函数里面,也就是public App()里面。

应用暂停

应用在后台运行了几秒(包括预启动)之后,如果用户没有重新打开它,应用就会暂停。已暂停的应用仅保留在内存中,不在运行状态。

为了能够继续播放音乐,单进程模型的播放器基本不会暂停,除非遇到极端情况。为了让它有这样的权力,需要在appxmanifest文件的“功能”处勾选“背景媒体播放”。

双进程的播放器则有不同。因为它把媒体播放分离到单独的后台任务当中,前台不需要保持运行状态,所以不需要勾选“背景媒体播放”,但是要声明后台任务。我们在1.1里面介绍了单进程媒体播放,在1.2讲双进程,把代码移过去的时候,忘记了去取消这个勾选。

我们在1.3里面非常简单地讲过后台任务如何向前台通信,当时我们用的是一个空信息new ValueSet()。以后我们会多次遇到需要传递信息的情况,当前台暂停的时候,向前台传递信息是无效的,因此我们可以在这个时候,作一个判断,当前台暂停的时候,就不要再通信了。

我们需要处理暂停的事件,微软已经帮我们预置了这一段代码:

this.Suspending += OnSuspending;

应用恢复

当用户回到已暂停的应用时,它首先会恢复到后台运行状态,然后改为前台运行状态。我们需要把暂停的过程反过来做,比如告诉后台任务可以向前台通信了。代码:

this.Resuming += App_Resuming;

这一段代码也放在初始化App的函数中。

应用终止

用户可以手动终止应用,应用将首先进入后台运行,然后暂停,然后关闭。当遇到极端情况,例如地震、洪水、泥石流、内存不足等,系统也会终止已暂停的应用。已暂停的应用不在运行状态,所以是收不到系统终止它的通知的。微软在官方文档里面写到,应用应当在OnSuspending的时候就保存好当前的状态。所以,如果你遇到了离开了某应用之后一段时间又回来,发现应用重启了,其实这是开发者的锅,没有把状态保存好。而不幸的是,这样的情况实在是太常见了。

对于我们这个双进程的播放器来说,又有一种情况要考虑,在1.3里面提到过的,共享生命周期。电脑上,终止了前台应用,后台也将一并终止。在其他设备,前台和后台相对独立,所以有可能前台终止了,后台继续播放。当用户回来的时候,我们有可能要检查一下后台任务的状况。

不论应用是被用户还是系统终止,当重新打开的时候,都会执行OnLaunched。为了检查上一次的终止情况,可以在OnLaunched函数中执行下面的代码:

if (e.PreviousExecutionState ==ApplicationExecutionState.Terminated)
//上一次是被系统终止的,现在需要恢复而不是重启
{
//TODO:从之前挂起的应用程序加载状态
}

微软已经预置了这一段代码。

后台任务的周期

后台任务的周期其实很短,时间要以秒来计算(可能有人会提到后台下载。后台下载的任务其实是由系统来做的,专题一应该不会涉及到,视情况而定)。只有音频可以持续保持运行。但是,一旦音频任务停止了(即遇到了极端情况),要重启它就很困难,除非重启整个应用。在1.1到1.4做的这个播放器,并不需要处理什么。但是现在,我们要想一想,是否要保存正在播放的歌曲的信息?是否要保存播放到的位置?如果前台还在运行,是否要告诉它“我挂了”?

在1.2,我们直接用def.Complete把这些全部搪塞了过去。但是现在,不能这么懒了。

5.利用VisualStudio进行调试

设置断点

在cs代码文件中,行号的左侧有一个空白区域,点击它可以设置断点。当代码执行到断点的位置时,会自动暂停,然后你就可以按F11或F10来逐语句或逐过程来执行代码。

***附件停止解析***

调试应用生命周期

在调试过程中,Visual Studio的底部状态栏为橙色。此时,你可以点击视图>工具栏,然后启动“调试位置”,你就可以手动调试应用在挂起、继续、挂起并关闭的运行情况。

***附件停止解析***
***附件停止解析***

需要注意的是,在使用Visual Studio进行调试时,Visual Studio会阻止应用自行挂起。所以,你也需要在Visual Studio外进行调试。为了了解你的应用会在何时挂起、何时继续、何时在前台运行、何时在后台运行,你可以在事件处理中加入发送通知的代码。发送通知在1.4里面已经讲过了。

Visual Studio还可以调试预启动的情况。在非调试状态下,点击调试>其他调试目标>调试预启动即可。

***附件停止解析***

准备好了吗?

我们7月27日19:00再见。
[backcolor=red]请投票选择“打卡签到”,谢谢。[/backcolor]

敬告:
为防止不可控的内容风险,本站已关闭新用户注册,新贴的发表及评论;
你现在看到的内容只是互联网用户曾经发表的言论快照,仅用于老用户留存纪念,且仅与科技行业相关,全部内容不代表本站观点及立场;
本站重新开放前已针对包括用户隐私、版权保护、信息安全、国家政策在内的各种互联网法律法规要求,执行了隐患内容的自查、屏蔽和删除;
本站目前所属个人主体,未有任何盈利安排与计划,且与原WFUN.COM所属公司不存在任何关联关系;
如果本帖内容或者相关资源侵犯到您的合法权益,或者您认为存在问题,那么请您务必点此举报或投诉!
全部回复:
AFAN-World UID.2879093
2017-07-25 使用 Lumia 640 XL 回复

本帖最后由 AFAN-World 于 2017-7-25 13:41 编辑

无。。。

Quote 1.已经把你添加到 了我的人脉中{:6_230:} 2.打卡签到下面的无效选项居然还有人选(不是我){:6_230:} 3.事先说明知道这只是教程: “预启动”是极其不负责任的行为。(我可没骂人啊)除非必要的系统服务,我非常不喜欢任何应用预启动。 预启动了一个应用,系统速度就会慢一点。 正因为如此,各大优化软件(如startisbackpp)才会加入禁止预启动的选项。 很遗憾,手机上没有这样的选项。 建议的做法(有待推敲)是在“设置”里面让用户自己选择是否开启预启动。只有用户使用频率高的应用才应该开启预启。你可以设计算法计算使用频率,但目测体验主机(shell)里面有这样的算法。 举一个很好但大家很少知道的例子:nokia(注意不是lumia)全套应用,只有使用频率高的(如nokia专业拍摄)才有可能申请预启。是否申请预启在注册表中有键值,由ndtksvc(nokia工具服务)管理。ndtk负责监视使用频率(目测却是始终开启)并使用系统权限和unsafe帮助专业拍摄更快启动(目测目测)。也就是说,Nokia对于手机性能和相机启动速度还是经过仔细考虑,最终选取了 一个两全其美的方案。 然而w10m的系统和相机都tm慢。 扯远了。 意思只是说,一般不要申请预启动。 (再次声明没有骂人)至于“抢占先机”的说法更不可取。慎用的东西,所以知道的人少。(没有骂人) 1.扯得远了。里面有错误的地方请指出。 2.再次说明教程还是非常好的。教程并不是实际操作,我再此只是指出实际应用时候的注意事项。 3.我真的没有骂人。

yc****56 UID.2805753
2017-07-25 使用 Lumia 1520 回复

声明,我是打卡签到哈

小张qq UID.1257492
2017-07-25 使用 Lumia 640 XL 回复

支持一下

zcxsythenew UID.911687
2017-07-25 回复

本帖最后由 zcxsythenew 于 2017-7-25 08:18 编辑

QuoteAFAN-World 发表于 2017-7-25 00:22
1.已经把你添加到 了我的人脉中
2.打卡签到下面的无效选项居然还有人选(不是我)
3.事先 ...


由于本系列的特点,我不可能将官网上的原文全部照搬。但是,当任何人有异议时,最好都先去看一看官网。
Quote当允许使用可用的系统资源时,可通过在后台主动启动用户的最常用应用,提升桌面设备系列设备上的 Windows 应用商店应用的启动性能。
***链接停止解析***
Quote如果设备具有足够资源,操作系统会预启动针对该行为选择的常用应用,以优化响应性。
***链接停止解析***
另外,预启动的应用会很快暂停,因此不会导致运行速度慢的现象。只是内存占用多了几十兆罢了。

AFAN-World UID.2879093
2017-07-25 使用 Lumia 640 XL 回复

Quotezcxsythenew 发表于 2017-7-25 08:13
由于本系列的特点,我不可能将官网上的原文全部照搬。但是,当任何人有异议时,最好都先去看一看官网。ht ...


我预计shell就是有计算频率的功能的。 仅限桌面啊,好吧我真的不应该随便瞎说的。(嗯好吧自己的推测果然还是比不上官方文档{:6_230:}) 然而?几十m我是绝对受不了的,禁用预启我一般是开着的。 好吧是我瞎说了 因为真的没看过有关文档 只是不太喜欢这样的做法啦~ {:6_243:}{:6_243:}{:6_243:} 好吧好吧好吧

AFAN-World UID.2879093
2017-07-25 使用 Lumia 640 XL 回复

Quotezcxsythenew 发表于 2017-7-25 08:13
由于本系列的特点,我不可能将官网上的原文全部照搬。但是,当任何人有异议时,最好都先去看一看官网。ht ...


行吧 其实昨天晚上发了之后我就有点后悔 毕竟只是我的推测,,, {:6_244:}{:6_244:}{:6_244:}

vbfool UID.352791
2017-07-25 回复

看的人确实少了点,都快变成商业互吹了

zcxsythenew UID.911687
2017-07-25 回复

Quotevbfool 发表于 2017-7-25 10:18
看的人确实少了点,都快变成商业互吹了


商业互吹指的是什么?

zcxsythenew UID.911687
2017-07-25 回复

QuoteAFAN-World 发表于 2017-7-25 09:11
我预计shell就是有计算频率的功能的。 仅限桌面啊,好吧我真的不应该随便瞎说的。(嗯好吧自己的推测果然 ...


也许是我学Windows App的时候太经验主义了,都是凭经验写的代码,没有系统地学过C#。现在看你写的C#零基础教程竟然很慌,因为里面有很多内容我看不懂(尽管我知道你说明了专有名词不是通用版本),求解答: 1. int int1=new Int(); 编译错误,为什么? 2. 像string和int这样基本的类型一般可以直接赋值,意思是说其它没有经过初始化的对象不能赋值吗?

AFAN-World UID.2879093
2017-07-25 使用 Lumia 640 XL 回复

Quotezcxsythenew 发表于 2017-7-25 14:26
也许是我学Windows App的时候太经验主义了,都是凭经验写的代码,没有系统地学过C#。现在看你写的C#零基 ...


第三步 那篇文章里面有很多错误。我还没写完。 首先像int那样的其实是不能初始化的,但不知看了哪篇“精通”说包括int在内的结构都自带构造函数。 然而我没有试过就写了上去,于是尴尬了。 第二点那个对象初始化确实是我表述问题。因为没人会拿这样的类练习初始化,然而 好吧我得赶紧去改改帖子

AFAN-World UID.2879093
2017-07-25 使用 Lumia 640 XL 回复

本帖最后由 AFAN-World 于 2017-7-25 14:37 编辑

Quotezcxsythenew 发表于 2017-7-25 14:26 也许是我学Windows App的时候太经验主义了,都是凭经验写的代码,没有系统地学过C#。现在看你写的C#零基 ...
Color c1; c1.Red = 10; 抛ArgumentNullException 但这跟赋值没关系。这是我的表述错误。 看来作家不是随便当的{:4_143:}

AFAN-World UID.2879093
2017-07-25 使用 Lumia 640 XL 回复

Quotezcxsythenew 发表于 2017-7-25 14:26
也许是我学Windows App的时候太经验主义了,都是凭经验写的代码,没有系统地学过C#。现在看你写的C#零基 ...


更新:表述应该更改为“基本的类型可以直接使用代码规定的表述方式来定义它的值” 嗯。后面加个如……就好了吧。 我那一开始也不照样没系统学过cs,,, {:4_143:}

zcxsythenew UID.911687
2017-07-25 回复

Quote***链接停止解析***
第三步 那篇文章里面有很多错误。我还没写完。
首先像int那样的其实是不能初始化的,但不知看了哪篇“精通 ...


不应该啊,你没有get到我的点。我还记得当年学C++的时候,首先就很容易搞错的事。放到C#也是一样的。
int i = new Int();
这句话的重点是:区分大小写
(就是这么ruo智。但是你要知道你面对的是零基础,而所谓的零基础,很可能还是学习了VB 6.0,对VB不区分大小写有一点模糊的记忆。这是中学要学的。)
首先,明确int是可以初始化的(不过几乎没有人那么无聊就是了);然后,正确的写法是:
int i = new int();
int i = new System.Int32();

第二个点,我想问的是:
Color x=Colors.Transparent;
这个x没有经过new Color()就直接赋值了,请问合法吗?

AFAN-World UID.2879093
2017-07-25 使用 Lumia 640 XL 回复

Quotezcxsythenew 发表于 2017-7-25 16:26
不应该啊,你没有get到我的点。我还记得当年学C++的时候,首先就很容易搞错的事。放到C#也是一样的。
int ...


我的妈呀。 看来得拿出我那本吃灰半年的“精通”了。 完了完了,我现在完全是凭印象写,然而对于这些基本的东西我没有一点印象。 谁在意这些东西? 然而对于零基础的写作,谁又能绕开这些东西? 终于发现这又是一个坑,, 不过我当然是不会放弃的, 然而我现在对于int到底能不能初始化已经快混了,特别是cs把基本类用作保留关键字的做法更是……唉…… 完了我有时间改。 关于第二个问题,当然(对我是这么想的)可以。这个之后会详详细细地讲。而且专门开一章(即“面向对象编程”)。作为dotnet里面的精华,这个问题可以说是“编程之美”的最佳体现了。 哦对了我好像还没有说答案。 如果我没有记错的话,是可以的。 但是这个问题已经涉及到了pointer(对没错),一时半会讲不清楚。 要不你就继续期待?不过我有可能就闪人了,我这工作不稳定,,, 算了抽个时间赶紧码完这一部分吧,, 真不是我卖关子, 呀怎么说 不是一下能够说完的 况且我速度这么慢 docs上有文档的吧? 实在不行你就先去找找vbfool

zcxsythenew UID.911687
2017-07-25 回复

Quote***链接停止解析***
我的妈呀。
看来得拿出我那本吃灰半年的“精通”了。
完了完了,我现在完全是凭印象写,然而对于这些基本的 ...


我当然知道是可以的。虽然我学的时候非常经验主义,但也不至于什么也不懂。
我也知道这个赋值会涉及到指针的问题,于是就不免牵扯到class和struct。所以我不敢挑起向零基础普及C#的大梁,实在是太难写了。

AFAN-World UID.2879093
2017-07-25 使用 Lumia 640 XL 回复

Quotezcxsythenew 发表于 2017-7-25 17:56
我当然知道是可以的。虽然我学的时候非常经验主义,但也不至于什么也不懂。
我也知道这个赋值会涉及到指 ...


(那你在问什么) 刚刚发现这是个坑,, 不过当然不准备放弃,正好顺便学习一下h5+css(js那个傻x我都不想去碰) 计划写上一段时间之后,充分发挥h5,并且添加一些 interesting things 或许放个广告插件?

zcxsythenew UID.911687
2017-07-25 回复

QuoteAFAN-World 发表于 2017-7-25 18:39
(那你在问什么)
刚刚发现这是个坑,,
不过当然不准备放弃,正好顺便学习一下h5+css(js那个傻x我都不想 ...


我在问的是:
像string和int这样基本的类型一般可以直接赋值,那么其它类型未初始化时不能赋值吗?
而我刚刚用Color举例,问
Color x=Colors.Transparent;
行不行,你说:行
所以,是不是有点前后矛盾的感觉?

-----

另外,你说你不保证教程用的是通用的专有名词,我想问一问,class和struct是否包含在“不通用”的范围内?按照通用版本,int(或者说System.Int32)并不是一个类(class)。

vbfool UID.352791
2017-07-26 回复

Quote***链接停止解析***
我在问的是:
像string和int这样基本的类型一般可以直接赋值,那么其它类型未初始化时不能赋值吗?
而我 ...


int不是一个类,我记得color也不是个类啊,没记错的话是个结构体,不赋值的话,会给个默认值的。
Color c;
c.Red=0记得好像是可以的。

引用类型的对象,不初始化的时候,默认值就是null了。

kn****88 UID.941228
2017-07-26 使用 Lumia 1520 回复

厉害了我的歌

zcxsythenew UID.911687
2017-07-26 回复

本帖最后由 zcxsythenew 于 2017-7-26 08:50 编辑

Quotevbfool 发表于 2017-7-26 02:14
int不是一个类,我记得color也不是个类啊,没记错的话是个结构体,不赋值的话,会给个默认值的。
Color c ...


我觉得他已经把类和结构体搞混了。不过,他说不保证专有名词均为通用版本,我就当他说的既是类又是结构体好了。但是似乎也经不起推敲。

某些结构体在局部变量中不赋值是不行的。比如int。但是Color为什么可以就不清楚了。

湖****海 UID.2870230
2017-07-26 使用 Lumia 640 回复

感谢开发者,我也用了vs有段时间了,git,那里一直不会,还有后台的处理。希望继续下去,毕竟这些都是伯伯的视频里没有的。加油。

vbfool UID.352791
2017-07-26 回复

Quote***链接停止解析***
我觉得他已经把类和结构体搞混了。不过,他说不保证专有名词均为通用版本,我就当他说的既是类又是结构体 ...


int也是可以的啊,只是少部分时候不行吧,好像是ref的时候需要先有值

AFAN-World UID.2879093
2017-07-26 使用 Lumia 640 XL 回复

Quotezcxsythenew 发表于 2017-7-25 23:52
我在问的是:
像string和int这样基本的类型一般可以直接赋值,那么其它类型未初始化时不能赋值吗?
而我 ...


真坑啊。 首先第一个问题我回答过了 quote: 表述应该更改为“基本的类型可以直接使用代码规定的表述方式来定义它的值” 所以。。 再者,我是知道c和s区别的。 之所以不通用,是因为面向零基础。下几节课我会详详细细地区分。 然而在区分之前,我并不知道用什么名称把c和s统一起来。 第三,color我先明确它是struct,然后明确不new的话不能对red赋值。这两点我都是有经历的。 但是csharp的基本类(你让我怎么说?)保留关键字的做法实在不得其解。

AFAN-World UID.2879093
2017-07-26 使用 Lumia 640 XL 回复

Quotezcxsythenew 发表于 2017-7-26 08:11
我觉得他已经把类和结构体搞混了。不过,他说不保证专有名词均为通用版本,我就当他说的既是类又是结构体 ...


要不我这样规定吧: 类:面向零基础的,统一c和s 类型:class 结构:struct

AFAN-World UID.2879093
2017-07-26 使用 Lumia 640 XL 回复

Quotezcxsythenew 发表于 2017-7-26 08:11
我觉得他已经把类和结构体搞混了。不过,他说不保证专有名词均为通用版本,我就当他说的既是类又是结构体 ...


然而这样规定class就不能简称类了

AFAN-World UID.2879093
2017-07-26 使用 Lumia 640 XL 回复

Quotevbfool 发表于 2017-7-26 02:14
int不是一个类,我记得color也不是个类啊,没记错的话是个结构体,不赋值的话,会给个默认值的。
Color c ...


根据下图是可以的,但在实际操作时会throw
***图片停止解析***

vbfool UID.352791
2017-07-26 回复

Quote***链接停止解析***
真坑啊。
首先第一个问题我回答过了
quote:
表述应该更改为“基本的类型可以直接使用代码规定的表述方式来 ...


那个应该叫“基础类型”吧。
保留了关键字是因为它们是语法的一部分了。

本站使用Golang构建,点击此处申请开源鄂ICP备18029942号-4联系站长投诉/举报