RenderScript使用指南

一、入口

https://developer.android.google.cn -> API指南 -> 庫 -> 功能 ->
v8 支持庫 -> RenderScript 開發(fā)者指南
本文章是對上面內(nèi)容的翻譯

二、RenderScript介紹

RenderScript是一個框架棕叫,這個框架是為了可以在性能好的android機器上執(zhí)行密集計算的任務(wù)。RenderScript是以并行的數(shù)據(jù)計算為設(shè)計原則殿怜,盡管對串行的工作也有益系枪。RenderScript在機器的可用處理器上并行運行,例如多核的cpu和GPU固额。這個允許你更多的關(guān)注算法而不是更多的關(guān)注安排工作的執(zhí)行順序眠蚂。
RenderScript特別擅長執(zhí)行圖像處理,計算攝影以及計算機視覺斗躏。


使用RenderScript之前逝慧,要明白下面幾個理念:

  • 使用c99-derived language來完成性能更好的運算代碼。下面的章節(jié)Writing a RenderSctipt Kernel描述了怎么使用它來寫一個運算內(nèi)核啄糙。
  • 控制API用于組織RenderScript資源和控制內(nèi)核執(zhí)行器的生命周期笛臣。運行在三種不同的語言下:Java,android NDK中的C++和c99派生出的內(nèi)核語言。下面的章節(jié)分別描述了第一種在Java中使用RenderScript(Using RenderScript from Java Code)和第三種單一來源的RenderScript(Single-Source renderScript)隧饼。

三沈堡、Writing a RenderScript Kernel

渲染腳本的內(nèi)核通常會在<project_root>/src/文件加下的.rs文件中,每個.rs被稱為一個腳本燕雁。每個腳本包含它自己的一組內(nèi)核诞丽,函數(shù),和變量拐格。一個腳本包含:

  • pragma聲明(#pragme version(1)):腳本中使用渲染腳本內(nèi)核使用的語言版本率拒,而且只能是1

  • pragma聲明(#pragma rs java_package_name(com.example.app)):定義從這個腳本中映射出對應(yīng)Java類的包名。要切記禁荒,.rs文件必須是應(yīng)用包里的代碼的一部分猬膨,而不是位于依賴庫工程中。

  • 0或更多個執(zhí)行函數(shù):執(zhí)行函數(shù)是單線程的渲染腳本函數(shù),可以在Java代碼中通過任意參數(shù)調(diào)用這個函數(shù)勃痴。執(zhí)行函數(shù)通常用于在較大的進程管線內(nèi)的初始化安裝和串行計算谒所。

  • 0或更多個腳本全局:每個腳本全局等同于c中的一個全局變量∨嫔辏可以在Java中訪問腳本全局劣领,腳本全局經(jīng)常作為參數(shù)傳給渲染腳本內(nèi)核。

  • 0或更多個計算內(nèi)核:計算內(nèi)核是單個函數(shù)或函數(shù)集合铁材,計算內(nèi)核可以穿過數(shù)據(jù)集合在渲染腳本運行時并行執(zhí)行尖淘,有兩種計算內(nèi)核:映射內(nèi)核(也被成為foreach 內(nèi)核)和減少內(nèi)核。
    <br />映射內(nèi)核是一個并行的函數(shù)著觉,它運行于相同維度的Allocation的集合中村生。默認的,這些維度中的每一個坐標上的元素執(zhí)行這個函數(shù)一次饼丘。它通常(不一定)用于將輸入Allocation的集合轉(zhuǎn)換為輸出Allocation的集合趁桃。

    • 下面是一個簡單映射內(nèi)核的例子:
      uchar4 RS_KERNEL invert(uchar4 in, uint32_t x, uint32_t y) {
      uchar4 out = in;
      out.r = 255 - in.r;
      out.g = 255 - in.g;
      out.b = 255 - in.b;
      return out;
      }
      在很多層面,這與標準的c函數(shù)相同肄鸽。在函數(shù)原型中使用的RS_KERNEL指明這個函數(shù)是一個渲染腳本映射內(nèi)核而不是一個可執(zhí)行函數(shù)卫病。基于啟動內(nèi)核時的輸入Allocation典徘,in參數(shù)被自動填充蟀苛,x和y參數(shù)會在下面討論。內(nèi)核的返回值會被寫入到輸出Allocation的對應(yīng)位置逮诲。內(nèi)核運行在整個的輸入Allocation上屹逛,在Allocation的每一個元素上執(zhí)行這個內(nèi)核函數(shù)一次。
      <br /> 映射內(nèi)核可能有一個或更多的輸入Allocation汛骂,單個或兩個輸出Allocation罕模。渲染腳本運行的時候會檢查并確保所有的輸入Allocation和輸出Allocation有相同的維度,而且每個元素的類型也要與內(nèi)核的原型(uchar4 in)匹配帘瞭;如果不匹配淑掌,會拋出異常。注意:在Android6.0(API level 23)之前蝶念,映射內(nèi)核只具有不高于一個的輸入Allocation抛腕。
      <br />如果你需要更多的輸入 Allocation 和輸出 Allocation ,這些對象要和名字為rs_allocation腳本全局綁定媒殉,并且在內(nèi)核或者可執(zhí)行函數(shù)中担敌,只能通過rsGetElementAt_type()或者rsSetElementAt_type()來訪問。注意:**為了方便廷蓉,RS_KERNEL是渲染腳本自動產(chǎn)生的宏定義全封。
      #define RS_KERNEL attribute((kernel))

    減少內(nèi)核是一組函數(shù),它運行在相同維度的輸入Allocation上。默認的刹悴,累加器函數(shù)會在Allocation中的每一個坐標的元素上執(zhí)行一次行楞。這個內(nèi)核一般用來減少輸入Allocation的集合將之變成一個。

    • 下面是一個簡單地減少內(nèi)核的例子土匀,功能是將輸入的元素加起來子房。
      #pragma rs reduce(addint) accumulator(addintAccum)

      static void addintAccum(int *accum, int val) {
        *accum += val;
      }  
      

減少內(nèi)核包含一個或更多用戶寫的函數(shù)。#pragma rs reduce通過指定它的名字(例如就轧,addint)证杭,組成內(nèi)核的函數(shù)的名字和角色(例如,一個accumulator函數(shù)addintAccum)來定義內(nèi)核妒御。函數(shù)必須是靜態(tài)的解愤。減少內(nèi)核需要累加器函數(shù);它或許還有別的函數(shù)携丁,取決于你想讓他干什么。
<br />減少內(nèi)核的累加器函數(shù)必須返回void兰怠,必須具有最少兩個參數(shù)梦鉴。第一個參數(shù)(例如 accum)是累加數(shù)據(jù)項的指針,第二個參數(shù)(例如 val)會基于內(nèi)核啟動時傳進來的輸入Allocation參數(shù)自動填充揭保。累加數(shù)據(jù)項是在渲染腳本運行時產(chǎn)生的肥橙;默認值為0。默認的秸侣,這個內(nèi)核運行于整個輸入Allocation上存筏,分配內(nèi)存中的每個元素執(zhí)行累加器函數(shù)一次。默認的味榛,累加數(shù)據(jù)項的最終的值被視為減少內(nèi)核的結(jié)果椭坚,返回到Java中。渲染腳本運行時會檢查并確保輸入Allocation中的元素和累加器函數(shù)的原型匹配搏色,如果不匹配善茎,渲染腳本會拋出異常。
<br />減少內(nèi)核擁有一個以上的輸入Allocation频轿,但是沒有輸出Allocation垂涯。
想了解減少內(nèi)核更多信息,查看下面的部分Reduction Kernels in Depth航邢。
減少內(nèi)核的支持版本是Android7.0或以上耕赘。

映射內(nèi)核的函數(shù)或者減少內(nèi)核的累加器函數(shù)會獲取當前執(zhí)行到哪個坐標(Allocaiton的坐標),通過傳入int/uint32_t類型的參數(shù)x,y,和z膳殷,這些參數(shù)是可選的操骡。
<br />映射內(nèi)核的函數(shù)或者減少內(nèi)核的累加器函數(shù)也可以采用可選的rs_kernel_context類型的上下文作為參數(shù)。一些運行時API需要這個參數(shù)來查詢當前執(zhí)行器的屬性--例如,rsGetDimX当娱。(上下文參數(shù)在Android6.0(API level 23)或以上才可用)吃既。

  • 可選的init()函數(shù)。init()函數(shù)是一種特殊的可執(zhí)行函數(shù)跨细,渲染腳本會在腳本第一次初始化的時候調(diào)用它鹦倚。這樣可以在腳本創(chuàng)建的時候自動進行一些運算。
  • 0或更多個靜態(tài)腳本全局和靜態(tài)函數(shù)冀惭。靜態(tài)的腳本全局和普通的腳本全局一樣震叙,但是它不能從java中訪問。靜態(tài)的函數(shù)是一個標準的c函數(shù)散休,它可以被腳本中的任何內(nèi)核和可執(zhí)行函數(shù)調(diào)用媒楼,但是不暴露給Java的API。如果腳本全局或者函數(shù)不需要再java代碼中調(diào)用戚丸,強烈建議將其聲明為靜態(tài)的划址。

設(shè)置浮點指針的精度

在腳本中你可以控制浮點類型的精度,如果不需要使用IEEE 754-2008標準(default)限府,這點就很有用了夺颤。下面的pragma可以被設(shè)置為不同的浮點指針精度。

  • #pragma rs_fp_full(不指定時的默認值):對于需要浮點精度的應(yīng)用程序胁勺,如IEEE 754-2008標準所述
  • #pragma rs_fp_relaxed:對于不需要嚴格的IEEE 754-2008標準的應(yīng)用程序世澜,可以使用更低的精度,這種模式可以使用刷新到零或者四舍五入到零
  • #pragma rs_fp_imprecise:對于不需要嚴格精度的應(yīng)用署穗。這種模式使得rs_fp_relaxed模式下的所有東西遵循下面的規(guī)則:
    • 結(jié)果是-0.0的可以用+0.0代替
    • INF(無窮大)和NAN(無效數(shù)字)沒有被定義

許多應(yīng)用使用 rs_fp-relaxed 也不會有什么副作用寥裂。對于僅需要放松進度就可以優(yōu)化的架構(gòu)非常有用(就像SIMD CPU instructions)

四、獲取RenderScript APIs

開發(fā)android應(yīng)用時案疲,你可以有兩種方法獲取到RenderScript API:
1封恰、當你開發(fā)的app最低版本是Android3.0(API level 11)時,你可以直接使用android.renderscript
2褐啡、在support library里面俭驮,有android.support.v8.renderscript,最低支持到Android2.3(API level 9)春贸。

下面是你要考慮的點:

  • 如果你使用Support Library APIs混萝,無論你想使用是RenderScript的什么功能,都會兼容到android2.3版本萍恕。這樣可以允許你的應(yīng)用運行在更多的設(shè)備上逸嘀。
  • 部分RenderScript特性將會無效
  • 如果你使用 Support Library APIs,與使用 native APIs 相比允粤,你的apk可能會更大

使用RenderScript Support Library APIS

你必須配置你的開發(fā)環(huán)境才可以獲取到支持庫崭倘。下面這些是必須的:

  • Android SDK Tools version >= 22.2
  • Android SDK Build-tools version >= 18.1.0

你可以通過Android SDK Manager來檢查和更新這些工具的版本
<br />如何使用支持庫

  1. 確認上面工具的版本滿足
  2. 更新android構(gòu)建指引的設(shè)置
    • 打開你的應(yīng)用的module的build.gradle

    • 將下面的RenderScript的設(shè)置添加進去

         android {
             compileSdkVersion 23
             buildToolsVersion "23.0.3"
         
             defaultConfig {
                 minSdkVersion 9
                 targetSdkVersion 19
         
                 renderscriptTargetApi 18
                 renderscriptSupportModeEnabled true
         
             }
         }  
      

上面的設(shè)置控制了構(gòu)建過程的下列行為
- renderscriptTargetApi-會產(chǎn)生指定的字節(jié)碼版本翼岁。在保證功能的前提下,我們建議將這個值設(shè)置為需要支持庫(需要將renderscriptSupportModeEnabled 設(shè)置為 true)的最低版本司光。這個設(shè)置的有效值是大于Android3.0(API level 11)的整型值琅坡,小于最新發(fā)布的API的正式版。如果app中manifest指定的最低sdk版本與這個值不同(我認為意思是小于這個值)残家,build.gradle中設(shè)置的值會被忽略榆俺,并且被設(shè)置為manifest中的最低sdk版本
- renderscriptSupportModeEnabled-如果應(yīng)用所運行的設(shè)備不支持目標版本坞淮,回饋到兼容版本產(chǎn)生特定的字節(jié)碼茴晋。
- buildToolsVersion-構(gòu)建工具的版本。這個版本需要>=18.1.0回窘。如果這個選項沒有指定诺擅,會使用安裝的構(gòu)建工具的最高版本。你應(yīng)該指定這個選項來確保在不同的開發(fā)機器上能有一致的配置啡直。

  1. 如果你的app要使用RenderScript烁涌,導入下面的類:
    import android.support.v8.renderscript.*;

五、在Java中使用(Using RenderScript from Java Code

在Java使用RenderScript需要依賴android.renderscript或者android.support.v8.renderscript包里面的API酒觅。下面是基本的使用模式:

  1. Initialize a RenderScript context:這個RenderScript對象通過RenderScript.create(Context)方法創(chuàng)建撮执,確保RenderScript對象可以被使用而且會提供一個對象來控制后續(xù)的RenderScript的對象的生命周期。你應(yīng)該將context的創(chuàng)建視為一個潛在的長時間運行的操作阐滩,因為他會在不同的硬件上創(chuàng)建資源二打;如果可能的話县忌,初始化操作不應(yīng)該在app的關(guān)鍵路徑(我猜是不是說要延遲初始化)掂榔。通常,一個應(yīng)用在一個階段只會有一個RenderScript Context實例症杏。
  2. Create at least one Allocation to be passed to a scriptAllocation是RenderScript用到的對象装获,它用來給定量的數(shù)據(jù)提供存儲空間。腳本中的內(nèi)核將Allocation對象作為它的輸出和輸入厉颤⊙ㄔィ可以內(nèi)核中通過rsGetElementAt_type()rsSetElementAt_type()來訪問這個對象。Allocation允許將數(shù)組從Java代碼傳遞到RenderScript代碼逼友,反之亦然精肃。Allocation對象通常使用createTyped()或者createFromBitmap()方法來創(chuàng)建。
  3. Create whatever scripts are necessary:當使用RenderScript的時候帜乞,有兩種類型的腳本:
    • ScriptC:這是一個用戶定義的腳本司抱,在上面Writing a RenderScript Kernel有描述過如何寫一個腳本。為了在Java代碼中方便的獲取這個腳本黎烈,每個腳本都有一個通過RenderScript編譯器映射出來的Java類习柠;這個類的名字是ScriptC_filename匀谣。例如,如果上面的內(nèi)核位于invert资溃。rs和RenderScript context**也已經(jīng)在mRenderScript中創(chuàng)建武翎,初始化腳本的代碼是:
      Script_invert invert = new Script_invert(mRenderScript)
    • ScriptIntrinsic:這個腳本創(chuàng)建于RenderScript內(nèi)核,為了一般的操作溶锭,就像Gaussian blur(高斯模糊)宝恶,convolution(卷積)和 image blending(圖像混合)。想了解更多的信息暖途,看一下ScriptIntrinsic的子類卑惜。
  4. Populate Allocations with data:除了通過createFromBitmap()方法創(chuàng)建的對象,Allocation被創(chuàng)建時也可以通過空數(shù)據(jù)來填充驻售。通過Allocationcopy方法來填充露久,這個copy方法是同步的。
  5. Set any necessary script globals:在Script_filename類中欺栗,你可以使用set_globalname方法來設(shè)置毫痕。你的腳本中有一個腳本全局名字是threshold,可以通過set_threshold(int)方法來設(shè)置迟几;通過set_lookup(Allocation)方法設(shè)置一個 as_allocation 類型的腳本全局變量lookup消请。這些set方法異步的**。
  6. Launch the appropriate kernels and invokable functions
    通過ScriptC_filename類中的方法forEach_mappingKernelName()reduce_reductionKernelName()來啟動給定內(nèi)核类腮。這個啟動時異步的臊泰。根據(jù)內(nèi)核中設(shè)定的參數(shù),這個方法采用一個或更多的Allocation蚜枢,所有的Allocation都必須設(shè)定相同的維度缸逃。默認的,內(nèi)核在這些維度的每個坐標上執(zhí)行厂抽;想在這些坐標的子集上運行內(nèi)核需频,需要傳遞合適的參數(shù)Script.LaunchOptions作為forEachreduce方法的最后一個參數(shù)。使用ScriptC_filename類中方法invoke_functionName**來啟動時筷凤,這些啟動是異步的昭殉。
  7. Retrieve data from Allocation objects and javaFuturetype objects。為了在Java代碼中從Allocation獲得數(shù)據(jù)藐守,你要使用Allocation中的'copy'方法將數(shù)據(jù)copy到j(luò)ava中挪丢。想要從減少內(nèi)核中獲取結(jié)果,必須使用javaFutureType.get()方法。上面說的'copy'get()方法是同步的
  8. Tear down the RenderScript context塘砸。你可以通過下面的方法銷毀RenderScript contextdestroy()或者允許RenderScript context對象進行垃圾收集巢块。之后礁阁,你使用任何屬于這個context的對象都會拋出異常。

異步執(zhí)行模式 Asynchronous execution model

方法forEach,invoke,reduce,and set都是異步的族奢,每個方法都有可能在完成目標操作之前返回(返回是不是在說結(jié)束)姥闭。但是,單個操作是串行的越走,依照他們啟動的順序棚品。
<br />Allocation類提供'copy'方法copy數(shù)據(jù)給Alloction對象,或者從Allocation對象中copy出數(shù)據(jù)廊敌。'copy'方法是同步的铜跑,是串行的(相對于上述的異步操作方法操作相同Allocation)。
<br />映射的javaFutureType類提供一個get()方法從reduction中獲取結(jié)果骡澈,get()方法是同步的锅纺,是串行的(相對于異步的reduction)。

六肋殴、單一來源的渲染腳本(Single-Source RenderScript)

Android 7.0 (API 24) 介紹了一種新的編程特性-Single-Source RenderScript,新的特性中囤锉,在script定義的時候,kernels從script中產(chǎn)生而不是從Java中產(chǎn)生』ご福現(xiàn)在這種方式局限于映射內(nèi)核中官地,在這個部分中簡稱為"kernels"。這種新的特征也支持在script中創(chuàng)建rs_allocation類型的Allocation±优常現(xiàn)在可以在單獨的腳本中實現(xiàn)整個算法驱入,即使需要啟動多個kernels。優(yōu)點是雙重的:1.更多的可讀代碼氯析,因為他用一種語言來實現(xiàn)算法亏较;2.潛在的,存在實現(xiàn)更快的代碼的可能魄鸦,因為在多個kernels啟動時宴杀,Java和RenderScript之間的轉(zhuǎn)換變少了癣朗。
<br />在Single-Source RenderScript中拾因,你寫一個Writing a RenderScript Kernel部分中描述的kernels。寫一個叫做 rsForEach() 可執(zhí)行的功能來啟動kernels旷余。這個方法采用一個內(nèi)核函數(shù)作為其第一個參數(shù)绢记,接下來是輸入Allocation和輸出Allocation。里一個相似的方法 reForEachWithOptions() 采用一個額外的參數(shù) rs_script_call_it正卧,這個參數(shù)指定一個輸入Allocation和輸出Allocation的元素子集作為內(nèi)核函數(shù)執(zhí)行的空間蠢熄。
<br />按照 Using RenderScript from Java Code 部分中的步驟,可以調(diào)用Java中特定執(zhí)行函數(shù)來開啟RenderScript 運算炉旷。在 launch the appropriate kernels 這一步中签孔,調(diào)用一個可執(zhí)行函數(shù) invoke_function_name()** 來開啟整個運算叉讥,包括啟動kernels。
<br />從一個內(nèi)核啟動到另一個內(nèi)核啟動饥追,經(jīng)常需要使用 Allocation 保存和及時傳遞結(jié)果图仓。你可以通過 rsCreateAllocation() 來創(chuàng)建他們。這個API的一種方便使用的方式是reCreateAllocation_<T><W>(...),T是元素的數(shù)據(jù)類型但绕,W是這個元素的矢量寬度救崔。這個函數(shù)采用X,Y和Z這三個維度作為參數(shù),對于1D和2D的allocation,Y或Z維度的尺寸會被忽略捏顺。例如六孵,reCreateAllocation_uchar4(16384)創(chuàng)建了一個含有16384個一維元素的分配空間,每一個元素都是uchar4類型的幅骄。
<br />分配的空間由系統(tǒng)自動管理劫窒,你不必特地的去釋放他們。但是拆座,你可以調(diào)用 rsClearObject(rs_allocation* alloc) 來表明你不再需要這塊內(nèi)存烛亦,這樣系統(tǒng)能盡快的將這塊資源釋放掉。
<br />Writing a RenderScript Kernel部分有一個轉(zhuǎn)換圖片簡單例子懂拾。下面使用 Single-Source RenderScript 拓展這個例子煤禽,對這個圖片做更多的操作,它包含另外一個內(nèi)核岖赋,greyscale,用來將一個彩色的圖片轉(zhuǎn)換為黑白的檬果。process()方法將兩個內(nèi)核連續(xù)的應(yīng)用于輸入的圖片(輸入的圖片Allocation),產(chǎn)生一個輸出圖片唐断。輸入 Allocation 和輸出 Allocation 作為 rs_allocation 的參數(shù)傳入选脊。

// File:singleSource.rs

#pragma version(1)
#pragma rs java_package_name(com.android.rssample)

static const float4 weight = {0.299f, 0.587f, 0.114f, 0.0f};

uchar4 RS_KERNEL invert(uchar4 in, uint32_t x, uint32_t y) {
  uchar4 out = in;
  out.r = 255 - in.r;
  out.g = 255 - in.g;
  out.b = 255 - in.b;
  return out;
}

uchar4 RS_KERNEL greyscale(uchar4 in) {
  const float4 inF = rsUnpackColor8888(in);
  const float4 outF = (float4){ dot(inF, weight) };
  return rsPackColorTo8888(outF);
}

void process(rs_allocation inputImage, rs_allocation outputImage) {
  const uint32_t imageWidth = rsAllocationGetDimX(inputImage);
  const uint32_t imageHeight = rsAllocationGetDimY(inputImage);
  rs_allocation tmp = rsCreateAllocation_uchar4(imageWidth, imageHeight);
  rsForEach(invert, inputImage, tmp);
  rsForEach(greyscale, tmp, outputImage);
}  

你可以像下面一樣在Java中調(diào)用process()函數(shù):

// File SingleSource.java

RenderScript RS = RenderScript.create(context);
ScriptC_singlesource script = new ScriptC_singlesource(RS);
Allocation inputAllocation = Allocation.createFromBitmapResource(
    RS, getResources(), R.drawable.image);
Allocation outputAllocation = Allocation.createTyped(
    RS, inputAllocation.getType(),
    Allocation.USAGE_SCRIPT | Allocation.USAGE_IO_OUTPUT);
script.invoke_process(inputAllocation, outputAllocation);  

這個例子展示了完全通過RenderScript語言來實現(xiàn)一個涉及到兩個內(nèi)核的算法。沒有 Single-Source RenderScript 脸甘,你必須在Java中啟動兩個內(nèi)核恳啥,分別啟動兩個內(nèi)核會使整個算法變得難以理解。Single-Source RenderScript 特性不單使代碼更容易看懂丹诀,它還消除了內(nèi)核啟動期間 Javascript 之間的過渡钝的。一些迭代算法會啟動內(nèi)核上百次,使得這種轉(zhuǎn)換的開銷相當?shù)拇蟆?/p>

七铆遭、Reduction Kernels in Depth

...

將會在下面的章節(jié)中講述一個使用 RenderScript 進行高斯模糊的例子硝桩,敬請期待

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市枚荣,隨后出現(xiàn)的幾起案子碗脊,更是在濱河造成了極大的恐慌,老刑警劉巖橄妆,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衙伶,死亡現(xiàn)場離奇詭異祈坠,居然都是意外死亡,警方通過查閱死者的電腦和手機矢劲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進店門颁虐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人卧须,你說我怎么就攤上這事另绩。” “怎么了花嘶?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵笋籽,是天一觀的道長。 經(jīng)常有香客問我椭员,道長车海,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任隘击,我火速辦了婚禮侍芝,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘埋同。我一直安慰自己州叠,他們只是感情好,可當我...
    茶點故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布凶赁。 她就那樣靜靜地躺著咧栗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪虱肄。 梳的紋絲不亂的頭發(fā)上致板,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天,我揣著相機與錄音咏窿,去河邊找鬼斟或。 笑死,一個胖子當著我的面吹牛集嵌,可吹牛的內(nèi)容都是我干的萝挤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼纸淮,長吁一口氣:“原來是場噩夢啊……” “哼平斩!你這毒婦竟也來了亚享?” 一聲冷哼從身側(cè)響起咽块,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎欺税,沒想到半個月后侈沪,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體揭璃,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年亭罪,在試婚紗的時候發(fā)現(xiàn)自己被綠了瘦馍。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,561評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡应役,死狀恐怖情组,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情箩祥,我是刑警寧澤院崇,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站袍祖,受9級特大地震影響底瓣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蕉陋,卻給世界環(huán)境...
    茶點故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一捐凭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧凳鬓,春花似錦茁肠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蚁孔,卻和暖如春奶赔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背杠氢。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工站刑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鼻百。 一個月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓绞旅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親温艇。 傳聞我的和親對象是個殘疾皇子因悲,可洞房花燭夜當晚...
    茶點故事閱讀 45,573評論 2 359

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

  • [譯]原文鏈接 RenderScript是運行在Android系統(tǒng)上的一個高性能密集計算框架。RenderScri...
    stefanli閱讀 8,461評論 0 13
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理勺爱,服務(wù)發(fā)現(xiàn)晃琳,斷路器,智...
    卡卡羅2017閱讀 134,702評論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法卫旱,內(nèi)部類的語法人灼,繼承相關(guān)的語法,異常的語法顾翼,線程的語...
    子非魚_t_閱讀 31,664評論 18 399
  • Flexible ellipses 顧名思義投放,靈活的橢圓。橢圓适贸,是我們今天的主角灸芳。拿它用來做什么呢???拜姿,對了耗绿,拿它...
    Scaukk閱讀 631評論 0 1
  • 我是日記星球177號星寶寶熙怡(yaya),我正在參加日記星球21天蛻變之旅砾隅,這是我的第57篇原創(chuàng)日記误阻。 我是家庭...
    妙丫丫POI閱讀 207評論 1 2