Android:自定義播放器傳視集成文檔(java划纽,AS)

請以Conviva開發(fā)者社區(qū)作為主要參考源。


一 前言

Conviva在android播放器中的集成需要兩個jar包青柄,一個是core包(Conviva_SDK_Android)阵漏,一個是每個播放器獨(dú)有的包(在下文中我們稱之為Proxy)。

Proxy在我們的開發(fā)者社區(qū)播放器庫里已經(jīng)有了很多的播放器類型绽左,按照相關(guān)的步驟集成就可以悼嫉,但是也有很多播放器我們播放器庫里是沒有的,Proxy就需要由我們進(jìn)行定制開發(fā)拼窥,以提供給開發(fā)者使用戏蔑。

但是,有很多的公司播放器的SDK可能涉及到保密鲁纠,我們無法直接提供定制方案总棵,就開放了自定義播放器Proxy的開發(fā)流程,以供開發(fā)者使用改含。

對于conviva集成自定義播放器而言情龄,Proxy是開發(fā)工作的核心

二 概念介紹

很多類封裝在ConvivaSessionManager類中,開發(fā)者可以靈活處理骤视。

??Session

Conviva對一段視頻數(shù)據(jù)的檢測是以Session為單位鞍爱,從創(chuàng)建Session開始(mSessionKey = mClient.creaateSession)到銷毀Session結(jié)束(mClient.cleanupSession(mSessionKey))。對這段視頻評估的數(shù)據(jù)专酗,都是從這個過程中獲取的睹逃。

??PlayStateManager

在創(chuàng)建Session開始到銷毀Session結(jié)束的過程中,需要傳遞視頻的播放狀態(tài)(mStateManager.setPlayerState(…))祷肯,上傳播放的錯誤(mStateManager.sendError(…))等等沉填。

Conviva自身分為以下幾個必須的標(biāo)準(zhǔn)狀態(tài):SOPPED(停止)PLAYING(播放)佑笋,BUFFERING(緩沖)翼闹,PAUSED(暫停)UNKNOW(未知)允青,開發(fā)者需要根據(jù)播放器的實(shí)際情況分別對應(yīng)Conviva的這五個狀態(tài)(后面會對比兩種自定義播放器Proxy的開發(fā)方案橄碾,幫助開發(fā)者理解)。

??ContentMetadata

我們提供了ContentMetadata這個類傳遞一些視頻信息(又叫元數(shù)據(jù))颠锉,比如視頻url法牲,視頻類型,ViewId等等琼掠。

??Client

主要用于創(chuàng)建Session拒垃,關(guān)聯(lián)Player和銷毀Session,發(fā)送事件(包括廣告事件瓷蛙、自定義事件)悼瓮。

三 集成流程

??導(dǎo)入SDK

到官網(wǎng)下載最新Conviva_SDK_Android,復(fù)制Conviva_SDK_Android到app的libs文件夾艰猬,Add As Liraty横堡。

找到Demo的helper文件夾,復(fù)制ConvivaSessionManager文件到項(xiàng)目中合適位置(建議復(fù)制冠桃,可以根據(jù)需求適當(dāng)修改命贴,也可以自己寫)。

??替換key

確定mGateWayUrl食听,測試階段的mGateWayUrl一般是https://testonly.conviva.com或ClientSettings.defaultDevelpomentGatewayUrl胸蛛,測試沒問題后替換成pulse的url;

??初始化

app啟動第一次調(diào)用即可(可以寫在Application)

ConvivaSessionManager.initClient(this,?mGateWayUrl);

??傳遞視頻基礎(chǔ)信息(配置元數(shù)據(jù))

創(chuàng)建Session,表示對一段視頻檢測的開始(位置在播放器開始請求視頻數(shù)據(jù)之前即可樱报,進(jìn)行到這一步Touchstone是有數(shù)據(jù)的葬项,盡管可能狀態(tài)不準(zhǔn)確),可以放在ConvivaSessionManager類中迹蛤,也可以根據(jù)需求調(diào)整位置民珍。如下:

//mStateManager需要在createSession和創(chuàng)建Proxy之前創(chuàng)建

mStateManager?=?ConvivaSessionManager.getPlayerManager();

//視頻基本信息

mStateManager.setBitrateKbps(-1);

ContentMetadata?convivaMetaData?=?new?ContentMetadata();

convivaMetaData.defaultResource?=?"AKAMAI";

//app的name

convivaMetaData.applicationName?=?"ConvivaSdk?Demo";

//視頻別名

convivaMetaData.assetName?=?"mediaplayer?test?video";

convivaMetaData.streamUrl?=?"www.sdadas.mp4";

/*這里表示視頻類型是點(diǎn)播襟士,conviva有三個標(biāo)準(zhǔn):VOD,LIVE,UNKNOEN,分別表示直播,點(diǎn)播和未知類型嚷量。*/

convivaMetaData.streamType?=?ContentMetadata.StreamType.VOD;

convivaMetaData.duration?=?0;

convivaMetaData.encodedFrameRate?=?-1;

//自定義tag敌蜂,根據(jù)用戶實(shí)際需求,設(shè)置一些tag

Map?tags?=?new?HashMap<>();

Tags.put("key",?"value");

//創(chuàng)建Session津肛,后面的參數(shù)就是視頻的url

ConvivaSessionManager.createConvivaSession(convivaMetaData);

通過convivaMetaData信息都會在Touchstone上顯示,如下圖:

??實(shí)例化Proxy對象

監(jiān)聽Player的播放狀態(tài)等信息,這是對視頻進(jìn)行監(jiān)控的過程汗贫,Proxy對象要在mStateManagermPlayer不為null的地方進(jìn)行實(shí)例化(后面詳細(xì)介紹這個Proxy的寫法)身坐。

//實(shí)例化Proxy,需要傳遞參數(shù)PlayerStateManager和播放器Player對象落包。

mPlayerInterface?=?new?CVXXXPlayerInterface(mStateManager,?mPlayer);

??對廣告部蛇,比特率,自定義錯誤咐蝇,自定義事件的操作

A:在廣告的監(jiān)聽中設(shè)置:

//廣告開始

ConvivaSessionManager.adStart();

//廣告開始自定義事件(可選涯鲁,作為廣告開始的補(bǔ)充,可傳遞一些信息)

ConvivaSessionManager.podEvent(ConvivaSessionManager.POS_EVENT_POD_START);

//廣告結(jié)束

ConvivaSessionManager.adEnd();

//廣告結(jié)束自定義事件(可選有序,作為廣告結(jié)束的補(bǔ)充抹腿,可傳遞一些信息)

ConvivaSessionManager.podEvent(ConvivaSessionManager.POS_EVENT_POD_END);

B:在可監(jiān)測比特率變化的監(jiān)聽中設(shè)置:

mPlayeStateManager.setBitrateKbps(…);

C:在系統(tǒng)檢測不到的錯誤,需要自定義的時候調(diào)用:

mPlayeStateManager.sendError(…);

D:在分辨變化的監(jiān)聽中設(shè)置:

mPlayeStateManager.setVideoWidth(…);

mPlayeStateManager.setVideoHeight(…);

??銷毀Session

表示對一段視頻的檢測結(jié)束旭寿。一般是在back時警绩,進(jìn)入下個視頻等結(jié)束該視頻時調(diào)用。包括三部分:

//清除Proxy

mPlayerInterface.cleanup();

//釋放mPlayeStateManager

ConvivaSessionManager.releasePlayerStateManager();

//清除Session

ConvivaSessionManager.cleanupConvivaSession();

?釋放Client

退出app時銷毀即可

ConvivaSessionManager.deinitClient();

四 測試

上述集成步驟進(jìn)行完以后盅称,conviva就可以對視頻進(jìn)行檢測肩祥,經(jīng)過后臺大數(shù)據(jù)分析返回有用的數(shù)據(jù)信息,初步集成之后需要用TouchStone進(jìn)行測試(測試流程詳見《TouchStone的使用及測試流程》)缩膝。

五 Proxy文件寫法

參考Demo的Proxy文件混狠,對照稍加修改即可。

在android開發(fā)中疾层,多次注冊Linister會被覆蓋掉将饺,只有最后一次注冊的Linister會生效。我們官方的Proxy文件都做了處理云芦,可參考我們的Proxy方案俯逾,按部就班的進(jìn)行,以免監(jiān)聽事件失效導(dǎo)致conviva檢測失敗舅逸。不同播放器的方案不盡相同桌肴,以下是兩種播放器的方案,一般來講琉历,第一種方案是自定義播放器常用的坠七,如果播放器的API不能滿足需求水醋,就采用第二種方案,開發(fā)者要靈活制定開發(fā)方案彪置,如果都不滿足需求拄踪,請登陸傳視網(wǎng)站咨詢我們。

ExoPlayer2 + Proxy:

Exoplayer的Proxy方案是依賴于各種Linister監(jiān)聽事件維護(hù)視頻播放狀態(tài)和獲取相關(guān)信息拳魁,因?yàn)橐曨l的四個狀態(tài)Buffering惶桐,Playing,Paused潘懊,Stopped以及其他信息都可以獲取到姚糊。

??在onPlayerStateChanges()回調(diào)方法中,可以更新四種必須的視頻播放狀態(tài)和視頻的Duration

@Override

public?void?onPlayerStateChanged(boolean?playWhenReady,?int?playbackState)?{

????if?(_inListener){

????????return;

????}

????stateChanged(playWhenReady,playbackState);

????if?(eventListener?!=?null){

????????_inListener?=?true;

????????eventListener.onPlayerStateChanged(playWhenReady,?playbackState);

????????_inListener?=?false;

????}

}


public?void?stateChanged(boolean?playWhenReady,?int?playbackState)?{

????try?{

????????switch?(playbackState)?{

????????????case?ExoPlayer.STATE_BUFFERING:

????????????????mStateManager.setPlayerState(PlayerState.BUFFERING);

????????????????break;

????????????case?ExoPlayer.STATE_ENDED:

????????????????mStateManager.setPlayerState(PlayerState.STOPPED);

????????????????break;

????????????case?ExoPlayer.STATE_IDLE:

????????????????mStateManager.setPlayerState(PlayerState.STOPPED);

????????????????break;

????????????case?ExoPlayer.STATE_READY:

????????????????if?(playWhenReady)?{

????????????????????mStateManager.setPlayerState(PlayerState.PLAYING);

????????????????????if?(!isContentSet)?{


????????????????????????//content?length?is?available?only?after?preparing?state

????????????????????????//mStateManager.setDuration(((int)?mPlayer.getDuration()?/?1000));


????????????????????????ContentMetadata?metadata?=?new?ContentMetadata();

????????????????????????metadata.duration?=?(int)?mPlayer.getDuration()?/?1000;

????????????????????????mStateManager.updateContentMetadata(metadata);

????????????????????????isContentSet?=?true;

????????????????????}

????????????????}?else?{

????????????????????mStateManager.setPlayerState(PlayerState.PAUSED);

????????????????}

????????????????break;

????????????default:

????????????????break;

????????}

????}?catch?(Exception?e)?{

????????Log("Player?state?exception",?SystemSettings.LogLevel.DEBUG);

????}

}

??在onViewSizeChanged()回調(diào)方法中調(diào)用updateResolution (width, height)授舟,更新分辨率

@Override

public?void?onVideoSizeChanged(int?width,?int?height,?int?unappliedRotationDegrees,?float?pixelWidthHeightRatio)?{

????if?(_viListener)?return;

????updateResolution(width,height,unappliedRotationDegrees,pixelWidthHeightRatio);

????if?(videoListener?!=?null)?{

????????_viListener?=?true;

????????videoListener.onVideoSizeChanged(width,?height,?unappliedRotationDegrees,pixelWidthHeightRatio);

????????_viListener?=?false;

????}

}

??在onPlayerError()回調(diào)方法中調(diào)用mStateManager.sendError(errorCode, Client.ErrorSeverity.FATAL)提交錯誤救恨,ctrl點(diǎn)開ExoPlaybackException.TYPE_SOURCE可以看到源碼中所有errorCode

@Override

public?void?onPlayerError(ExoPlaybackException?error)?{

????if?(_inListener)?return;

????try?{

????????updateError(error);

????????if?(eventListener?!=?null){

????????????_inListener?=?true;

????????????eventListener.onPlayerError(error);

????????????_inListener?=?false;

????????}

????}?catch?(ConvivaException?e)?{

????????e.printStackTrace();

????}

}

public?void?updateError(ExoPlaybackException?errorMsg)?throws?ConvivaException?{

????String?errorCode?=?null;

????if?(errorMsg.type?==?ExoPlaybackException.TYPE_SOURCE)?{

????????errorCode?=?TYPE_SOURCE+":"+errorMsg.getSourceException();

????}

????else?if?(errorMsg.type?==?ExoPlaybackException.TYPE_RENDERER)?{

????????errorCode?=?TYPE_RENDERER+":"+errorMsg.getRendererException();

????}

????else?if?(errorMsg.type??==?ExoPlaybackException.TYPE_UNEXPECTED)?{

?????????errorCode?=?TYPE_RUNTIME+":"+errorMsg.getUnexpectedException();

????}

????else?{

????????errorCode?=?UNKONW_EXPECTION+":"+errorMsg.getMessage();

????}

????if?(mStateManager!=?null)?{

????????mStateManager.setPlayerState(PlayerState.STOPPED);

????????mStateManager.sendError(errorCode,?Client.ErrorSeverity.FATAL);

????}

}

??在Seek結(jié)束的回調(diào)方法onPositionDiscontinuity()中調(diào)用mStateManager.setPlayerSeekEnd(),告知后臺

@Override

public?void?onPositionDiscontinuity()?{

????try?{

????????mStateManager.setPlayerSeekEnd();

????}?catch?(ConvivaException?e)?{

????????e.printStackTrace();

????}

}

MediaPlayer Proxy:

MediaPlayer的Proxy方案是依賴于各種Linister監(jiān)聽事件和播放器Position結(jié)合定時任務(wù)維護(hù)視頻播放狀態(tài)和獲取相關(guān)信息释树。

A 依賴于監(jiān)聽事件

??在onPrepare()回調(diào)方法中更新視頻播放狀態(tài)為Buffering肠槽,更新播放器的Height,Width, 提交了視頻的Duration

@Override

public?void?onPrepared(MediaPlayer?mp)?{

????Log("OnPrepared",?SystemSettings.LogLevel.DEBUG);

????if?(_inListener)?return;


????//執(zhí)行該回調(diào)方法時奢啥,認(rèn)為player處于Buffering狀態(tài)

????updateState(PlayerState.BUFFERING);


????//傳遞此時player的寬高或者說是分辨率

????updateResolution(_mPlayer.getVideoHeight(),?_mPlayer.getVideoWidth());

????_mIsPlayerActive?=?true;


????if(mp?!=?null)?{

????????int?duration?=?mp.getDuration();

????????if?(mStateManager?!=?null?&&?duration?>?0)?{

????????????try?{

????????????????//mStateManager.setDuration(duration?/?1000);廢棄的api秸仙,下面是最新的

????????????????//獲取視頻時長傳遞給conviva

????????????????ContentMetadata?metadata?=?new?ContentMetadata();

????????????????metadata.duration?=?duration?/?1000;

????????????????Log.e("time",metadata.duration+"");

????????????????mStateManager.updateContentMetadata(metadata);

????????????}?catch?(Exception?e)?{

????????????????e.printStackTrace();

????????????}

????????}

????}

}

??在OnCompletion()的回調(diào)中,更新播放狀態(tài)為Stopped扫尺。

@Override

public?void?onCompletion(MediaPlayer?mp)?{

????Log("onCompletion",?SystemSettings.LogLevel.DEBUG);

????if?(_inListener)?return;

????_mIsPlayerActive?=?false;

????updateState(PlayerState.STOPPED);


????//可以觀察到筋栋,每個回調(diào)都會有這種寫法,目的是不影響外面對監(jiān)聽事件的使用正驻。如果不理解弊攘,對照寫就行。

????if?(_onCompListenerOrig?!=?null)?{

????????_inListener?=?true;

????????try?{

????????????_onCompListenerOrig.onCompletion(mp);

????????}?finally?{

????????????_inListener?=?false;

????????}

????}

}

??在onVideoSizeChanged()回調(diào)方法中調(diào)用updateResolution (width, height)姑曙,更新分辨率;

@Override?

public?void?onVideoSizeChanged(MediaPlayer?mp,?int?width,?int?height)?{

????updateResolution(width,?height);

}

//更新分辨率

public?void?updateResolution(int?width,?int?height)?{

????if(mStateManager?!=?null)?{

????????try?{

????????????mStateManager.setVideoWidth(width);

????????????mStateManager.setVideoHeight(height);

????????}?catch?(ConvivaException?e)?{

????????????e.printStackTrace();

????????}

????}

}

??在onError()回調(diào)方法中調(diào)用mStateManager.sendError(errorCode, Client.ErrorSeverity.FATAL)提交錯誤襟交,ctrl點(diǎn)開Mediaplayer.MEDIA_ERROR_UNKNOWN可以看到源碼中所有errorCode。

@Override

public?boolean?onError(MediaPlayer?mp,?int?what,?int?extra)?{


????//Log("OnError?:?Error?occurred",?SystemSettings.LogLevel.DEBUG);

????if?(_inListener)?return?true;


????if(mStateManager?!=?null)?{

????????Log("Proxy:?onError?("?+?what?+?",?"?+?extra?+?")",?SystemSettings.LogLevel.DEBUG);

????????String?errorCode?=?null;

????????if?(what?==?MediaPlayer.MEDIA_ERROR_UNKNOWN)?{

????????????errorCode?=?ERR_UNKNOWN;

????????}

????????else?if?(what?==?MediaPlayer.MEDIA_ERROR_SERVER_DIED)?{

????????????errorCode?=?ERR_SERVERDIED;

????????}

????????else?if?(what?==?MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK)?{

????????????errorCode?=?ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK;

????????}

????????else?{

????????????errorCode?=?ERR_UNKNOWN;

????????}


????????try?{

????????????mStateManager.sendError(errorCode,?Client.ErrorSeverity.FATAL);

????????}?catch?(Exception?e)?{

????????????e.printStackTrace();

????????}

????}


????//clean?up?session?if?the?error?causes?video?start?failure

????//可以觀察到伤靠,每個回掉都會有這種寫法捣域,如果不理解,對照寫就行宴合,目的是不影響外面對監(jiān)聽事件的使用焕梅。

????if?(_onErrorListenerOrig?!=?null)?{

????????_inListener?=?true;

????????try?{

????????????return?_onErrorListenerOrig.onError(mp,?what,?extra);

????????}?finally?{

????????????_inListener?=?false;

????????}

????}

????return?true;

}

??在Seek結(jié)束的回調(diào)方法onSeekComplete()中調(diào)用mStateManager.setPlayerSeekEnd(),告知后臺卦洽。

@Override

public?void?onSeekComplete(MediaPlayer?mp)?{

????if(mStateManager?!=?null)?{

????????try?{

????????????mStateManager.setPlayerSeekEnd();

????????}?catch?(ConvivaException?e)?{

????????????Log("Exception?occurred?during?Seek?End",?SystemSettings.LogLevel.ERROR);

????????}

????}


????if(_onSeekListenerOrig?!=?null)?{

????????_onSeekListenerOrig.onSeekComplete(mp);

????}

}

B 依賴于定時任務(wù)

??除了onPrepare()和onCompeletion(),已經(jīng)沒有監(jiān)聽方法可以提供給我們更新Playing和Paused的狀態(tài)了贞言,Buffering在這里就調(diào)用一次,后面的Buffering狀態(tài)也沒辦法拿到阀蒂,于是就有了定時器去判斷這些狀態(tài)(依賴于判斷position變化確定播放狀態(tài))该窗。通過對上一次position和本次position的對比弟蚀,判斷Buffering,Playing,Paused狀態(tài)并提交給conviva。

//定時器200ms執(zhí)行一次任務(wù)

ITimerInterface?iTimerInterface?=?new?AndroidTimerInterface();

_mCancelTimer?=?iTimerInterface.createTimer(_pollStreamerTask,?200,?"CVMediaPlayerInterface");?

//根據(jù)position酗失,判斷狀態(tài)的定時任務(wù)

private?Runnable?_pollStreamerTask?=?new?Runnable()?{

????@Override

????public?void?run()?{

????????GetPlayheadTimeMs();

????}

};


//定時任務(wù)執(zhí)行的方法??

public?int?GetPlayheadTimeMs()?{??????

????int?currPos?=?-1;??????

????try?{??


????????//Check?if?player?is?not?null?and?player?is?prepared?before?pht?values?are?queried.??????????

????????if(_mPlayer?!=?null?&&?_mIsPlayerActive)?{??????????????

????????????currPos?=?_mPlayer.getCurrentPosition();?


????????????//isPlaying?在Playing或Buffering狀態(tài)為true??????????????

????????????if(_mPlayer.isPlaying())?{???????????????????

????????????????//i如果當(dāng)前position和前一次position相同??????????????????

????????????????if(currPos?==?_previousPosition)?{??????????????????????

????????????????????updateState(PlayerState.BUFFERING);??????????????????

????????????????}?else?{??????????????????????

????????????????????updateState(PlayerState.PLAYING);??????????????????

????????????????}??????????????????

????????????????_previousPosition?=?currPos;??????????????

????????????}?else?{???????????????????


????????????//If?isPlaying?is?false,?player?is?paused.??????????????????

????????????updateState(PlayerState.PAUSED);??????????????

????????????}??????????

????????}??????

????}?catch?(IllegalStateException?e)?{??????????

????????e.printStackTrace();??????

????}??????

????return?currPos;??

}

六 常見錯誤

Touchstone報以下錯誤:

原因:在attachPlayer()時傳入的PlayerStateManager對象為null」骐龋可能是在CreateSession之后才實(shí)例化PlayStateManager對象拖刃。

解決辦法:需要在CreateSession之前實(shí)例化PlayStateManager對象。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市发绢,隨后出現(xiàn)的幾起案子边酒,更是在濱河造成了極大的恐慌墩朦,老刑警劉巖氓涣,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件劳吠,死亡現(xiàn)場離奇詭異痒玩,居然都是意外死亡蠢古,警方通過查閱死者的電腦和手機(jī)别凹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進(jìn)店門到涂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人践啄,你說我怎么就攤上這事屿讽》ヌ福” “怎么了诵棵?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵嘶窄,是天一觀的道長柄冲。 經(jīng)常有香客問我忠蝗,道長阁最,這世上最難降的妖魔是什么速种? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任哟旗,我火速辦了婚禮闸餐,結(jié)果婚禮上舍沙,老公的妹妹穿的比我還像新娘。我一直安慰自己壹无,他們只是感情好斗锭,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著帮毁,像睡著了一般烈疚。 火紅的嫁衣襯著肌膚如雪爷肝。 梳的紋絲不亂的頭發(fā)上阶剑,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天,我揣著相機(jī)與錄音外莲,去河邊找鬼偷线。 笑死声邦,一個胖子當(dāng)著我的面吹牛亥曹,可吹牛的內(nèi)容都是我干的媳瞪。 我是一名探鬼主播蛇受,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼兢仰,長吁一口氣:“原來是場噩夢啊……” “哼轻专!你這毒婦竟也來了秸弛?” 一聲冷哼從身側(cè)響起递览,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤镜雨,失蹤者是張志新(化名)和其女友劉穎儿捧,沒想到半個月后菲盾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體诡挂,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年临谱,在試婚紗的時候發(fā)現(xiàn)自己被綠了璃俗。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,664評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡悉默,死狀恐怖城豁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抄课,我是刑警寧澤唱星,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站跟磨,受9級特大地震影響魏颓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜偷遗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一泵喘、第九天 我趴在偏房一處隱蔽的房頂上張望碟渺。 院中可真熱鬧,春花似錦、人聲如沸榔袋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至惭笑,卻和暖如春蚜厉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工蕊连, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人看彼。 一個月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子军洼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評論 2 349

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理扇住,服務(wù)發(fā)現(xiàn)票灰,斷路器,智...
    卡卡羅2017閱讀 134,633評論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法蚯舱,類相關(guān)的語法掩蛤,內(nèi)部類的語法枉昏,繼承相關(guān)的語法,異常的語法蜈亩,線程的語...
    子非魚_t_閱讀 31,598評論 18 399
  • 請以Conviva開發(fā)者社區(qū)作為主要參考源尊流。 集成之前,請前往官網(wǎng)下載對應(yīng)播放器類型的Demo,參考進(jìn)行集成。 一...
    繁天涯閱讀 446評論 0 0
  • 早晨還沒起來伴奥,就聽到一陣一陣的鞭炮聲,不知道是在慶祝什么。 原本打算出行的艇肴,也拖到了明天腔呜,具體原因不明。 今天早上...
    云栗閱讀 211評論 0 1
  • “激情”和“友誼”有所平衡再悼,就是永久和諧最有效的處方核畴。 現(xiàn)在,請拿起筆填下列的表格冲九,一起評估你們的感情在“激情指數(shù)...
    紅豆印跡閱讀 512評論 0 0