Android讀書筆記(2)—— IPC機(jī)制

一、IPC與多線程

1、IPC簡介

線程:① CPU最小的調(diào)度單元 ② 一種有限的系統(tǒng)資源
進(jìn)程:一個執(zhí)行單元凿跳。一般指一個程序或一個應(yīng)用坑傅。一個進(jìn)程可以包含多個線程僵驰。
IPC:進(jìn)程間通信。

多線程的情況
1)因為某些原因自身需要采用多線程模式來實現(xiàn)唁毒。比如:某些模塊需要運(yùn)行在單獨(dú)進(jìn)程蒜茴;為了加大一個應(yīng)用可以使用的內(nèi)存。
2)需要從其他應(yīng)用獲取數(shù)據(jù)浆西。

2粉私、Android中的多進(jìn)程模式

2.1、開啟多進(jìn)程模式

在Android中一個應(yīng)用開啟多進(jìn)程唯一辦法:給四大組件在AndroidMenifest.xml中指定android:process屬性近零。

<service
    android:name=".MyService"
    android:process=":remote" />
<service
    android:name=".SecondService"
    android:process="com.example.xiang.myapplication.remote" />

默認(rèn)進(jìn)程名是包名诺核。“:remote”是一種省略寫法久信,完整名為“com.example.xiang.myapplication:remote”進(jìn)程名窖杀,以“:”開頭,屬于當(dāng)前應(yīng)用的私有進(jìn)程裙士,其他應(yīng)用的組件不可以和它跑在同一個進(jìn)程中入客。

2.2、多進(jìn)程模式的運(yùn)行機(jī)制

Android系統(tǒng)為每一個進(jìn)程分配了一個獨(dú)立的虛擬機(jī)腿椎,不同的虛擬機(jī)在內(nèi)存分配上有不同的地址空間桌硫。將導(dǎo)致存在如下問題:
1)靜態(tài)成員和單例完全失效
2)線程同步機(jī)制完全失效
3)SharedPreferences的可靠性下降
4)Application會多次創(chuàng)建
不同的進(jìn)程擁有獨(dú)立的虛擬機(jī)、Application和內(nèi)存空間酥诽,導(dǎo)致通過內(nèi)存來共享數(shù)據(jù)鞍泉,都會共享失敗。

Android的IPC方式
1)Intent
2)文件共享方式
3)Binder(AIDL和Messenger)
4)ContentProvider
5)Socket

二肮帐、IPC的基礎(chǔ)概念

為什么要序列化咖驮?
1)永久性保存對象的字節(jié)序列到本地文件中
2)通過序列化在網(wǎng)絡(luò)中傳遞對象
3)通過序列化在進(jìn)程間傳遞對象

1、Serializable接口

Serializable是Java提供的一個序列化接口训枢,是一個空接口托修,為對象提供標(biāo)準(zhǔn)的序列化和反序列化操作。

private static final long serialVersionUID = 8154678445665565611L;

serialVersionUID是用來輔助序列化和序列化的過程恒界,原則上序列化后的數(shù)據(jù)中的serialVersionUID只有和當(dāng)前類的serialVersionUID相同才能夠正常地被反序列化睦刃。一般我們應(yīng)該手動指定serialVersionUID的值,比如1L(或者根據(jù)類結(jié)構(gòu)生成hash值)十酣。若不指定涩拙,反序列化時當(dāng)前類有所改變(比如增加或者刪除了成員變量)际长,那么系統(tǒng)會重新計算當(dāng)前類的hash值并賦給serialVersionUID,導(dǎo)致serialVersionUID不一致兴泥,于是反序列化失敗工育,程序就會crash。

靜態(tài)成員變量屬于類不屬于對象搓彻,不會參加序列化
用transient標(biāo)記的成員變量不會參與序列化

2如绸、Parcelable接口

public class User implements Parcelable {
    private int userId;
    private String userName;
    private Book book;

    protected User(Parcel in) {
        userId = in.readInt();
        userName = in.readString();
        //book是一個可序列化對象,需要傳遞當(dāng)前線程的上下文類加載器
        book = in.readParcelable(Thread.currentThread().getContextClassLoader());
    }

    /**
     * 實現(xiàn)反序列化
     */
    public static final Creator<User> CREATOR = new Creator<User>() {
        @Override
        public User createFromParcel(Parcel in) {
            return new User(in);
        }

        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };

    /**
     * 幾乎所有情況都返回0
     * @return
     */
    @Override
    public int describeContents() {
        return 0;
    }

    /**
     * 實現(xiàn)序列化
     *
     * @param parcel
     * @param i
     */
    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeInt(userId);
        parcel.writeString(userName);
        parcel.writeParcelable(book, i);
    }
}

3旭贬、Binder

3.1怔接、AIDL接口的創(chuàng)建

Binder就是Android中實現(xiàn)了IBinder接口的一個類,是跨進(jìn)程通信的媒介稀轨。在Android開發(fā)中扼脐,Binder主要用在Service中,包括Messenger(底層其實是AIDL)和AIDL靶端。

//Book.java
package com.example.xiang.myapplication;

import android.os.Parcel;
import android.os.Parcelable;

public class Book implements Parcelable {
    private int bookId;
    private String bookName;

    public Book(int bookId, String bookName) {
        this.bookId = bookId;
        this.bookName = bookName;
    }

    /**
     * 幾乎所有情況都返回0
     * @return
     */
    @Override
    public int describeContents() {
        return 0;
    }

    /**
     * 實現(xiàn)序列化
     * @param parcel
     * @param i
     */
    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeInt(bookId);
        parcel.writeString(bookName);
    }

    /**
     * 實現(xiàn)反序列化
     */
    public static final Creator<Book> CREATOR = new Creator<Book>() {
        @Override
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

        @Override
        public Book[] newArray(int size) {
            return new Book[size];
        }
    };

    public Book(Parcel in) {
        bookId = in.readInt();
        bookName = in.readString();
    }
}

//Book.aidl
package com.example.xiang.myapplication;

parcelable Book;

// IBookManager.aidl
package com.example.xiang.myapplication;

import com.example.xiang.myapplication.Book;//必須導(dǎo)入谎势,否則報錯

interface IBookManager {
    List<Book> getBookList();
    void addBook(in Book book);
}

Book.aidl是Book類在AIDL中的聲明。IBookManager.aidl是定義的一個接口杨名,雖然Book類和IBookManager在同一個包中,但是還是要顯示導(dǎo)入Book類猖毫。目錄結(jié)構(gòu)如下:

AIDL目錄結(jié)構(gòu)

(新建Book.aidl時候台谍,直接填Book為名字時候會報錯,只有先創(chuàng)建完之后再RENAME才不會報錯)

3.2吁断、Binder類分析

系統(tǒng)為IBookManager.aidl自動生成的Binder類

package com.example.xiang.myapplication;

public interface IBookManager extends android.os.IInterface {
   
    public static abstract class Stub extends Binder implements IBookManager {
        //Binder的唯一標(biāo)識
        private static final String DESCRIPTOR = "com.example.xiang.myapplication.IBookManager";
       
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        public static IBookManager asInterface(IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof IBookManager))) {
                return ((IBookManager) iin);
            }
            return new IBookManager.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        @Override
        public boolean onTransact(int code, Parcel data,
        Parcel reply, int flags) throws RemoteException {
             switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                case TRANSACTION_getBookList: {
                    data.enforceInterface(DESCRIPTOR);
                    List<Book> _result = this.getBookList();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
                case TRANSACTION_addBook: {
                    data.enforceInterface(DESCRIPTOR);
                    Book _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = Book.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.addBook(_arg0);
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements IBookManager {
            private IBinder mRemote;

            Proxy(IBinder remote) {
                mRemote = remote;
            }

            @Override
            public IBinder asBinder() {
                return mRemote;
            }

            public String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }

            @Override
            public List<Book> getBookList() throws RemoteException {
                Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();
                List<Book> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    //_data寫入?yún)?shù)
                    //發(fā)起遠(yuǎn)程調(diào)用趁蕊,當(dāng)前線程掛起
                    mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(Book.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public void addBook(Book book) throws RemoteException {
                Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    if ((book != null)) {
                        _data.writeInt(1);
                        book.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

        static final int TRANSACTION_getBookList = (IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_addBook = (IBinder.FIRST_CALL_TRANSACTION + 1);
    }

    public List<Book> getBookList() throws RemoteException;

    public void addBook(Book book) throws RemoteException;
}

  • asInterface //將服務(wù)端的Binder對象轉(zhuǎn)換為客戶端所需的AIDL接口類型的對象,如果C/S位于同一進(jìn)程仔役,此方法返回就是服務(wù)端的Stub對象本身掷伙,否則返回的就是系統(tǒng)封裝后的Stub.proxy對象
  • asBinder //返回當(dāng)前的Binder對象
  • onTransact//運(yùn)行在服務(wù)端
  • Proxy#getBookList//運(yùn)行在客戶端,內(nèi)部實現(xiàn)過程如下:首先創(chuàng)建該方法所需要的輸入型對象Parcel對象_data又兵,輸出型Parcel對象_reply和返回值對象List任柜。然后把該方法的參數(shù)信息寫入_data( 如果有參數(shù));接著調(diào)用transact方法發(fā)起RPC( 遠(yuǎn)程過程調(diào)用)沛厨,同時當(dāng)前線程掛起(因此不能再UI線程中發(fā)起遠(yuǎn)程請求)宙地;然后服務(wù)端的onTransact方法會被調(diào)用(服務(wù)端的Binder方法運(yùn)行在線程池,所以需要采用同步方式實現(xiàn))逆皮,直到RPC過程返回后宅粥,當(dāng)前線程繼續(xù)執(zhí)行,并從_reply中取出RPC過程的返回結(jié)果电谣,最后返回_reply中的數(shù)據(jù)秽梅。
Binder工作機(jī)制

AIDL的本質(zhì):系統(tǒng)提供的一個快速實現(xiàn)Binder的工具而已抹蚀。

3.3、遠(yuǎn)程服務(wù)端Service的實現(xiàn)
public class BookManagerService extends Service {
    private static final String TAG = "BookManagerService";
    //CopyOnWriteArrayList支持并發(fā)讀/寫
    private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
    private Binder mBinder = new IBookManager.Stub() {
        @Override
        public List<Book> getBookList() throws RemoteException {
            return mBookList;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            mBookList.add(book);
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        mBookList.add(new Book(1, "Android開發(fā)藝術(shù)探索"));
        mBookList.add(new Book(2, "Android進(jìn)階之光"));
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}

//注冊Service
<service
    android:name="com.example.service.MessengerService"
    android:process=":remote" />

AIDL方法(getBookList和addBook)是運(yùn)行在Binder線程池中的企垦,所以需要處理線程同步环壤,這里采用CopyOnWriteArrayList來進(jìn)行自動的線程同步。

3.4竹观、客戶端的實現(xiàn)
public class BookManagerActivity extends Activity {
    private static final String TAG = "BookManagerActivity";
    
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            IBookManager bookManager = IBookManager.Stub.asInterface(service);
            try {
                List<Book> list = bookManager.getBookList();
                Log.d(TAG, "查詢圖書列表:" + list.toString());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent intent = new Intent(this, BookManagerService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        unbindService(connection);
        super.onDestroy();
    }
}

服務(wù)端的方法可能需要很久才能執(zhí)行完畢镐捧,上面這樣寫的目的是為了更好的了解AIDL的實現(xiàn)步驟。
對象是不能跨進(jìn)程直接傳輸?shù)某粼觯瑢ο罂邕M(jìn)程傳輸?shù)谋举|(zhì)是反序列化過程懂酱,這也是為什么AIDL中定義的對象必須實現(xiàn)Parcelable接口。

4誊抛、Binder的兩個重要方法

linkToDeath(DeathRecipient recipient, int flags) //設(shè)置Binder的死亡代理列牺。當(dāng)Binder死亡時,系統(tǒng)會回調(diào)DeathRecipient的binderDied()方法拗窃,所以需要在此方法中移除之前綁定的binder代理(調(diào)用unlinkToDeath)并重新綁定遠(yuǎn)程服務(wù)
unlinkToDeath(DeathRecipient recipient, int flags) //移除死亡代理
isBinderAlive() //判斷Binder是否死亡

DeathRecipient是IBinder的一個內(nèi)部接口瞎领,里面只有一個方法binderDied()

5、補(bǔ)充說明

AIDL文件支持的數(shù)據(jù)類型
1)基本數(shù)據(jù)類型(int随夸、long九默、char、boolean等)
2)String和CharSequence
3)List:只支持ArrayList宾毒,里面的每個元素必須被AIDL所支持
4)Map:只支持HashMap驼修,里面的每個元素必須被AIDL所支持,包括key和value
5)Parcelable:所有實現(xiàn)了Parcelable接口的對象
6)AIDL:所有AIDL接口本身也可以在AIDL文件中使用

  • 自定義的Parcelable對象(如上例中的Book類)诈铛,必須新建一個和它同名的AIDL文件(Book.aidl)乙各,并添加相應(yīng)的內(nèi)容。
  • 自定義Parcelable對象和AIDL對象必須要顯式import進(jìn)來幢竹。
  • 除了基本數(shù)據(jù)類型的其他類型參數(shù)耳峦,都需要標(biāo)上方向:in、out或者inout焕毫。
  • AIDL接口中只支持方法蹲坷,不支持聲明靜態(tài)常量。
  • 建議把所有和AIDL相關(guān)的類和文件全部放在同一個包中咬荷,好處是冠句,若客戶端在另一應(yīng)用(模塊),復(fù)制整個包即可幸乒。
  • AIDL的包結(jié)構(gòu)在服務(wù)端和客戶端必須保持一致懦底,否則運(yùn)行出錯。

DeathRecipient是IBinder的一個內(nèi)部接口,里面只有一個方法binderDied()

三聚唐、Android中的IPC方式

1丐重、使用Intent

啟動另一個進(jìn)程的Activity、Service和Receiver的時候杆查,在Bundle(實現(xiàn)了Parcelable接口)中附加信息扮惦,并通過Intent進(jìn)行傳遞

2、使用文件共享

序列化一個對象到文件系統(tǒng)中的同時從另一個進(jìn)程中恢復(fù)這個對象亲桦,適合對數(shù)據(jù)同步要求不高的進(jìn)程之間進(jìn)行通信崖蜜,并且要妥善處理并發(fā)讀寫問題。

SharedPreferences底層實現(xiàn)采用XML文件來存儲鍵值對客峭。系統(tǒng)對它的讀/寫有一定的緩存策略豫领,即在內(nèi)存中會有一份 SharedPreferences文件的緩存,因此在多進(jìn)程模式下舔琅,系統(tǒng)對它的讀/寫變得不可靠等恐,面對高并發(fā)讀/寫時SharedPreferences 有很大幾率丟失數(shù)據(jù),因此不建議在IPC中使用SharedPreferences备蚓。

3课蔬、使用Messenger(信使)

一種輕量級的IPC方案,底層實現(xiàn)是AIDL郊尝。服務(wù)端以串行的方式處理客戶端發(fā)來的Message對象二跋。
舉個例子

//MessengerService.java
//服務(wù)端代碼
public class MessengerService extends Service {
    private static final String TAG = "MessengerService";

    private static class MessengerHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case Constants.MSG_FROM_CLIENT:
                    //收到客戶端的消息
                    Log.d(TAG, "收到客戶端發(fā)來的信息:" + msg.getData().getString("msg"));
                    Messenger client = msg.replyTo;
                    Message replyMessage = Message.obtain(null, Constants.MSG_FROM_SERVER);
                    Bundle bundle = new Bundle();
                    bundle.putString("reply","你的消息我已經(jīng)收到,稍后回復(fù)你流昏。");
                    try {
                        client.send(replyMessage);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
            }
        }
    }

    private final Messenger mMessenger = new Messenger(new MessengerHandler());

    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }
}


//注冊Service
<service
    android:name="com.example.service.MessengerService"
    android:process=":remote" />

//MainActivity.java
//客戶端實現(xiàn)
public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";
    private Messenger mService;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            mService = new Messenger(iBinder);
            Message msg = Message.obtain(null, Constants.MSG_FROM_CLIENT);
            Bundle data = new Bundle();
            data.putString("msg", "hello, this is client");
            msg.setData(data);
            //注意這一句
            msg.replyTo = mGetReplyMessenger;
            try {
                mService.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
        }
    };
    private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler());

    private class MessengerHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case Constants.MSG_FROM_SERVER:
                    Log.d(TAG, "收到服務(wù)端的回復(fù)" + msg.getData().getString("reply"));
                    break;
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final Intent intent = new Intent(this, MessengerService.class);
        findViewById(R.id.btn_bind).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                bindService(intent, connection, Context.BIND_AUTO_CREATE);
            }
        });
    }

    @Override
    protected void onDestroy() {
        unbindService(connection);
        super.onDestroy();
    }
}

Messenger中傳遞的數(shù)據(jù)必須將數(shù)據(jù)放入Message同欠,Message和Messenger都實現(xiàn)了Parcelable接口(放入Message中的對象也要實現(xiàn)Parcelable接口才能傳遞)。工作原理如圖所示:
[站外圖片上傳中...(image-7382db-1516020836113)]

Messenger常用方法

Messenger(Handler target)
Messenger(IBinder target)
send(Message message)
getBinder() IBinder

Message相關(guān)屬性

replyTo //返回一個可以答復(fù)的Messenger

4横缔、使用AIDL

見上面的例子

5、使用ContentProvider

6衫哥、使用Socket

四茎刚、Binder連接池

五、IPC總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末撤逢,一起剝皮案震驚了整個濱河市膛锭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蚊荣,老刑警劉巖初狰,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異互例,居然都是意外死亡奢入,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門媳叨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來腥光,“玉大人关顷,你說我怎么就攤上這事∥涓#” “怎么了议双?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長捉片。 經(jīng)常有香客問我平痰,道長,這世上最難降的妖魔是什么伍纫? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任宗雇,我火速辦了婚禮,結(jié)果婚禮上翻斟,老公的妹妹穿的比我還像新娘逾礁。我一直安慰自己,他們只是感情好访惜,可當(dāng)我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布嘹履。 她就那樣靜靜地躺著,像睡著了一般债热。 火紅的嫁衣襯著肌膚如雪砾嫉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天窒篱,我揣著相機(jī)與錄音焕刮,去河邊找鬼。 笑死墙杯,一個胖子當(dāng)著我的面吹牛配并,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播高镐,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼溉旋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了嫉髓?” 一聲冷哼從身側(cè)響起观腊,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎算行,沒想到半個月后梧油,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡州邢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年儡陨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡迄委,死狀恐怖褐筛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情叙身,我是刑警寧澤渔扎,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站信轿,受9級特大地震影響晃痴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜财忽,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一倘核、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧即彪,春花似錦紧唱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至深胳,卻和暖如春绰疤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背舞终。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工轻庆, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人敛劝。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓余爆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親夸盟。 傳聞我的和親對象是個殘疾皇子龙屉,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,675評論 2 359