android跨進(jìn)程通信AIDL使用

AIDL(Android Interface Definition Language捏卓,Android接口定義語(yǔ)言):如果在一個(gè)進(jìn)程中要調(diào)用另一個(gè)進(jìn)程中對(duì)象的方法铅檩,可使用AIDL生成可序列化的參數(shù)实胸,AIDL會(huì)生成一個(gè)服務(wù)端對(duì)象的代理類,通過(guò)它客戶端實(shí)現(xiàn)間接調(diào)用服務(wù)端對(duì)象的方法。

AIDL的本質(zhì)是系統(tǒng)提供了一套可快速實(shí)現(xiàn)Binder的工具晌缘。

關(guān)鍵類和方法:

  • AIDL接口:繼承IInterface饰豺。
  • Stub類:Binder的實(shí)現(xiàn)類亿鲜,服務(wù)端通過(guò)這個(gè)類來(lái)提供服務(wù)。
  • Proxy類:服務(wù)器的本地代理冤吨,客戶端通過(guò)這個(gè)類調(diào)用服務(wù)器的方法蒿柳。
  • asInterface():客戶端調(diào)用,將服務(wù)端的返回的Binder對(duì)象漩蟆,轉(zhuǎn)換成客戶端所需要的AIDL接口類型對(duì)象垒探。
    返回對(duì)象:
    若客戶端和服務(wù)端位于同一進(jìn)程,則直接返回Stub對(duì)象本身怠李;
    若客戶端和服務(wù)端位于不同一進(jìn)程圾叼,返回的是系統(tǒng)封裝后的Stub.proxy對(duì)象。
  • asBinder():根據(jù)當(dāng)前調(diào)用情況返回代理Proxy的Binder對(duì)象捺癞。
  • onTransact():運(yùn)行服務(wù)端的Binder線程池中夷蚊,當(dāng)客戶端發(fā)起跨進(jìn)程請(qǐng)求時(shí),遠(yuǎn)程請(qǐng)求會(huì)通過(guò)系統(tǒng)底層封裝后交由此方法來(lái)處理髓介。
  • transact():運(yùn)行在客戶端惕鼓,當(dāng)客戶端發(fā)起遠(yuǎn)程請(qǐng)求的同時(shí)將當(dāng)前線程掛起。之后調(diào)用服務(wù)端的onTransact()直到遠(yuǎn)程請(qǐng)求返回版保,當(dāng)前線程才繼續(xù)執(zhí)行呜笑。


如何使用AIDL

1.先建立兩個(gè)android項(xiàng)目
創(chuàng)建一個(gè)BinderA項(xiàng)目和一個(gè)BinderB工程,BinderA項(xiàng)目調(diào)用BinderB中提供的登錄接口彻犁,在BinderB中點(diǎn)擊登錄后叫胁,登錄之后不管是否成功,BinderB都會(huì)調(diào)用BinderA中登錄返回接口汞幢,這樣就實(shí)現(xiàn)了一個(gè)雙向的通信驼鹅。



2、創(chuàng)建一個(gè)包名用來(lái)存放aidl文件
創(chuàng)建一個(gè)包名用來(lái)存放aidl文件,比如com.migill.binder森篷,在里面新建ILoginInterface.aidl文件输钩,如果需要訪問(wèn)自定義對(duì)象,還需要建立對(duì)象的aidl文件仲智,這里我們由于使用了自定義對(duì)象LoginUser买乃,所以,還需要?jiǎng)?chuàng)建LoginUser.aidl和LoginUser.java钓辆。注意剪验,這三個(gè)文件肴焊,需要都放在com.migill.binder包里。而且ILoginInterface.aidl功戚,LoginUser.aidl娶眷,LoginUser.java這三個(gè)文件在BinderA與BinderB項(xiàng)目中是一樣的。下面描述如何寫(xiě)這三個(gè)文件啸臀。
客戶端中的aidl文件與服務(wù)端中的aidl文件的包名要一樣届宠,在創(chuàng)建客戶端AIDL文件的時(shí)候是不需要把服務(wù)端提供的接口都添加進(jìn)來(lái),只需要添加需要的接口就好了

// ILoginInterface.aidl
package com.migill.binder;
import com.migill.binder.LoginUser;
interface ILoginInterface {
    // 登錄
    void login();
    // 登錄返回
    void loginCallback(boolean loginStatus, inout LoginUser loginUser);
}

說(shuō)明:
aidl中支持的參數(shù)類型為:

  • 基本類型(ibyte乘粒,int豌注,long,float谓厘,double幌羞,boolean,char),String類型,CharSequence類型,List,Map竟稳。
  • 其他類型必須使用import導(dǎo)入属桦,即使它們可能在同一個(gè)包里,比如這里的LoginUser他爸,盡管它和ILoginInterface在同一個(gè)包中聂宾,但是還是需要顯示的import進(jìn)來(lái)。另外诊笤,接口中的參數(shù)除了aidl支持的類型系谐,其他類型必須標(biāo)識(shí)其方向:到底是輸入還是輸出抑或兩者兼之,用in讨跟,out或者inout來(lái)表示纪他,上面的代碼我們用inout標(biāo)記,其實(shí)用in就可以晾匠,因?yàn)樗禽斎胄蛥?shù)(我的理解是BinderB現(xiàn)在是客戶端茶袒,BinderA是服務(wù)端,BinderB中的數(shù)據(jù)流入BinderA中凉馆,所以是入型參數(shù))薪寓。

在gen下面可以看到,AS為我們自動(dòng)生成了一個(gè)代理類public static abstract class Stub extends android.os.Binder implements com.migill.binder.ILoginInterface可見(jiàn)這個(gè)Stub類就是一個(gè)普通的Binder澜共,只不過(guò)它實(shí)現(xiàn)了我們定義的aidl接口向叉。
它還有一個(gè)靜態(tài)方法public static com.migill.binder.ILoginInterface asInterface(android.os.IBinder obj)這個(gè)方法很有用,通過(guò)它嗦董,我們就可以在客戶端中得到MyService的實(shí)例母谎,進(jìn)而通過(guò)實(shí)例來(lái)調(diào)用其方法。

// LoginUser.aidl
package com.migill.binder;
parcelable LoginUser;
package com.migill.binder;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Locale;
public final class LoginUser implements Parcelable {
    public String userName;
    public String userPassWord;
    public LoginUser() {
    }
    protected LoginUser(Parcel in) {
        readFromParcel(in);
    }
    public void readFromParcel(Parcel in) {
        userName = in.readString();
        userPassWord = in.readString();
    }
    public static final Creator<LoginUser> CREATOR = new Creator<LoginUser>() {
        @Override
        public LoginUser createFromParcel(Parcel in) {
            return new LoginUser(in);
        }
        @Override
        public LoginUser[] newArray(int size) {
            return new LoginUser[size];
        }
    };
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getUserPassWord() {
        return userPassWord;
    }
    public void setUserPassWord(String userPassWord) {
        this.userPassWord = userPassWord;
    }
    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(userName);
        dest.writeString(userPassWord);
    }
    @Override
    public String toString() {
        return String.format(Locale.ENGLISH, "[ %s, %s ]", userName, userPassWord);
    }
}

3.BinderA項(xiàng)目
MyService.java中的loginCallback()中發(fā)送了一個(gè)廣播京革,廣播在LoginActivity中接收销睁。
有個(gè)問(wèn)題就是有可能你的service只想讓某個(gè)特定的apk使用供璧,而不是所有apk都能使用,這個(gè)時(shí)候冻记,你需要重寫(xiě)Stub中的onTransact方法,根據(jù)調(diào)用者的uid來(lái)獲得其信息来惧,然后做權(quán)限認(rèn)證冗栗,如果返回true,則調(diào)用成功供搀,否則調(diào)用會(huì)失敗隅居。對(duì)于其他apk,你只要在onTransact中返回false就可以讓其無(wú)法調(diào)用MyService中的方法葛虐,這樣就可以解決這個(gè)問(wèn)題了胎源。

public class MyService extends Service {
    private static String TAG = "migill_A";
    private static final String PACKAGE_SAYHI = "com.migill.binder.b";
    @Override
    public IBinder onBind(Intent intent) {
        return new ILoginInterface.Stub() {
            @Override
            public void login() throws RemoteException {
            }
            @Override
            public void loginCallback(boolean loginStatus, LoginUser loginUser) throws RemoteException {
                Log.e(TAG, "loginStatus: " + loginStatus + " / LoginUser: " + loginUser.toString());
                sendLoginCallBackBrodcast(loginStatus, loginUser);
            }
            //在這里可以做權(quán)限認(rèn)證,return false意味著客戶端的調(diào)用就會(huì)失敗屿脐,比如下面涕蚤,只允許包名為com.migill.binder.a的客戶端通過(guò),
            //其他apk將無(wú)法完成調(diào)用過(guò)程
            public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
                    throws RemoteException {
                String packageName = null;
                String[] packages = MyService.this.getPackageManager().
                        getPackagesForUid(getCallingUid());
                if (packages != null && packages.length > 0) {
                    packageName = packages[0];
                }
                Log.e(TAG, "onTransact: " + packageName);
                if (!PACKAGE_SAYHI.equals(packageName)) {
                    return false;
                }
                return super.onTransact(code, data, reply, flags);
            }
        };
    }

    private void sendLoginCallBackBrodcast(boolean loginStatus, LoginUser loginUser) {
        Intent intent = new Intent("com.migill.binder.a.LOGINCAKKBACK_STATE");
        intent.putExtra("loginStatus", loginStatus);
        intent.putExtra("loginUser", loginUser);
        sendBroadcast(intent);
    }
}

AndroidManifest.xml中添加service標(biāo)簽

     <!--
                 代表在應(yīng)用程序里的诵,當(dāng)需要該service時(shí)万栅,會(huì)自動(dòng)創(chuàng)建新的進(jìn)程。
                 android:process=":remote"
                 是否可以被系統(tǒng)實(shí)例化
                 android:enabled="true"
                 代表是否能被其他應(yīng)用隱式調(diào)用
                 android:exported="true"
        -->
        <service
            android:name=".service.MyService"
            android:enabled="true"
            android:exported="true"
            android:process=":remote">
            <intent-filter>
                <!-- 激活 MyService 唯一name西疤,不能重名 -->
                <action android:name="BinderA_Action" />
            </intent-filter>
        </service>

LoginActivity綁定BinderB提供的服務(wù)烦粒,在點(diǎn)擊QQ按鈕的時(shí)候,調(diào)用BinderB中提供的登錄接口代赁。在LoginActivity定義了一個(gè)廣播接受者扰她,用于接收BinderB返回的登錄結(jié)果

public class LoginActivity extends Activity {
    private static String TAG = "migill_A";
    private boolean isStartRemote; // 是否開(kāi)啟跨進(jìn)程通信
    private ILoginInterface iLogin; // AIDL定義接口
    LoginCallbackReceiver loginCallbackReceiver;
    TextView tvLogincallback;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE); // 隱藏標(biāo)題
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN); // 設(shè)置全屏

        setContentView(R.layout.activity_login);
        tvLogincallback = findViewById(R.id.tv_logincallback);
        initBindService();//初始化
        RegisterBroadcast();
    }
    public void RegisterBroadcast() {
        IntentFilter filter = new IntentFilter();
        filter.addAction("com.migill.binder.a.LOGINCAKKBACK_STATE");
        loginCallbackReceiver = new LoginCallbackReceiver();
        registerReceiver(loginCallbackReceiver, filter);
    }
    // 點(diǎn)擊事件
    public void startQQLoginAction(View view) {
        if (iLogin != null) {
            try {
                // 調(diào)用Server方法
                iLogin.login();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        } else {
            Toast.makeText(this, "請(qǐng)安裝QQ應(yīng)用...", Toast.LENGTH_SHORT).show();
        }
    }
    public void initBindService() {
        Intent intent = new Intent();
        // 設(shè)置Server應(yīng)用Action
        intent.setAction("BinderB_Action");
        // 設(shè)置Server應(yīng)用包名(5.1+要求)
        intent.setPackage("com.migill.binder.b");
        // 開(kāi)始綁定服務(wù)
        bindService(intent, conn, BIND_AUTO_CREATE);
        // 標(biāo)識(shí)跨進(jìn)程綁定
        isStartRemote = true;
    }
    // 服務(wù)連接
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iLogin = ILoginInterface.Stub.asInterface(service);
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (isStartRemote) {
            // 解綁服務(wù),一定要記得解綁服務(wù)芭碍,否則可能會(huì)報(bào)異常(服務(wù)連接資源異常)
            unbindService(conn);
        }
        unregisterReceiver(loginCallbackReceiver);
    }
    private void LoginCallback(boolean loginStatus, LoginUser loginUser) {
        Log.e(TAG, "LoginCallback loginStatus: " + loginStatus + " / LoginUser: " + loginUser.toString());
        tvLogincallback.setText("登錄結(jié)果: " + (loginStatus==true?"登錄成功":"登錄失敗") + "\n" +
                "LoginUser: " + loginUser.toString());
    }
    private final class LoginCallbackReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            boolean loginStatus = intent.getBooleanExtra("loginStatus", false);
            LoginUser loginUser = (LoginUser) intent.getParcelableExtra("loginUser");
            LoginCallback(loginStatus, loginUser);
        }
    }
}

4.BinderB項(xiàng)目
MyService.java中在login()中啟動(dòng)了MainActivity徒役。

public class MyService extends Service {
    private static String TAG = "migill_B";
    private static final String PACKAGE_SAYHI = "com.migill.binder.a";
    @Override
    public IBinder onBind(Intent intent) {
        return new ILoginInterface.Stub() {
            @Override
            public void login() throws RemoteException {
                Log.e(TAG, "BinderB_MyService");
                // 單項(xiàng)通信有問(wèn)題,真實(shí)項(xiàng)目雙向通信豁跑,雙服務(wù)綁定
                serviceStartActivity();
            }
            @Override
            public void loginCallback(boolean loginStatus, LoginUser loginUser) throws RemoteException {
            }
            //在這里可以做權(quán)限認(rèn)證廉涕,return false意味著客戶端的調(diào)用就會(huì)失敗,比如下面艇拍,只允許包名為com.migill.binder.a的客戶端通過(guò)狐蜕,
            //其他apk將無(wú)法完成調(diào)用過(guò)程
            public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
                    throws RemoteException {
                String packageName = null;
                String[] packages = MyService.this.getPackageManager().
                        getPackagesForUid(getCallingUid());
                if (packages != null && packages.length > 0) {
                    packageName = packages[0];
                }
                Log.e(TAG, "onTransact: " + packageName);
                if (!PACKAGE_SAYHI.equals(packageName)) {
                    return false;
                }
                return super.onTransact(code, data, reply, flags);
            }

        };
    }
    /**
     * 在Service啟動(dòng)Activity,需要配置:.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
     */
    private void serviceStartActivity() {
        Intent intent = new Intent(this, MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }
}

AndroidManifest.xml中添加service標(biāo)簽

   <!--
                 代表在應(yīng)用程序里卸夕,當(dāng)需要該service時(shí)层释,會(huì)自動(dòng)創(chuàng)建新的進(jìn)程。
                 android:process=":remote"
                 是否可以被系統(tǒng)實(shí)例化
                 android:enabled="true"
                 代表是否能被其他應(yīng)用隱式調(diào)用
                 android:exported="true"
        -->
        <service
            android:name="com.migill.binder.b.service.MyService"
            android:enabled="true"
            android:exported="true"
            android:process=":remote_service">
            <intent-filter>
                <!-- 激活 MyService 唯一name快集,不能重名-->
                <action android:name="BinderB_Action" />
            </intent-filter>
        </service>

BinderA調(diào)用了BinderB提供的登錄接口贡羔,BinderB的登錄接口執(zhí)行啟動(dòng)MainActivity廉白,在BinderB項(xiàng)目的MainActivity中綁定了BinderA中提供的服務(wù)。在點(diǎn)擊登錄的時(shí)候乖寒,在調(diào)用BidnerA中登錄返回接口猴蹂。

public class MainActivity extends Activity {
    private static String TAG = "migill_B";
    // 模擬用戶名和密碼 的值
    private final static String NAME = "migill";
    private final static String PWD = "123";
    private EditText nameEt;
    private EditText pwdEt;
    private boolean isStartRemote; // 是否開(kāi)啟跨進(jìn)程通信
    private ILoginInterface iLogin; // AIDL定義接口

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE);  // 隱藏標(biāo)題
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);    // 設(shè)置全屏
        setContentView(R.layout.activity_main);
        nameEt = findViewById(R.id.nameEt);
        pwdEt = findViewById(R.id.pwdEt);
        initBindService();
    }

    public void initBindService() {
        Intent intent = new Intent();
        // 設(shè)置Server應(yīng)用Action
        intent.setAction("BinderA_Action");
        // 設(shè)置Server應(yīng)用包名(5.1+要求)
        intent.setPackage("com.migill.binder.a");
        // 開(kāi)始綁定服務(wù)
        bindService(intent, conn, BIND_AUTO_CREATE);
        // 標(biāo)識(shí)跨進(jìn)程綁定
        isStartRemote = true;
    }

    // 服務(wù)連接
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //將服務(wù)端的返回的Binder對(duì)象,轉(zhuǎn)換成客戶端所需要的AIDL接口類型對(duì)象楣嘁。
            //返回對(duì)象:
            //若客戶端和服務(wù)端位于同一進(jìn)程磅轻,則直接返回Stub對(duì)象本身;
            //若客戶端和服務(wù)端位于不同一進(jìn)程逐虚,返回的是系統(tǒng)封裝后的Stub.proxy對(duì)象聋溜。
            iLogin = ILoginInterface.Stub.asInterface(service);
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    // 點(diǎn)擊事件
    public void startLogin(View view) {
        final String name = nameEt.getText().toString();
        final String pwd = pwdEt.getText().toString();
        if (TextUtils.isEmpty(name) || TextUtils.isEmpty(pwd)) {
            showToast("請(qǐng)輸入用戶名或密碼...");
            return;
        }
        // 模擬登錄狀態(tài)加載...
        final ProgressDialog progressDialog = new ProgressDialog(this);
        progressDialog.setTitle("登錄");
        progressDialog.setMessage("正在登錄中...");
        progressDialog.show();
        new Thread(new Runnable() {
            @Override
            public void run() {

                SystemClock.sleep(1000);

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            boolean isLoginSuccess = false;
                            if (NAME.equals(name) && PWD.equals(pwd)) {
                                showToast("QQ登錄成功!");
                                isLoginSuccess = true;
                                finish();
                            } else {
                                showToast("QQ登錄失敗!");
                                progressDialog.dismiss();
                            }
                            LoginUser loginUser = new LoginUser();
                            loginUser.userName = name;
                            loginUser.userPassWord = pwd;
                            iLogin.loginCallback(isLoginSuccess, loginUser);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        }).start();

    }
    private void showToast(String text) {
        Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (isStartRemote) {
            // 解綁服務(wù),一定要記得解綁服務(wù)叭爱,否則可能會(huì)報(bào)異常(服務(wù)連接資源異常)
            unbindService(conn);
        }
    }
}

總結(jié):我們要先安裝BinderB項(xiàng)目撮躁,這樣BinderB就會(huì)在ServiceManager中進(jìn)行注冊(cè)。BinderA就可以在ServiceManager中通過(guò)名字查找买雾,獲取Binder對(duì)象把曼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市凝果,隨后出現(xiàn)的幾起案子祝迂,更是在濱河造成了極大的恐慌,老刑警劉巖器净,帶你破解...
    沈念sama閱讀 222,681評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件型雳,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡山害,警方通過(guò)查閱死者的電腦和手機(jī)纠俭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)浪慌,“玉大人冤荆,你說(shuō)我怎么就攤上這事∪ㄏ耍” “怎么了钓简?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,421評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)汹想。 經(jīng)常有香客問(wèn)我外邓,道長(zhǎng),這世上最難降的妖魔是什么古掏? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,114評(píng)論 1 300
  • 正文 為了忘掉前任损话,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘丧枪。我一直安慰自己光涂,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布拧烦。 她就那樣靜靜地躺著忘闻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪恋博。 梳的紋絲不亂的頭發(fā)上服赎,一...
    開(kāi)封第一講書(shū)人閱讀 52,713評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音交播,去河邊找鬼。 笑死践付,一個(gè)胖子當(dāng)著我的面吹牛秦士,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播永高,決...
    沈念sama閱讀 41,170評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼隧土,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了命爬?” 一聲冷哼從身側(cè)響起曹傀,我...
    開(kāi)封第一講書(shū)人閱讀 40,116評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎饲宛,沒(méi)想到半個(gè)月后皆愉,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,651評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡艇抠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評(píng)論 3 342
  • 正文 我和宋清朗相戀三年幕庐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片家淤。...
    茶點(diǎn)故事閱讀 40,865評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡异剥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出絮重,到底是詐尸還是另有隱情冤寿,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布青伤,位于F島的核電站督怜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏潮模。R本人自食惡果不足惜亮蛔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望擎厢。 院中可真熱鬧究流,春花似錦辣吃、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,699評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至偷仿,卻和暖如春哩簿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背酝静。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,814評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工节榜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人别智。 一個(gè)月前我還...
    沈念sama閱讀 49,299評(píng)論 3 379
  • 正文 我出身青樓宗苍,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親薄榛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子讳窟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評(píng)論 2 361

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