神奇的藍(lán)牙之即時(shí)通訊

時(shí)間好快,轉(zhuǎn)眼又一個(gè)月了叁丧,每天工作很忙啤誊,也沒(méi)有什么時(shí)間學(xué)習(xí)岳瞭,下一篇打算研究一下 framwork 的一些東西。

藍(lán)牙

Android 平臺(tái)包含藍(lán)牙網(wǎng)絡(luò)堆棧支持蚊锹,憑借此項(xiàng)支持瞳筏,設(shè)備能以無(wú)線方式與其他藍(lán)牙設(shè)備交換數(shù)據(jù)。應(yīng)用框架提供了通過(guò) Android Bluetooth API 訪問(wèn)藍(lán)牙功能的途徑牡昆。 這些 API 允許應(yīng)用以無(wú)線方式連接到其他藍(lán)牙設(shè)備姚炕,從而實(shí)現(xiàn)點(diǎn)到點(diǎn)和多點(diǎn)無(wú)線功能。

傳統(tǒng)藍(lán)牙

使用藍(lán)牙進(jìn)行通信的四項(xiàng)主要任務(wù):

  • 設(shè)置藍(lán)牙
  • 查找局部區(qū)域內(nèi)的配對(duì)設(shè)備或可用設(shè)備
  • 連接設(shè)備
  • 在設(shè)備之間傳輸數(shù)據(jù)

1丢烘、聲明權(quán)限

<manifest ... >
  <uses-permission android:name="android.permission.BLUETOOTH" />
  ...
</manifest>

2柱宦、設(shè)置藍(lán)牙

  • a、獲取 BluetoothAdapter
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
    // Device does not support Bluetooth
}
  • b播瞳、啟用藍(lán)牙
if (!mBluetoothAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}

您的應(yīng)用還可以選擇偵聽(tīng) ACTION_STATE_CHANGED 廣播 Intent掸刊,每當(dāng)藍(lán)牙狀態(tài)發(fā)生變化時(shí),系統(tǒng)都會(huì)廣播此 Intent赢乓。 此廣播包含額外字段

  • EXTRA_STATE : 新的藍(lán)牙狀態(tài)
  • EXTRA_PREVIOUS_STATE : 舊的藍(lán)牙狀態(tài)

這些額外字段可能的值包括 :

  • STATE_TURNING_ON
  • STATE_ON
  • STATE_TURNING_OFF
  • STATE_OFF

偵聽(tīng)此廣播適用于檢測(cè)在您的應(yīng)用運(yùn)行期間對(duì)藍(lán)牙狀態(tài)所做的更改忧侧。

3、查找設(shè)備

設(shè)備發(fā)現(xiàn)是一個(gè)掃描過(guò)程牌芋,它會(huì)搜索局部區(qū)域內(nèi)已啟用藍(lán)牙功能的設(shè)備蚓炬,然后請(qǐng)求一些關(guān)于各臺(tái)設(shè)備的信息。

但局部區(qū)域內(nèi)的藍(lán)牙設(shè)備僅在其當(dāng)前已啟用可檢測(cè)性時(shí)才會(huì)響應(yīng)發(fā)現(xiàn)請(qǐng)求姜贡。

利用此信息试吁,執(zhí)行發(fā)現(xiàn)的設(shè)備可以選擇發(fā)起到被發(fā)現(xiàn)設(shè)備的連接。

請(qǐng)記住楼咳,被配對(duì)與被連接之間存在差別熄捍。被配對(duì)意味著兩臺(tái)設(shè)備知曉彼此的存在,具有可用于身份驗(yàn)證的共享鏈路密鑰母怜,并且能夠與彼此建立加密連接余耽。 被連接意味著設(shè)備當(dāng)前共享一個(gè) RFCOMM 通道,并且能夠向彼此傳輸數(shù)據(jù)苹熏。 當(dāng)前的 Android Bluetooth API 要求對(duì)設(shè)備進(jìn)行配對(duì)碟贾,然后才能建立 RFCOMM 連接。

  • a轨域、查詢(xún)配對(duì)的設(shè)備
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
    // Loop through paired devices
    for (BluetoothDevice device : pairedDevices) {
        // Add the name and address to an array adapter to show in a ListView
        mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
    }
}
  • b袱耽、發(fā)現(xiàn)設(shè)備

要開(kāi)始發(fā)現(xiàn)設(shè)備,只需調(diào)用 startDiscovery()干发。該進(jìn)程為異步進(jìn)程朱巨,并且該方法會(huì)立即返回一個(gè)布爾值,指示是否已成功啟動(dòng)發(fā)現(xiàn)操作枉长。

針對(duì) ACTION_FOUND Intent 注冊(cè)一個(gè) BroadcastReceiver冀续,以便接收每臺(tái)發(fā)現(xiàn)的設(shè)備的相關(guān)信息琼讽。 針對(duì)每臺(tái)設(shè)備,系統(tǒng)將會(huì)廣播 ACTION_FOUND Intent洪唐。此 Intent 將攜帶額外字段

  • EXTRA_DEVICE // 包含 BluetoothDevice
  • EXTRA_CLASS // 包含 BluetoothClass
// Create a BroadcastReceiver for ACTION_FOUND
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        // When discovery finds a device
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            // Get the BluetoothDevice object from the Intent
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            // Add the name and address to an array adapter to show in a ListView
            mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
        }
    }
};
// Register the BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
  • c钻蹬、啟用可檢測(cè)性

如果您希望將本地設(shè)備設(shè)為可被其他設(shè)備檢測(cè)到,請(qǐng)使用

ACTION_REQUEST_DISCOVERABLE

操作 Intent 凭需,您可以通過(guò)添加 :

EXTRA_DISCOVERABLE_DURATION 

Intent Extra 來(lái)定義不同的持續(xù)時(shí)間问欠。 應(yīng)用可以設(shè)置的最大持續(xù)時(shí)間為 3600 秒,值為 0 則表示設(shè)備始終可檢測(cè)到功炮。 任何小于 0 或大于 3600 的值都會(huì)自動(dòng)設(shè)為 120 秒溅潜。 例如,以下片段會(huì)將持續(xù)時(shí)間設(shè)為 300 秒:

Intent discoverableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);

如果您希望在可檢測(cè)到模式發(fā)生變化時(shí)收到通知薪伏,您可以針對(duì)

ACTION_SCAN_MODE_CHANGED Intent 

注冊(cè) BroadcastReceiver滚澜。 它將包含額外字段

  • EXTRA_SCAN_MODE
  • EXTRA_PREVIOUS_SCAN_MODE

二者分別告知您新的和舊的掃描模式。 每個(gè)字段可能的值包括:

  • SCAN_MODE_CONNECTABLE_DISCOVERABLE :可檢測(cè)到模式
  • SCAN_MODE_CONNECTABLE :未處于可檢測(cè)到模式但仍能接收連接
  • SCAN_MODE_NONE :未處于可檢測(cè)到模式并且無(wú)法接收連接

4嫁怀、連接設(shè)備

要在兩臺(tái)設(shè)備上的應(yīng)用之間創(chuàng)建連接设捐,必須同時(shí)實(shí)現(xiàn)服務(wù)器端和客戶(hù)端機(jī)制,因?yàn)槠渲幸慌_(tái)設(shè)備必須開(kāi)放服務(wù)器套接字塘淑,而另一臺(tái)設(shè)備必須發(fā)起連接(使用服務(wù)器設(shè)備的 MAC 地址發(fā)起連接)萝招。 當(dāng)服務(wù)器和客戶(hù)端在同一 RFCOMM 通道上分別擁有已連接的 BluetoothSocket 時(shí),二者將被視為彼此連接存捺。

藍(lán)牙套接字接口(與 TCP Socket 相似)槐沼。這是允許應(yīng)用通過(guò) InputStream 和 OutputStream 與其他藍(lán)牙設(shè)備交換數(shù)據(jù)的連接點(diǎn)。

  • a捌治、連接為服務(wù)器

以下是設(shè)置服務(wù)器套接字并接受連接的基本過(guò)程:

1岗钩、通過(guò)調(diào)用 listenUsingRfcommWithServiceRecord(String, UUID) 獲取 BluetoothServerSocket。

2肖油、通過(guò)調(diào)用 accept() 開(kāi)始偵聽(tīng)連接請(qǐng)求兼吓。

3、除非您想要接受更多連接森枪,否則請(qǐng)調(diào)用 close()视搏。

這將釋放服務(wù)器套接字及其所有資源,但不會(huì)關(guān)閉 accept() 所返回的已連接的 BluetoothSocket县袱。

accept() 調(diào)用不應(yīng)在主 Activity UI 線程中執(zhí)行浑娜,因?yàn)樗亲枞{(diào)用,并會(huì)阻止與應(yīng)用的任何其他交互式散。 在您的應(yīng)用所管理的新線程中使用 BluetoothServerSocket 或 BluetoothSocket 完成所有工作棚愤。

  • b、連接為客戶(hù)端

以下是基本過(guò)程:

1、使用 BluetoothDevice宛畦,通過(guò)調(diào)用 createRfcommSocketToServiceRecord(UUID) 獲取 BluetoothSocket。

2揍移、通過(guò)調(diào)用 connect() 發(fā)起連接次和。

系統(tǒng)將會(huì)在遠(yuǎn)程設(shè)備上執(zhí)行 SDP 查找,以便匹配 UUID那伐。 如果查找成功并且遠(yuǎn)程設(shè)備接受了該連接踏施,它將共享 RFCOMM 通道以便在連接期間使用,并且 connect() 將會(huì)返回罕邀。 此方法為阻塞調(diào)用畅形。

  • c、管理連接

在成功連接兩臺(tái)(或更多臺(tái))設(shè)備后诉探,每臺(tái)設(shè)備都會(huì)有一個(gè)已連接的 BluetoothSocket日熬。 這一點(diǎn)非常有趣,因?yàn)檫@表示您可以在設(shè)備之間共享數(shù)據(jù)肾胯。 利用 BluetoothSocket竖席,傳輸任意數(shù)據(jù)的一般過(guò)程非常簡(jiǎn)單:

獲取 InputStream 和 OutputStream,二者分別通過(guò)套接字以及 getInputStream() 和 getOutputStream() 來(lái)處理數(shù)據(jù)傳輸敬肚。

使用 read(byte[]) 和 write(byte[]) 讀取數(shù)據(jù)并寫(xiě)入到流式傳輸毕荐。

就這么簡(jiǎn)單。

5艳馒、使用配置文件

從 Android 3.0 開(kāi)始憎亚,Bluetooth API 便支持使用藍(lán)牙配置文件。 藍(lán)牙配置文件是適用于設(shè)備間藍(lán)牙通信的無(wú)線接口規(guī)范弄慰。

對(duì)于連接到無(wú)線耳機(jī)的手機(jī)第美,兩臺(tái)設(shè)備都必須支持 “免提配置文件”。

Android Bluetooth API 提供了以下藍(lán)牙配置文件的實(shí)現(xiàn):

  • 耳機(jī)

耳機(jī)配置文件提供了藍(lán)牙耳機(jī)支持曹动,以便與手機(jī)配合使用斋日。

  • A2DP

高級(jí)音頻分發(fā)配置文件 (A2DP) 定義了高質(zhì)量音頻如何通過(guò)藍(lán)牙連接和流式傳輸,從一個(gè)設(shè)備傳輸?shù)搅硪粋€(gè)設(shè)備墓陈。 Android 提供了 BluetoothA2dp 類(lèi)恶守,它是用于通過(guò) IPC 來(lái)控制藍(lán)牙 A2DP 服務(wù)的代理。

  • 健康設(shè)備

Android 4.0(API 級(jí)別 14)引入了對(duì)藍(lán)牙健康設(shè)備配置文件 (HDP) 的支持贡必。 這允許您創(chuàng)建應(yīng)用兔港,使用藍(lán)牙與支持藍(lán)牙功能的健康設(shè)備進(jìn)行通信,例如心率監(jiān)測(cè)儀仔拟、血糖儀衫樊、溫度計(jì)、臺(tái)秤等等。

以下是使用配置文件的基本步驟:

1科侈、獲取默認(rèn)適配器(請(qǐng)參閱設(shè)置藍(lán)牙)载佳。

2、使用 getProfileProxy() 建立到配置文件所關(guān)聯(lián)的配置文件代理對(duì)象的連接臀栈。在以下示例中蔫慧,配置文件代理對(duì)象是一個(gè) BluetoothHeadset 的實(shí)例。

3权薯、設(shè)置 BluetoothProfile.ServiceListener姑躲。此偵聽(tīng)程序會(huì)在 BluetoothProfile IPC 客戶(hù)端連接到服務(wù)或斷開(kāi)服務(wù)連接時(shí)向其發(fā)送通知。

4盟蚣、在 onServiceConnected() 中黍析,獲取配置文件代理對(duì)象的句柄。

5屎开、獲得配置文件代理對(duì)象后阐枣,可以立即將其用于監(jiān)視連接狀態(tài)和執(zhí)行其他與該配置文件相關(guān)的操作。

以下代碼片段顯示了如何連接到 BluetoothHeadset 代理對(duì)象牍戚,以便能夠控制耳機(jī)配置文件:

BluetoothHeadset mBluetoothHeadset;

// Get the default adapter
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

// Establish connection to the proxy.
mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET);

private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
    public void onServiceConnected(int profile, BluetoothProfile proxy) {
        if (profile == BluetoothProfile.HEADSET) {
            mBluetoothHeadset = (BluetoothHeadset) proxy;
        }
    }
    public void onServiceDisconnected(int profile) {
        if (profile == BluetoothProfile.HEADSET) {
            mBluetoothHeadset = null;
        }
    }
};

// ... call functions on mBluetoothHeadset

// Close proxy connection after use.
mBluetoothAdapter.closeProfileProxy(mBluetoothHeadset);

供應(yīng)商特定的 AT 命令

從 Android 3.0 開(kāi)始侮繁,應(yīng)用可以注冊(cè)接收耳機(jī)所發(fā)送的預(yù)定義的供應(yīng)商特定 AT 命令的系統(tǒng)廣播(例如 Plantronics +XEVENT 命令)。

例如如孝,應(yīng)用可以接收指示所連接設(shè)備的電池電量的廣播宪哩,并根據(jù)需要通知用戶(hù)或采取其他操作。 為

ACTION_VENDOR_SPECIFIC_HEADSET_EVENT intent

創(chuàng)建廣播接收器第晰,以處理耳機(jī)的供應(yīng)商特定 AT 命令锁孟。

下面是獲取藍(lán)牙耳機(jī)電池電量:

 /**
     * Handle {@link BluetoothHeadset#ACTION_VENDOR_SPECIFIC_HEADSET_EVENT} intent
     * @param intent must be {@link BluetoothHeadset#ACTION_VENDOR_SPECIFIC_HEADSET_EVENT} intent
     */
    @VisibleForTesting
    void onVendorSpecificHeadsetEvent(Intent intent) {
        BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
        if (device == null) {
            Log.e(TAG, "onVendorSpecificHeadsetEvent() remote device is null");
            return;
        }
        String cmd =
                intent.getStringExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD);
        if (cmd == null) {
            Log.e(TAG, "onVendorSpecificHeadsetEvent() command is null");
            return;
        }
        int cmdType = intent.getIntExtra(
                BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE, -1);
        // Only process set command
        if (cmdType != BluetoothHeadset.AT_CMD_TYPE_SET) {
            debugLog("onVendorSpecificHeadsetEvent() only SET command is processed");
            return;
        }
        Object[] args = (Object[]) intent.getExtras().get(
                BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS);
        if (args == null) {
            Log.e(TAG, "onVendorSpecificHeadsetEvent() arguments are null");
            return;
        }
        int batteryPercent = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
        switch (cmd) {
            case BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_XEVENT:
                batteryPercent = getBatteryLevelFromXEventVsc(args);
                break;
            case BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV:
                batteryPercent = getBatteryLevelFromAppleBatteryVsc(args);
                break;
        }
        if (batteryPercent != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
            updateBatteryLevel(device, batteryPercent);
            infoLog("Updated device " + device + " battery level to "
                    + String.valueOf(batteryPercent) + "%");
        }
    }

健康設(shè)備配置文件

  • 源設(shè)備:在 HDP 中定義的角色。源設(shè)備是將醫(yī)療數(shù)據(jù)傳輸?shù)?Android 手機(jī)或平板電腦等智能設(shè)備的健康設(shè)備(體重秤茁瘦、血糖儀品抽、溫度計(jì)等)。

  • 匯集設(shè)備:在 HDP 中定義的角色甜熔。在 HDP 中圆恤,匯集設(shè)備是接收醫(yī)療數(shù)據(jù)的智能設(shè)備。 在 Android HDP 應(yīng)用中腔稀,匯集設(shè)備表示為 BluetoothHealthAppConfiguration 對(duì)象盆昙。

  • 注冊(cè):指的是注冊(cè)特定健康設(shè)備的匯集設(shè)備。

  • 連接:指的是開(kāi)放健康設(shè)備與 Android 手機(jī)或平板電腦等智能設(shè)備之間的通道焊虏。

創(chuàng)建 HDP 應(yīng)用

以下是創(chuàng)建 Android HDP 應(yīng)用所涉及的基本步驟:

1淡喜、獲取 BluetoothHealth 代理對(duì)象的引用。

2诵闭、與常規(guī)耳機(jī)和 A2DP 配置文件設(shè)備相似炼团,您必須使用 BluetoothProfile.ServiceListener 和 HEALTH 配置文件類(lèi)型來(lái)調(diào)用 getProfileProxy()澎嚣,以便與配置文件代理對(duì)象建立連接。

3瘟芝、創(chuàng)建 BluetoothHealthCallback 并注冊(cè)充當(dāng)健康匯集設(shè)備的應(yīng)用配置 (BluetoothHealthAppConfiguration)易桃。

4、建立到健康設(shè)備的連接模狭。一些設(shè)備將會(huì)發(fā)起該連接颈抚。 對(duì)于這類(lèi)設(shè)備,無(wú)需執(zhí)行該步驟嚼鹉。
成功連接到健康設(shè)備后,使用文件描述符對(duì)健康設(shè)備執(zhí)行讀/寫(xiě)操作驱富。

5锚赤、接收的數(shù)據(jù)需要使用實(shí)現(xiàn)了 IEEE 11073-xxxxx 規(guī)范的健康管理器進(jìn)行解釋。

完成后褐鸥,關(guān)閉健康通道并取消注冊(cè)該應(yīng)用线脚。該通道在長(zhǎng)期閑置時(shí)也會(huì)關(guān)閉。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末叫榕,一起剝皮案震驚了整個(gè)濱河市浑侥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌晰绎,老刑警劉巖寓落,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異荞下,居然都是意外死亡伶选,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)尖昏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)仰税,“玉大人,你說(shuō)我怎么就攤上這事抽诉≡纱兀” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵迹淌,是天一觀的道長(zhǎng)河绽。 經(jīng)常有香客問(wèn)我,道長(zhǎng)巍沙,這世上最難降的妖魔是什么葵姥? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮句携,結(jié)果婚禮上榔幸,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好削咆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布牍疏。 她就那樣靜靜地躺著,像睡著了一般拨齐。 火紅的嫁衣襯著肌膚如雪鳞陨。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,708評(píng)論 1 305
  • 那天瞻惋,我揣著相機(jī)與錄音厦滤,去河邊找鬼。 笑死歼狼,一個(gè)胖子當(dāng)著我的面吹牛掏导,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播羽峰,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼趟咆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了梅屉?” 一聲冷哼從身側(cè)響起值纱,我...
    開(kāi)封第一講書(shū)人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎坯汤,沒(méi)想到半個(gè)月后虐唠,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡玫霎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年凿滤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片庶近。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡翁脆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鼻种,到底是詐尸還是另有隱情反番,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布叉钥,位于F島的核電站罢缸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏投队。R本人自食惡果不足惜枫疆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望敷鸦。 院中可真熱鬧息楔,春花似錦寝贡、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至愿险,卻和暖如春颇蜡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辆亏。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工风秤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人扮叨。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓唁情,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親甫匹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

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