【實(shí)戰(zhàn)總結(jié)】幀動(dòng)畫(huà)調(diào)優(yōu)實(shí)踐

原文鏈接:https://www.zybuluo.com/avenwu/note/876161

APP架構(gòu)師整理發(fā)布炉菲,轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)。


1.背景

在做動(dòng)畫(huà)的時(shí)候我們有很多選擇方案荒给。

  • 最常見(jiàn)的是Android原生的幀動(dòng)畫(huà)竞膳,位移動(dòng)畫(huà)浓体,旋轉(zhuǎn)動(dòng)畫(huà),屬性動(dòng)畫(huà)等等,具體根據(jù)動(dòng)畫(huà)效果選擇實(shí)現(xiàn)方案喘批;

  • 針對(duì)那些有規(guī)律朋贬,不太復(fù)雜的矢量動(dòng)畫(huà)我們往往也采取自定義View來(lái)實(shí)現(xiàn),比如各種狂拽炫酷的loading動(dòng)畫(huà)蚪燕;

  • 如果自定義實(shí)現(xiàn)成本比較大娶牌,或者難以達(dá)到Android/iOS多端統(tǒng)一,也經(jīng)常采用幀動(dòng)畫(huà)馆纳,由UE提供幀動(dòng)畫(huà)素材诗良;

  • 如果項(xiàng)目支持,也可以使用Airbnb出品的Lottie[1]鲁驶,這是一個(gè)非常牛x的動(dòng)畫(huà)解析庫(kù)鉴裹,不過(guò)對(duì)sdk版本有要求,具體可以自行查驗(yàn)下.

目前最優(yōu)方案是使用Lottie動(dòng)畫(huà)庫(kù)钥弯,在無(wú)法使用Lottie的情況下径荔,我們就需要手動(dòng)來(lái)具體幀動(dòng)畫(huà)的調(diào)優(yōu)了。

本文主要談?wù)勛鰩瑒?dòng)畫(huà)的一些優(yōu)化策略以避免OutOfMemoryError問(wèn)題脆霎。

2. 幀動(dòng)畫(huà)有什么問(wèn)題总处?

我們都知道原生的Android幀動(dòng)畫(huà)在加載序列幀時(shí),是一次性將所有序列幀的圖片編碼到內(nèi)存當(dāng)中的睛蛛,所以執(zhí)行幀數(shù)較多的動(dòng)畫(huà)時(shí)很容易發(fā)生內(nèi)存不足鹦马,拋出?OutOfMemoryError胧谈。

所以呢,你就需要解決內(nèi)存問(wèn)題荸频,基本上可以從以下幾方面入手菱肖;

  • 降幀

    在保證UI效果和視覺(jué)流暢度的情況下盡可能減少幀數(shù),比如UE輸出的序列幀可能默認(rèn)有有4试溯,5十張圖片蔑滓,減幀后可能只有20張;這里一定要注意的是遇绞,必須經(jīng)過(guò)UE來(lái)減幀键袱,RD不允許私自調(diào)整,避免效果不達(dá)標(biāo)摹闽;

  • 壓縮尺寸

    根據(jù)在手機(jī)上的展示大小蹄咖,縮放到一致的高寬,避免屏幕上展示100x100,你用一個(gè)500x500的資源付鹿;

  • 壓縮體積

    采用無(wú)損或者可接受的有損壓縮圖片質(zhì)量澜汤,這個(gè)也無(wú)需多說(shuō),老司機(jī)都懂得舵匾。打個(gè)廣告俊抵,推薦筆者寫(xiě)的IntelliJ插件?http://avenwu.net/biu/;

  • 重寫(xiě)幀動(dòng)畫(huà)的編碼邏輯

    這里的一個(gè)思路是動(dòng)態(tài)編碼圖片,不再一次性加載所有圖片坐梯,通過(guò)懶加載的方式徽诲,圖片對(duì)內(nèi)存的要求會(huì)大幅降低;

3. 手工實(shí)現(xiàn)幀動(dòng)畫(huà)

3.1 幀動(dòng)畫(huà)分析

下面主要針對(duì)?重寫(xiě)幀動(dòng)畫(huà)的編碼邏輯?這個(gè)維度來(lái)聊聊具體的實(shí)現(xiàn)策略吵血。?
既然要重寫(xiě)幀動(dòng)畫(huà)谎替,首先就要知道Android原生幀動(dòng)畫(huà)的實(shí)現(xiàn)邏輯;通過(guò)閱讀相關(guān)源碼蹋辅,筆者繪制了如下簡(jiǎn)化示意圖钱贯,基本涵蓋了幀動(dòng)畫(huà)的構(gòu)造和執(zhí)行過(guò)程;

可以看到幀動(dòng)畫(huà)在首次inflate的時(shí)候會(huì)解析xml侦另,并將每一個(gè)item節(jié)點(diǎn)解析為drawable對(duì)象實(shí)例秩命,然后加入到數(shù)組當(dāng)中;后續(xù)動(dòng)畫(huà)過(guò)程就是輪詢(xún)繪制淋肾,在Drawable容器中繪制當(dāng)前drawable即可硫麻,整體代碼簡(jiǎn)潔漂亮。

但是這個(gè)邏輯我們并不能直接復(fù)用到手工實(shí)現(xiàn)的幀動(dòng)畫(huà)中樊卓,為什么拿愧?這里暫不解答,讀者可以自己思考一下:)

現(xiàn)在我們把幀動(dòng)畫(huà)的實(shí)現(xiàn)策略抽象一下碌尔,它就是一個(gè)生產(chǎn)者和消費(fèi)者的關(guān)系浇辜,如下圖所示:

總的來(lái)說(shuō)我們的優(yōu)化策略集中在編碼和緩存上面券敌,渲染不需要改變。根據(jù)編碼的的策略可能代碼差異會(huì)很大柳洋。在實(shí)際開(kāi)發(fā)中待诅,我們也遇到過(guò)一些坑,比如編碼速度跟不上熊镣,導(dǎo)致渲染的時(shí)候出現(xiàn)跳幀卑雁,推測(cè)主要是CPU時(shí)間切片問(wèn)題。?
所以如果做成單線程編碼绪囱,UI線程渲染是要非常謹(jǐn)慎的测蹲,否則很有可能你的編碼業(yè)務(wù)全部被阻塞了,導(dǎo)致UI層面頻繁丟幀鬼吵。

3.2 Bitmap 復(fù)用

在圖片編碼之后扣甲,我們需要考慮Bitmap的編碼復(fù)用,這樣可以避免每次decode一張圖片都要全新申請(qǐng)一塊內(nèi)存齿椅,通過(guò)復(fù)用已有的bitmap實(shí)例對(duì)象我們可以做到編碼的更低開(kāi)銷(xiāo)琉挖。

其核心在于?Options#inBitmap,這個(gè)API是Android引入的一個(gè)新API涣脚,新API本身沒(méi)什么問(wèn)題示辈,問(wèn)題在于這個(gè)屬性是API 11引入的,但并不可以直接使用遣蚀,這導(dǎo)致做版本判斷的時(shí)候比較坑(你無(wú)法確定這個(gè)接口是否可用,除非你窮舉一下相關(guān)SDK版本)顽耳。根據(jù)源代碼,在API 14的時(shí)候使用該屬性會(huì)拋異常妙同,具體大家可以去develop了解相關(guān)細(xì)節(jié),膝迎。

在引入了Options#inBitmap的時(shí)候一定要注意姿勢(shì)粥帚。否則的話極有可能出現(xiàn)大量日志警告:

  1. Called reconfigure on a bitmap that is in use! This may cause graphical corruption!

當(dāng)然如果出現(xiàn)了這個(gè)警告也不要緊張,肯定是可以解決的限次,這個(gè)警告是在core/jni/android/graphics/Bitmap.cpp中拋出來(lái)的芒涡,含義其大致就是說(shuō)如果你在修改一個(gè)正在被使用的bitmap那么這會(huì)導(dǎo)致graphical corruption。這個(gè)單詞沒(méi)有想到合適的中文翻譯卖漫,我猜就是會(huì)破壞圖形的意思吧费尽。

如果你一定要忽略這個(gè)異常的話,請(qǐng)忍受控制臺(tái)的大量警告輸出羊始,反正我是忍不了旱幼。要解決整個(gè)警告也很簡(jiǎn)單,只要保證復(fù)用bitmap作為inBitmap時(shí)不要使用當(dāng)前正在被ImageView展示的bitmap實(shí)例就可以了突委。

3.3 RAM和CPU的平衡處理

前面提到了柏卤,編碼圖片可能會(huì)跟不上渲染冬三,這是因?yàn)榫幋a一張圖片需要CPU去處理圖片,包括IO之類(lèi)的缘缚,這需要編碼線程申請(qǐng)CPU時(shí)間切片勾笆,如果UI線程或者其他線程池有高優(yōu)的任務(wù),那么編碼這一塊就會(huì)很尷尬桥滨。所以要解決這個(gè)問(wèn)題一方面可以提供bitmap內(nèi)存緩存窝爪,減少需要重新編碼的次數(shù),比如我們通過(guò)調(diào)試把圖片復(fù)用的命中率提高到40%,50%之類(lèi)齐媒。另外一個(gè)就是不能給編碼線程設(shè)置過(guò)低的優(yōu)先級(jí)蒲每,不要覺(jué)得這是后臺(tái)任務(wù)應(yīng)該放一個(gè)BACKGROUND之類(lèi)的低優(yōu)先級(jí),根據(jù)andorid的官方說(shuō)明(具體文檔我忘了)里初,后臺(tái)線程和前臺(tái)(其他默認(rèn)優(yōu)先級(jí)線程)之間獲取CPU的能力差異是非常大的啃勉,好像接近二八開(kāi)的樣子。

3.4 緩存策略

緩存策略也是需要認(rèn)真考慮的地方双妨,前面我們講到了為了平衡編碼壓力淮阐,我們可以引入內(nèi)存緩存,那么以什么策略來(lái)緩存圖片呢刁品?(在心里說(shuō)出一個(gè)答案泣特,看看對(duì)不對(duì))

LRU?

如果你回答LRU的話挑随,恭喜你状您,你的緩存完全失效了。

雖然LRU使用非常廣泛的緩存算法兜挨,但是很遺憾他并不適合幀動(dòng)畫(huà)緩存膏孟,為什么呢?讀者可以自己思考一下LRU的淘汰策略和幀動(dòng)畫(huà)的執(zhí)行策略就明白了拌汇。

所以我們用的是什么裝逼的算法呢柒桑?這個(gè)筆者并不是專(zhuān)研算法的,所以不懂得太多唬人的名字噪舀。不過(guò)回想起多年前求學(xué)時(shí)魁淳,耳(quan)熟(bu)能(wang)詳(ji)的那些算法,你會(huì)想起還有一個(gè)叫LIFO的東西与倡,也就是后進(jìn)先出算法(Last in first out)界逛。

我們根據(jù)需要可以稍加改造找一下,首先實(shí)現(xiàn)一個(gè)LifoCache,這個(gè)可以從LruCache略加改造纺座,然后在取緩存/刪緩存時(shí)息拜,取倒數(shù)第二個(gè)即可。這樣可以最早執(zhí)行的動(dòng)畫(huà)被緩存下來(lái),并且有機(jī)會(huì)再下一輪動(dòng)畫(huà)來(lái)臨時(shí)被復(fù)用该溯。當(dāng)然機(jī)智的你也可以選擇其他更好的算法岛抄。

3.5 優(yōu)化點(diǎn)回顧

以上是我們?cè)趯?shí)踐當(dāng)中總結(jié)的一些比較關(guān)鍵的點(diǎn)。出于尊重原創(chuàng)的職業(yè)素養(yǎng)狈茉,必須聲明夫椭,我們的整體優(yōu)化的啟示靈感來(lái)源于FasterAnimationsContainer[2];?
原項(xiàng)目更多的像一個(gè)示意demo氯庆,存在諸多bug蹭秋,需要修復(fù)才能滿足基本使用,因此我們修復(fù)了這些問(wèn)題堤撵,并且發(fā)起了?
Pull Request[3]仁讨。

不過(guò)從維護(hù)記錄來(lái)看原項(xiàng)目已經(jīng)不太活躍,我們將這些改動(dòng)和新增的功能優(yōu)化做了梳理实昨。?
當(dāng)然除了修復(fù)這些問(wèn)題洞豁,我們實(shí)際上進(jìn)行了幾乎95%以上的重構(gòu),所以嚴(yán)格來(lái)說(shuō)荒给,這兩個(gè)項(xiàng)目除去解決內(nèi)存泄漏的思想丈挟,在工程上已經(jīng)沒(méi)有太多相似處了。

我們主要做了如下改動(dòng):

  1. 消除bitmap編碼警告志电;

  2. 修復(fù)前后臺(tái)切換后動(dòng)畫(huà)僵死的問(wèn)題曙咽;

  3. 取消單例模式,支持每個(gè)ImageView控制獨(dú)立的動(dòng)畫(huà)挑辆;

  4. 新增圖片內(nèi)存緩存例朱,支持緩存比配置;

  5. 動(dòng)畫(huà)不顯示時(shí)緩存自動(dòng)釋放與恢復(fù)鱼蝉;

  6. 支持原生xml定義洒嗤,兼容原生寫(xiě)法;

4. 調(diào)優(yōu)效果

這一節(jié)魁亦,我們簡(jiǎn)單對(duì)比下烁竭,手工實(shí)現(xiàn)的幀動(dòng)畫(huà)和原生幀動(dòng)畫(huà)的內(nèi)存數(shù)據(jù);

4.1 原生標(biāo)準(zhǔn)幀動(dòng)畫(huà)

在這幅圖中吉挣,我們執(zhí)行了一個(gè)完整的操作流程

  • 啟動(dòng)程序(不包含目標(biāo)動(dòng)畫(huà)視圖);

  • 跳轉(zhuǎn)到原生幀動(dòng)畫(huà)Activity婉弹,內(nèi)部有一個(gè)ImageView睬魂,設(shè)置了android:src為一個(gè)xml幀動(dòng)畫(huà);

  • 可以看到剛進(jìn)入目標(biāo)Activity內(nèi)存立刻開(kāi)始大幅上升镀赌,CPU出現(xiàn)了波動(dòng)氯哮;而此時(shí)我們實(shí)際上沒(méi)有開(kāi)始執(zhí)行動(dòng)畫(huà);

  • 獲取ImageView的src并start動(dòng)畫(huà)商佛,此時(shí)內(nèi)存沒(méi)有明顯波動(dòng)喉钢,并且CPU也相對(duì)平穩(wěn)姆打;

  • 持續(xù)播放動(dòng)畫(huà),內(nèi)存和CPU基本不再變化肠虽,維持在一個(gè)高位狀態(tài)幔戏;

  • 退出頁(yè)面,GC后內(nèi)存全部釋放税课;

4.2 懶加載幀動(dòng)畫(huà)

前面已經(jīng)提到闲延,我們的幀動(dòng)畫(huà)支持緩存設(shè)置,所以分別看一下緩存40%和100%緩存的兩種情況韩玩。

我們保持一致的操作流程垒玲,來(lái)看一下優(yōu)化后的幀動(dòng)畫(huà)的數(shù)據(jù);

  • 啟動(dòng)程序(不包含目標(biāo)動(dòng)畫(huà)視圖)

  • 跳轉(zhuǎn)到優(yōu)化幀動(dòng)畫(huà)Activity找颓,內(nèi)部有一個(gè)ImageView合愈,設(shè)置了app:src為一個(gè)xml幀動(dòng)畫(huà);

  • 剛進(jìn)入目標(biāo)Activity內(nèi)存小幅增加击狮,CPU出現(xiàn)波動(dòng)佛析;此時(shí)我們實(shí)際上也沒(méi)有開(kāi)始執(zhí)行動(dòng)畫(huà),這個(gè)內(nèi)存開(kāi)銷(xiāo)是預(yù)覽的首幀帘不;

  • 獲取ImageView的src并start動(dòng)畫(huà)说莫,隨著動(dòng)畫(huà)的執(zhí)行內(nèi)存使用量開(kāi)始慢慢上爬,期間伴隨著CPU的波動(dòng)寞焙;

  • 持續(xù)播放動(dòng)畫(huà)储狭,內(nèi)存達(dá)到一個(gè)穩(wěn)定態(tài),基本不再變化捣郊;CPU持續(xù)變化辽狈;

  • 退出頁(yè)面,GC后內(nèi)存全部釋放呛牲;

類(lèi)似的當(dāng)我們把緩存比調(diào)大刮萌,比如調(diào)到100%后,可以得到一個(gè)新的圖娘扩。這個(gè)圖的內(nèi)存高峰和CPU狀態(tài)基本可以看做是上面兩種情況的結(jié)合體着茸。當(dāng)緩存占比高了,那么后續(xù)需要重新編碼的次數(shù)也就少了琐旁,所以CPU的占用也就少了涮阔。

4.3 數(shù)據(jù)對(duì)比

以我們的測(cè)試為例,選用了?16?張?600x600?的jpg圖片灰殴,每張大小約為?14~18KB?之間敬特。?
為了方便,對(duì)比我們選取幾個(gè)關(guān)鍵點(diǎn)的近似內(nèi)存和CPU數(shù)據(jù)。

5. 使用說(shuō)明

介紹完了原理伟阔,就來(lái)看下怎么使用吧辣之,API層面沒(méi)有做太多改變和原生使用比較接近。由于項(xiàng)目是開(kāi)源的皱炉,這里放上傳送門(mén):

http://hub.hacktons.cn/animation/

通過(guò)上述地址可以獲取項(xiàng)目最新的變化和源代碼等信息怀估。 下面我們簡(jiǎn)單看下目前如何使用我們的優(yōu)化方案來(lái)播放一個(gè)幀動(dòng)畫(huà)。

5.1 配置Gradle依賴(lài)庫(kù)

  1. compile 'com.github.avenwu:animation:0.2.0'

5.2 通過(guò)MockFrameImageView使用動(dòng)畫(huà)

先進(jìn)行動(dòng)畫(huà)定義娃承,一般都是用一個(gè)xml搞定奏夫,方便省事。

在layout中進(jìn)行布局定義

最后在Activity或者其他地方就可以啟動(dòng)動(dòng)畫(huà)了

上面的使用方法維持了和原生幀動(dòng)畫(huà)一致的操作和配置历筝,除了layout里面寫(xiě)的控件不是ImageView酗昼,其他一模一樣的。

5.3 通過(guò)代碼使用動(dòng)畫(huà)

除此之外梳猪,我們也可以直接用代碼來(lái)實(shí)現(xiàn)這個(gè)動(dòng)畫(huà)配置麻削,這也是項(xiàng)目最開(kāi)始所支持的方式,這個(gè)就不需要依賴(lài)任何自定義的View春弥,直接在原生ImageView上生效:

5.4 效果對(duì)比圖

最后看一下各種幀動(dòng)畫(huà)的實(shí)現(xiàn)效果呛哟。

Download Video

6. 小結(jié)

綜合來(lái)看,原生幀動(dòng)畫(huà)更適合體量較小匿沛,內(nèi)存壓力不那么大的幀動(dòng)畫(huà)扫责,如此一次性加載所有幀,可以保證后續(xù)幀切換的流程性逃呼;而MockFrameAnimation則為了解決內(nèi)存問(wèn)題鳖孤,采取動(dòng)態(tài)編碼序列幀。

這相當(dāng)于用CPU的編碼/計(jì)算能力換取了內(nèi)存消耗抡笼;同時(shí)為了達(dá)到適合的平衡苏揣,我們?cè)试S開(kāi)發(fā)者設(shè)置圖片緩存的張數(shù),緩存數(shù)越大那么內(nèi)存消耗越多推姻,需要重新編碼的次數(shù)也就相對(duì)更少平匈;

[1]?https://github.com/airbnb/lottie-android??
[2]?https://github.com/tigerjj/FasterAnimationsContainer??
[3]?https://github.com/tigerjj/FasterAnimationsContainer/issues/11??

?

如果你有好的文章想和大家分享歡迎投稿,直接向我投遞文章鏈接即可藏古。



最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末增炭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子拧晕,更是在濱河造成了極大的恐慌隙姿,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件防症,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蔫敲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)饲嗽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人奈嘿,你說(shuō)我怎么就攤上這事貌虾。” “怎么了裙犹?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵尽狠,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我叶圃,道長(zhǎng)袄膏,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任掺冠,我火速辦了婚禮沉馆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘德崭。我一直安慰自己斥黑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布眉厨。 她就那樣靜靜地躺著锌奴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪憾股。 梳的紋絲不亂的頭發(fā)上鹿蜀,一...
    開(kāi)封第一講書(shū)人閱讀 52,328評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音荔燎,去河邊找鬼耻姥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛有咨,可吹牛的內(nèi)容都是我干的琐簇。 我是一名探鬼主播,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼座享,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼婉商!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起渣叛,我...
    開(kāi)封第一講書(shū)人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤丈秩,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后淳衙,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蘑秽,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饺著,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肠牲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片幼衰。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖缀雳,靈堂內(nèi)的尸體忽然破棺而出渡嚣,到底是詐尸還是另有隱情,我是刑警寧澤肥印,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布识椰,位于F島的核電站,受9級(jí)特大地震影響深碱,放射性物質(zhì)發(fā)生泄漏腹鹉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一莹痢、第九天 我趴在偏房一處隱蔽的房頂上張望种蘸。 院中可真熱鬧,春花似錦竞膳、人聲如沸航瞭。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)刊侯。三九已至,卻和暖如春锉走,著一層夾襖步出監(jiān)牢的瞬間滨彻,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工挪蹭, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留亭饵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓梁厉,卻偏偏與公主長(zhǎng)得像辜羊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子词顾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,290評(píng)論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)八秃、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,120評(píng)論 4 61
  • 1.Android應(yīng)用程序打包時(shí)肉盹,出現(xiàn)錯(cuò)誤:"XXX" is not translated in "af" (Af...
    塔塔付閱讀 373評(píng)論 0 0
  • "人生如果缺少旅行昔驱,那么一生都將抱憾!" 這是我認(rèn)為的人生上忍。一個(gè)完美的人生就應(yīng)該是領(lǐng)略了所有的沿途風(fēng)景和自然風(fēng)光骤肛,...
    凡爾賽玫瑰閱讀 561評(píng)論 0 1
  • 大家一定都痛恨小偷吧纳本,其竊走我們心愛(ài)之物,讓我們蒙受財(cái)物損失腋颠,給生活造成諸多不便饮醇。那你有沒(méi)有想過(guò),我們每天都在不知...
    笑開(kāi)閱讀 172評(píng)論 0 0