APP优化篇——优化关键评估指标

目前,随着APP行业的竞争越来越激烈,功能也越发丰富,人们评价一款产品的优秀程度,已经不能单纯通过 ”是否具备某些功能“ 来评价某个产品了,纯技术壁垒的产品已经是凤毛麟角,从用户角度,客户端不仅仅需要具备用户的基本诉求功能,流畅程度、发热程度、启动速度等等,分分钟可能让用户放弃你的APP,从而拥向你竞品APP的怀抱。

随着H5技术的快速发展,微信小程序的出现,使用前端相关语言开发,无论是“网页版”APP还是混合开发模式,市场占有率也不断增高,试想如果前端语言开发的产品和Native开发的产品,体验差不多,也就没有原生APP什么事情了, 毕竟开发成本摆在那。谁都不是sha zi,能用一份价格,搞定多个环境(Android手机、iOS手机、PC),相信老板们是很精明的。

那么作为一名Android APP的研发人员,我们应该从哪些角度来优化我们的APP以提高竞争力呢?又应该以什么“标准”来评价自己所做的优化工作是否合理呢?基于这些背景,我总结了一些关于产品优化的几个维度,如图:

1.CPU占用率

网友们也称作使用率,通俗的可以理解为APP在运行过程中,对于CPU资源的使用情况,若CPU使用率过高,会使整个手机无法响应用户,整体性能降低,影响用户体验,也容易引起ANR等问题,故我们的目标是APP正常运行的情况下,CPU使用率越低为好

常用的测试方法:使用adb命令;使用Android studio profiler;使用各种云测平台;

方法1、基于adb shell dumpsys cpuinfo的方式,此方式可以测试手机中任意packageName的app
adb shell "dumpsys cpuinfo | grep package"     //其中package为具体应用的包名信息
例如: adb shell "dumpsys cpuinfo | grep com.android.browser"  //当前系统浏览器的情况

第一个参数:0.1%即为当前情况下,该应用的CPU使用情况,具体一目了然。

方法2、读取方 /proc/pid/stat的方式
adb  shell cat /proc/stat
Linux层有公共目录。很多公共信息资源由两个虚拟的文件系统提供:
    /proc:包括内存,CPU,网络等
    /sys:设备驱动,网络环境(/sys/class/net/)等
通过/proc这个伪文件系统,我们可以和内核内部数据结构进行交互,获取有关进程的有用信息。

具体的解释,可以看参考文档,里面有具体的说明,图中详细记载8核CPU的使用情况。

方法3、基于Linux的top命令
adb shell top
常用参数一般有如下:
    -m:表示需要展示的进程数目
    -n:结束前需要刷新多少次
    -d:刷新间隔(单位秒)
    -s:按照什么列排序(CPU,VSS,RSS,THR)

输出的信息里面主要包括:
    PID(进程ID),CPU%(CPU使用率),VSS(虚拟内存使用量),RSS(实际物理内存使用量)等等。

我们一般关心的数据列就是我们CPU%。
例如:adb shell top -m 1 -d 0 -n 1

最直观的,应该是使用Android studio的Profiler工具了,具体代码中,出现的方法占用均有明确的信息(当然前提是APP是自己的,如果是别人的APP,用adb测试):

工具中,详细展示了各个进程的使用情况,通过record一段时间记录,来分析当前环境下,具体代码占用CPU的信息。

参考:https://www.jianshu.com/p/31b1a4aef550

2、内存占用:

在Android系统中,每个APP进程除了同其他进程共享(shared dirty)外,还独用私有内存(private dirty),通常我们使用PSS(=私有内存+比例分配共享内存)来衡量一个APP的内存开销。移动设备的内存资源是非常有限,为每个APP进程分配的私有内存也是有限制。一方面我们要合理的申请内存使用,以免导致频繁的GC(垃圾回收机制)影响性能和大对象申请发生内存溢出;另一方面,我们要及时释放内存,以免发生内存泄漏。

关于内存涉及几个概念:

Terms
    VSS- Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
    RSS- Resident Set Size 实际使用物理内存(包含共享库占用的内存)
    PSS- Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
    USS- Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS

参考:https://blog.csdn.net/adaptiver/article/details/7084364

常用的测试方法:使用adb命令;使用Android studio profiler;

方法1、基于adb shell dumpsys meminfo的方式,打印详细的当前环境PSS使用信息
adb shell "dumpsys meminfo | grep package"     //其中package为具体应用的包名信息
例如: adb shell "dumpsys meminfo | 具体应用包名"  //当前系统某个APP的总体情况
例如: adb shell dumpsys meminfo 具体应用包名       //当前系统某个APP的详细信息
方法2、基于adb方  shell top,将内存使用信息以文件方式储存后,再查阅
步骤如下:
    (1)、adb shell top -d 1 > d://meminfo  //将得到的数据输出到pc中d盘的,meminfo文件中
    (2)、操作被测试的应用
    (3)、中断,分析记录的数据,具体命令如下

如果是window的环境,可以使用cgywin,具体工具的安装过程,这里不做详解,来使用cat 命令过滤出想要的APP的内存使用情况信息,linux或者mac的小伙伴就没有这个烦恼了。

cat d://meninfo | grep 具体某个包名

另外,更高级的做法,是通过脚本,将meminfo信息,转换为Excel的分析报告,然后做每个时间段的对比分析图,这里不做方式的延伸,具体感兴趣的小伙伴可以自行查阅相关的资料。
最直观的,应该是使用Android studio的Profiler工具了,具体代码中,出现的方法占用均有明确的信息(当然前提是APP是自己的,如果是别人的APP,用adb测试):

发现没,和上面查看CPU情况的工具相同,没错,Android Studio 3.+以后,已经做了统一,且去留意sdk tools工具也少了很多bat,例如.9工具,MAT等等

工具中,详细展示了各个进程的使用情况,通过record一段时间记录,来分析当前环境下,具体代码占用内存的信息。

对于运行时内存的优化目标:占用越小越好,扫掉一切内存泄漏的场景

3、启动时间:

通俗理解为,用户打开APP,看到正常的画面,启动分为冷启动和热启动两种。

冷启动:应用程序首次启动,进程首次创建并加载资源的过程;

热启动:应用程序启动后点“back”键、“Home”键,应用程序退到后台,并未被完全“Kill”的状态,再次启动;

冷启动测试:

启动APP命令: adb shell am start -W -n package/activity
停止APP命令: adb shell am force-stop package

package为应用的包名,activity为具体页面,启动测试可以是launcher配置的页面
例如,测试浏览器的启动时间:
    adb shell am start -W -n com.android.browser/.BrowserActivity
    adb shell am force-stop com.android.browser

结果分析: <b>ThisTime:596</b> 这条信息中的时间就作为这次应用启动(冷启动)的耗时,单位是ms。

热启动测试:

启动APP命令: adb shell am start -W -n package/activity
停止APP命令: adb shell input keyevent 3  (发送一个keyevent事件,3代表点击手机上的“back”键)

例如,依旧是测试浏览器的启动时间:
    adb shell input keyevent 3  //关掉上面程序已经冷启动的页面
    adb shell am start -W -n com.android.browser/.BrowserActivity  //重新打开APP

结果分析:<b>ThisTime:196</b> 这条信息中的时间就作为这次应用启动(热启动)的耗时,单位是ms。

更加专业的手段,可以通过监控脚本实现,具体这里不做详细介绍,有兴趣的小伙伴可以另行查阅,资料还是蛮多的。
对于启动时间的优化目标:启动时间越小越好!没有最小,只有更小

4、流畅度:

应用的流畅度是最直接影响用户体验的,与之直接挂钩的概念为 FPS(每秒的帧数),Android系统里定义每秒大于60帧是流畅的(一帧的完成时间是16ms),通过帧率和流畅度曲线,可以帮助开发者分析是否存在UI问题。

平滑的完成一帧意味着任何特殊的帧需要执行所有的渲染代码(包括 framework 发送给 GPU 和 CPU 绘制到缓冲区的命令)都要在 16ms 内完成,才能保持流畅的体验。如果没有在期间完成渲染秒就会发生掉帧。掉帧是用户体验中一个非常核心的问题,丢弃了当前帧,并且之后不能够延续之前的帧率,这种不连续的间隔会容易会引起用户的注意,也就是我们常说的卡顿、不流畅。

测试方法:https://developer.android.com/training/testing/performance?hl=zh-cn

方法1、开发者模式下:“GPU呈现模式分析”, 只要下方的曲线不超过绿线,都可以视之为流畅
方法2、Android设备的“设置”->"开发者选项",然后勾选“GPU呈现模式分析”,勾选adb shell dumpsys gfxinfo,记录信息到文件中(不同品牌手机路径可能不同)
    例如:adb shell dumpsys gfxinfo {具体某个应用的包名} > d://fps.txt            将某个应用的信息记录到d盘fps文件中
打开生成的fps.txt,找到Profile data in ms这部分数据,也可以将数据添加到Excel中查看
"Draw""  :     创建显示列表(display lists,记录所有view对象的绘制指令)的时间开销。
"Process" :  执行显示列表中绘制指令的时间。UI视窗中的View数量越多,需要执行的绘画命令就越多。
"Execute" :  将一帧图像交给合成器compostior的时间。这部分占用的时间通常比较少

通过图表方式,就很直观了,建议直接测试较复杂的页面,发现Execute这一列明显执行时间变长(大于16ms)后,就得留意看看具体APP对应的页面如何优化了,通过记录数据,与优化前的数据进行对比(例如做个折线图),也能清晰的分析自己的成果。

方法3、在程序中添加BlockCanary,监控程序的卡顿情况,这块资料比较多,不做详细介绍;

对于流畅度的优化目标:控制一帧的完成时间在16ms内

5、过度绘制:

提到过度绘制,相信很多人都知道,产生的原因,一方面是设计的复杂性,但主要还是和研发人员所采用的具体方案决定。常说条条大路通罗马,其实想实现UI的功能,方法很多,走错路也很常见,对于过度绘制的测试主要通过人工进行测试,系统是不会报错的,一不小心就创建了一个多层套用的布局,想从根本上解决问题,还得从健康的习惯开始,首先我们先来几张熟图(被盗来盗去的)。

image
蓝色:1倍过度绘制
绿色:2倍过度绘制
浅红色:3倍过度绘制
深红色:4倍过度绘制及以上

测试方法有:

方法1、打开开发者选项中的显示GPU过度绘制来进行测试(PS:只有Android4.2及以上的版本才具备此功能),直接在手机上查看结果;
方法2、使用Android Studio的Tools——>Layout Inspector
    首先启动APP后,打开Activity,然后再使用Inspector分析

这个是使用了分析后的结果,可以看到明显的存在过度绘制的问题,套用层级过多,如使用约束布局,或者自定义View来绘制Item,则可以减少很多层级关系。

凡事得有个标准,我们才能更好的来优化,所以比较流行的验收的标准(网友版)为:
    (1)、不允许出现黑色像素;
    (2)、不允许存在4x过度绘制;
    (3)、不允许存在面积超过屏幕1/4区域的3x过度绘制(淡红色区域)

以上是我们自己的APP的分析,那么我们如何来分析别人的APP呢?

方法3、使用 “uiautomatorviewer” 测试;
    从Android studio 3.1以后会发现没有了DDMS,用uiautomatorviewer可以替代它,路径在:Android SDK->tools->bin->uiautomatorviewer,启动后,可能会遇到“Unable to connect to adb. Check if adb is installed correctly”(我遇到了),此时,将uiautomatorviewer.bat,用NotePad++等工具打开,将文件最后一行的bindir路径修改为SDK的platform-tools所在路径(注意,用完后,还得还原回来,我测试用win10的操作系统,在platform-tools使用后,发现Android studio中Layout Inspector启动不了,下图配置还原后又恢复了)

上图,是我拿手机某个优秀APP来分析的案例,通过UI工具,可以很清晰的,分析别人做的产品使用了哪些布局技术,以及他们的层级关系。通过与优秀的APP做对标,我们来优化自己的APP,目标也就很清晰了。

对于过度绘制的优化目标:减少冗余的层次使用,活用相对布局、约束布局、自定义VIew,ViewGroup、活用Merge,ViewStub,include等等手段。

6、响应时间:

我们通常所说的APP卡、慢通常就是由于页面响应时间过长导致的。

可供参考的标准:
    优秀:0~400ms;
    标准:400ms~2000ms;
    轻微隐患:2000ms~5000ms;
    严重隐患:5000ms以上。

测试方法:

方法1、:使用 “logcat” 测试页面启动时间;
方法2、:使用第三方的云测工具,市面上很多,选择一款即可
    例如:OneAPM,     https://www.oneapm.com/
         华为DevEco,  https://deveco.huawei.com/
         百度测试,    http://bce.baidu.com/product/mat.html
         Testin,     https://www.testin.cn/

这里主要介绍下方式1,logcat这个控制台,相信大家都非常熟悉,通过过滤tag,display即可得到结果。772ms即为此次开启页面所消耗的时间

对于响应时间的优化目标:当然是越短内越好啦!

7、稳定性:

安卓稳定性标准,有两大指标:

(1)、闪退率,闪退率包括java的闪退率以及native闪退率;

(2)、ANR,就是应用没有响应。

主要分两个方面:

(1)、启动崩溃率,
公式 = 应用中一天发生闪退总数 / 应用一天中总的启动次数;

(2)、用户或设备崩溃率,
公式 = 应用一天中发生的闪推用户数(去重)/ 应用一天中总体的活跃用户数;

测试方式:1、上线前(Monkey测试、华为终端云测、Testin云测等等);2、上线后(友盟统计、腾讯Bugly等等);

而阿里推荐的优秀的产品,参考标准为:1、参考启动崩溃率:00.15%;2、参考设备崩溃率:00.2%。与上图的听云的数据大体相同,可以认为是行业的一个标准。

参考数据来源:
https://blog.csdn.net/x32sky/article/details/52778169
https://juejin.im/post/5ab47533f265da237d02f03c

作为开发人员,我们平时在打包Release包后,使用Monkey测试下,还是比较推荐的一种做法(基于测试员和工程师的友好相处法则),而Monkey测试具体标准是需要覆盖70%以上的页面,包括登陆,非登陆状态,并且经过八个小时不崩溃,平时如果是时间比较赶,短时间验证后及时修正明显的问题后,交付专业测试即可。

Monkey测试的方法:
    1、在adb的目录,使用adb shell monkey测试;
    2、如果Android studio已经配置了adb的路径,可以直接在Terminal控制台,输入指令;
具体指令为(指令比较多,这里只罗列了几个):
    adb shell monkey -p {包名} -v {后面的测试的次数} –throttle {延迟时间} > {测试文件路径}
例如:
    adb shell monkey -p xxx.xxx.xxx -v 100 –throttle 300 > D:\MTestLog.txt
    针对包名为xxx.xxx.xxx的产品进行测试,每个事件执行时间为300ms,执行100个事件,并将测试报告输出到d盘的MTestLog.txt文件上
    如果,monkey设置运行时间过长,期望中断,则可以按如下命令执行:
      (1)、adb shell
      (2)、ps | grep monkey 得到monkey进程号
      (3)、kill pid [刚才查到的进程号]
monkey -help:可查看参数说明列表。参数选项有:
(1) -p 包名1 -p 包名2 … :指定一或多个待测试的包,若不指定则测试中可打开任意APP;
(2) -v:指定打印日志的详细程度,有‘-v’,'-v -v','-v -v -v'三个级别;
(3) -s seed值:在测试中,虽然用户操作序列(每次操作按一定的顺序所组成的一系列操作)是随机生成的,但只要对同一个包指定相同的Seed值,就能使测试事件相同,可用于排错。所以也说这个操作序列是伪随机的。若不添加此参数,结果中会自动生成seed值;
(4) –-throttle 毫秒数:指定操作(即事件)间的时延,单位是毫秒;
(5) –-ignore-crashes:使得操作序列可以全部执行完,而不会在发生崩溃时就终止程序进程;
(6) –ignore-timeouts:使得操作序列可以全部执行完,而不会在发生ANR(Android Not Responding)时就终止程序进程;
(7) –-ignore-security-exceptions:使得操作序列可以全部执行完,而不会在发生许可错误时(如证书许可,网络许可等)时就终止程序进程;
(8) –-kill-process-after-error:使得当应用程序发生错误时停止运行并保持在当前状态,即仅是静止在发生错误时的状态,而不是结束该应用程序的进程;
(9) –-monitor-native-crashes:指定监视并报告应用程序发生崩溃的本地代码;
(10)–-pct-事件1 事件百分比1 -pct-事件2 事件百分比2 … :用于指定某类事件数目占总事件数目的百分比;

其中所指定事件参数选项可为:
    -flip(点击事件)
    -touch(触摸事件是一个down-up事件)
    -motion(动作事件由一个down事件、一系列的伪随机事件和一个up事件组成)
    -trackball(轨迹事件,在屏幕上进行随机拖动)
    -nav(基本导航事件,如上下左右键)
    -majornav(主要导航事件,通常引发图形界面中的动作)
    -syskeys(系统按键事件指如系统按键Home、Back、Start Call、End Call及volumeControl)
    -appswitch(启动activity事件)
    -anyevent(其它类型事件)
    注意,各事件类型的百分比总数不能超过100

实际开发过程,可以通过脚本,例如Python等,指定点击设备的具体位置,流程化的进行测试验证,具体可以参考:

https://juejin.im/entry/59a7d23a6fb9a024a27c0e85 //含scriptfile、python

稳定性优化的目标:崩溃率控制在优秀的范围内,越小越好,且问题越早发现越好,上线前做下灰度测试也是不错的选择。

8、消耗电量:

相对于PC来说,移动设备的电池电量是非常有限的,保持持久的续航能力尤为重要。Android的很多特性都比较耗电(如屏幕,GPS,sensor传感器,唤醒机制,CPU,连网等的使用),我们必须要慎重检查APP的电量使用,以免导致用户手机耗电发热,带来不良体验。

测试方法,测试手机安装目标APK前后待机功耗无明显差异, 常见使用场景中能够正常进入待机,待机电流在正常范围内。长时间连续使用应用无异常耗电现象;电量测试的方法分为软件测试和硬件测试两类。
测试手段包含软件测试和硬件测试两类,这里主要介绍下软件测试的手段:

方法1、通过BatteryManager发的广播来做分析,可参考:http://hukai.me/android-training-course-in-chinese/performance/monitor-device-state/battery-monitor.html
方法2.1、adb shell dumpsys battery来获取,本地分析
方法2.2、historian.py脚本 + Python环境
    (1)、下载historian.py脚本,下载地址:https://github.com/google/battery-historian
    (2)、依旧是方式1,系统方式,记录日志文件,初始化batterystats数据
          adb shell dumpsys batterystats--reset
    (3)、拔掉手机,操作APP,操作完成后,重新连接手机,执行下面的命令,收集系统整体的Battery数据
          adb shell dumpsys batterystats > batterystats.txt
    (4)、得到这些数据后,这个时候使用我们的battery-historian来生成我们可见HTML报告
          python historian.py batterystats.txt > batterystats.html
    (5)、浏览器打开,分析具体结果

如图,level值就是电量,取测试结束后和测试开始时的电量做差,就是我们要得到的测试过程中电量的消耗

方法3、使用腾讯的GT APP,操作选中APP后,将生成的.csv文件保存到本地,再进行分析,如图停止后,获取生成的文件,SD卡目录,找到GT文件夹,具体的分析过程,不在此详细描述

参考:http://gt.tencent.com/docs/a/GTAndroidUserGuide.pdf



方法4、采用市场上提供的第三方工具

耗电量的优化目标,根据不同APP的情况,视频类,游戏类等等,寻找发热原因,优化代码才是关键

9、安装包大小:

包体大小能被列为性能指标,是从APP性能指标及运营两个维度考虑的,用户是更希望包体小的同时性能要好,有时它们会是一个互相取舍的关系。对Android Apk包的资源文件进行解析,分析冗余资源文件,可压缩资源文件,并计算可压缩的比例。

优化方法:

方法1、通过Android studio的分析工具,删除冗余的“历史资源”

方法2、通过Gradle的配置
release {
    minifyEnabled true            //proguard 删除所有未使用的方法和指令
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), "proguard-rules.pro"
    debuggable false
    jniDebuggable false
    renderscriptDebuggable false
    pseudoLocalesEnabled false
    zipAlignEnabled true
}
//应用不需要支持国际化,那么可以设置 resConfigs 为 "zh","en",对于官方的 support library,默认是支持国际化的,也就是包含了很多不同语言的资源文件
defaultConfig {
    //...
    resConfigs "zh","en"
}

方法3、通过将res中的png、jpeg等图片,可考虑转为webp格式使用

10、消耗流量:

目前的网络类型包含2G、3G、4Gwifi,其中还有不同运营商的区分,我们在APP的使用中经常遇到大资源,重复请求,调用响应慢,调用失败等各种情况。在不同的网络类型之下,我们不仅要控制流量使用,还需要加快请求的响应。另外,对于需要联网的手游来说,部分游戏对不同联网方式的网络类型采用了不同的流量消耗策略,主要分为wifi环境和蜂窝网络环境。我们可以根据实际采用的方案来决定具体是否分开两种环境测试。

测试方法:

获取某个应用的PID,再获取该pid的消耗流量值
首先要获取进程的ID,命令:adb shell "ps | grep 具体包名"
然后获取报告:adb shell "cat/proc/pid/net/dev"   注意替换这个pid为上一行命令获取的pid

此应用一共三个进程,其中包含两个独立服务,我们获取pid=16746来进行测试


得到的结果中只需要关注两个值:Receive(app接收到的数据)、Transmit(app发出的请求数据);流量等于这两个值的和:Receive+Transmit,取有效值Receive和Transmit相加即可。

总结:

我们做性能测试的时候,不仅要发现问题,也要定位问题,深入挖掘性能问题的根源才是我们需要持续努力的方向,通过对比其他公司的优秀产品,分析出自身APP的不足,来优化我们的代码,通过竞品分析,可以避免闭门造车,不断完善我们的方案。

另外,除了上文中提到的云测试网站,一些可用的测试工具有:

iTest:http://itest.iflytek.com:8090/

能够记录特定应用的性能消耗情况,包括CPU、内存、流量、电量等信息,支持浮窗实时查看应用的具体信息,iTest不需要集成SDK到应用中,在iTest中选中需要测试的应用即可进行测试;

Emmagee: https://github.com/NetEase/Emmagee

网易开发的性能检测工具,Emmage和iTest一样,不需要在应用中集成SDK,能够对应用的常用性能指标进行检测,并以csv的格式保存方便查看应用的各项参数;

Tencent GT: https://gt.qq.com/

腾讯系的测试工具,直接安装到手机上即可。

参考:

《Android APP性能测试小结(7个性能指标》https://www.cnblogs.com/ailiailan/p/6397663.html

《Android FPS流畅度测试》https://www.jianshu.com/p/1fe9783d266b

《APP性能测试的6项关键指标及测试获取手段》https://blog.csdn.net/hualusiyu/article/details/78460809

《那些年我们用过的显示性能指标》https://blog.csdn.net/tencent_bugly/article/details/51354517

《Android应用性能评测调优》https://www.csdn.net/article/2015-06-12/2824949/1

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271