一些跨进程通信包括不同应用之间和同一应用不同进程之间

跨进程之不通应用之间

1在app中启动另外一个app
A应用拉起B应用的非主页面的某个页面,并且传值(一般是鉴权token值、type值以及其他参数值,本文仅仅以传递type值为例),B应用根据传递过来的不同的值启动不同的页面。需要注意的是A应用拉起B应用的启动页(SplashActivity)并传值(token值和type值以及其他参数值),在启动页获取到值并且存储到SharedPreferences中,最好再存储一个Boolean值,代表这是从第三方应用拉起来的。然后有两种情况,通过Activity的管理工具类判断栈中是否含有B应用的主页面(即B应用是否已经运行在后台)①不含有:代表后台并没有运行B应用,那么我们正常启动主页面,在主页(MainActivity)从SharedPreferences中获取到这个Boolean值与A应用传递过来的值,由主页根据A应用传递过来的值打开相应的页面,这样用户点击返回顺序为:B应用相应页面-B应用主页面-A应用;②含有:代表B应用已经运行在后台,并且现在可能停留在某个页面,此时,我们不应该在启动页继续走启动主页面的逻辑了,如果继续启动主页面,由于我们设置了主页的启动模式为android:launchMode=”singleTask”,那么B应用栈中主页面以上页面都会出栈,用户将看不到刚刚浏览过的页面,这样太不友好了。因此此时的解决方案是我们要在启动页发个静态广播,在广播接收者中获取到SharedPreferences中的Boolean值与A应用传递过来的值,并且通过Activity的管理工具类获取到栈顶的Activity,然后在栈顶Activity的基础上启动相应的页面,(当然,这里也可以不发送广播,直接在启动页通过Activity的管理工具类获取到栈顶的Activity,然后在栈顶Activity的基础上启动相应的页面,这样效果是一样的)这样用户点击返回的顺序为:B应用相应页面-B应用用户拉起客户端之前浏览的页面-B应用主页面-A应用。

b应用启动页清单文件配置
 <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <!--ACTION启动配置用于隐士启动app host path选填-->
            <intent-filter>
                <data
                    android:host="pull.csd.demo"
                    android:path="/cyn"
                    android:scheme="csd" />
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
            </intent-filter>
A应用启动B的代码
Intent intent = new Intent();
            intent.setData(Uri.parse("csd://pull.csd.demo/cyn?type=110"));
            intent.putExtra("", "");//这里Intent当然也可传递参数,但是一般情况下都会放到上面的URL中进行传递
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
B应用获取A传递的信息
 if(null!=intent&&null!=intent.data) {
            val uri:Uri = intent.data
            if (uri != null) {
               Toast.makeText(this,uri.scheme + "--" + uri.host + "--" + uri.path + uri.getQueryParameter("type"),Toast.LENGTH_SHORT).show()
            }
        }

2广播

public class BroadcastActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_broadcast);
        View send = findViewById(R.id.send_broad_cast);
        send.setOnClickListener(v->{
            Intent intent=new Intent();
            intent.setAction("test_send_cast");
            intent.putExtra("info", "传递内容");
            sendBroadcast(intent);
            System.out.println("发送了广播");
        });
    }
另外一个项目中接受广播
package com.example.shanghai.daojishiapplication;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;

public class ReceiveBroadcastActivity extends AppCompatActivity {
    BroadcastReceiver broadcastReceiver;
    IntentFilter intentFilter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_receive_broadcast);
        intentFilter=new IntentFilter();
        intentFilter.addAction("test_send_cast");
        broadcastReceiver=new MyReceiver();
        registerReceiver(broadcastReceiver,intentFilter);
    }
    class MyReceiver extends BroadcastReceiver
    {

        @Override
        public void onReceive(Context context, Intent intent) {
            // TODO Auto-generated method stub
            if(intent!=null){
                if(!TextUtils.isEmpty(intent.getAction())){
                    System.out.println("!TextUtils.isEmpty(intent.getAction()");
                }
                if(!TextUtils.isEmpty(intent.getStringExtra("info"))){
                   System.out.println(intent.getStringExtra("info"));
                }
            }
        }

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(broadcastReceiver);
    }
}

3AIDL (Android interface definition language)
在AndroidStudio 中新建aidl文件


// Declare any non-default types here with import statements

interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
           
            boolean forwardPayMoney(float money);


}

新建一个service隐士启动

        <service
            android:name=".service.ProvideService"
            android:enabled="true"
            android:exported="true"
            >
            <intent-filter>
                <action android:name="com.example.shanghai.daojishiapplication.action.AIDL"></action>
            </intent-filter>
        </service>
package com.example.shanghai.daojishiapplication.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;

import com.example.shanghai.daojishiapplication.IMyAidlInterface;

/**
 * Created by shanghai on 2018/4/10.
 */

public class ProvideService extends Service{
    private static final String TAG="ProvideService";
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        System.out.println(TAG+"onBind");
        return new MyBinder();
    }

    private class MyBinder extends IMyAidlInterface.Stub{

        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public boolean forwardPayMoney(float money) throws RemoteException {
            System.out.println(TAG+"public boolean forwardPayMoney(float money) throws RemoteException");
            return false;
        }
    }
}

把main目录下的aidl包拷贝到在另外一个app中的main目录下build项目
在activity中bindservice调用service中的方法

package com.github.zackratos.rvitemam;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

import com.example.shanghai.daojishiapplication.IMyAidlInterface;

public class TestAidlActivity extends AppCompatActivity {

  private View btn_bind;
  private View btn_invoke;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_test_aidl);
      btn_bind = findViewById(R.id.btn_bind);
      btn_invoke = findViewById(R.id.btn_invoke);

      btn_bind.setOnClickListener(v->{
          System.out.println("TestAidlActivity--btn_bind");
          bindservice();
      });
      btn_invoke.setOnClickListener(v -> {
          System.out.println("TestAidlActivity--btn_invoke");
          try {
              boolean b = mIService.forwardPayMoney(0.1f);
              System.out.println("TestAidlActivity-forwarpay="+b);
          } catch (RemoteException e) {
              e.printStackTrace();
          }
      });
  }
  /**
   * 绑定远程服务
   */
  public void bindservice() {
      Intent mIntent = new Intent();
      mIntent.setAction("com.example.shanghai.daojishiapplication.action.AIDL");
      mIntent.setPackage("com.example.shanghai.daojishiapplication");//需要指定提供服务的程序包名
      MyConnection myConnection = new MyConnection();
      bindService(mIntent, myConnection,BIND_AUTO_CREATE);

  }

  private IMyAidlInterface mIService;

  class MyConnection implements ServiceConnection {
      @Override
      public void onServiceConnected(ComponentName name, IBinder service) {
          mIService = IMyAidlInterface.Stub.asInterface(service);
      }

      @Override
      public void onServiceDisconnected(ComponentName name) {

      }
  }


}

4Messenger

不需要创建aidl文件
service隐士启动

<service
          android:name=".service.MyService"
          android:enabled="true"
          android:exported="true"
          android:process=":remote">
          <intent-filter>
              <action android:name="com.example.shanghai.daojishiapplication.service.MyService"></action>
          </intent-filter>
      </service>
package com.example.shanghai.daojishiapplication.service;

import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v4.app.INotificationSideChannel;
import android.util.Log;

/**
* 与客户端跨进程通信
*/
public class MyService extends Service {
  /** Command to the service to display a message */
  public static final int MSG_SAY_HELLO = 1;
  private static final String TAG ="wzj" ;

  /* 用于接收从客户端传递过来的数据 */
  class IncomingHandler extends Handler {
      @Override
      public void handleMessage(Message msg) {
          switch (msg.what) {
              case MSG_SAY_HELLO:
                  System.out.println("thanks,Service had receiver message from client!");
                  Messenger client=msg.replyTo;
                  Message replyMsg=Message.obtain(null,MyService.MSG_SAY_HELLO);
                  Bundle bundle=new Bundle();
                  bundle.putString("reply","ok~,I had receiver message from you! ");
                  replyMsg.setData(bundle);
                  try {
                      client.send(replyMsg);
                  } catch (RemoteException e) {
                      e.printStackTrace();
                  }
                  break;
              default:
                  super.handleMessage(msg);
          }
      }
  }

  /* 创建Messenger并传入Handler实例对象 */
  final Messenger mMessenger = new Messenger(new IncomingHandler());

  /* 当绑定Service时,该方法被调用,将通过mMessenger返回一个实现IBinder接口的实例对象 */
  @Override
  public IBinder onBind(Intent intent) {
      System.out.println("Service is invoke onBind");
      return mMessenger.getBinder();
  }


}

activity
package com.github.zackratos.rvitemam;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
public class MessageActivity extends AppCompatActivity {
  /* 与服务端交互的Messenger */
  Messenger mService = null;
  /**
   * Flag indicating whether we have called bind on the service.
   */
  boolean mBound;
  private View btn;
  private StringBuffer printMessage = new StringBuffer();
  private View send;
  private View unbind;
  private String SERVICE_ACTION="com.example.shanghai.daojishiapplication.service.MyService";
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_message);
      btn = findViewById(R.id.btn_bind);
      send = findViewById(R.id.btn_send);
      unbind = findViewById(R.id.btn_unbind);
      btn.setOnClickListener(v -> {
          System.out.println("onClick-->bindService");
          Intent mIntent = new Intent();
          mIntent.setAction("com.example.shanghai.daojishiapplication.service.MyService");
          mIntent.setPackage("com.example.shanghai.daojishiapplication");//需要指定提供服务的程序包名
          bindService(mIntent, mConnection,BIND_AUTO_CREATE);
      });

      send.setOnClickListener(v -> {
          System.out.println("click"+"sayHello");
          sayHello();
      });


      unbind.setOnClickListener(v -> {
          if (mBound) {
              System.out.println("onClick-->unbindService");
              unbindService(mConnection);
              mBound = false;
          }
      });
  }

  /* 实现与服务端链接的对象ServiceConnection */
  private ServiceConnection mConnection = new ServiceConnection() {
      public void onServiceConnected(ComponentName className, IBinder service) {
          System.out.println("onServiceConnected");
          /* 通过服务端传递的IBinder对象,创建相应的Messenger
           * 通过该Messenger对象与服务端进行交互 */
          mService = new Messenger(service);
          mBound = true;
      }

      public void onServiceDisconnected(ComponentName className) {
          // This is called when the connection with the service has been
          // unexpectedly disconnected -- that is, its process crashed.
          mService = null;
          mBound = false;
      }
  };

  public void sayHello() {
      if (!mBound) return;
      System.out.println("sayHello");
      // 创建与服务交互的消息实体Message
      Message msg = Message.obtain();
      msg.what=1;
      msg.replyTo=mRecevierReplyMsg;
      try {
          //发送消息
          mService.send(msg);
      } catch (RemoteException e) {
          e.printStackTrace();
      }

  }

  private static class ReceiverReplyMsgHandler extends Handler {
      private static final String TAG = "zj";

      @Override
      public void handleMessage(Message msg) {
          System.out.println("receiver message from service:");
          switch (msg.what) {
              //接收服务端回复
              case 1:
                  System.out.println("receiver message from service:" + msg.getData().getString("reply"));
                  break;
              default:
                  super.handleMessage(msg);
          }
      }


  }


  private Messenger mRecevierReplyMsg = new Messenger(new ReceiverReplyMsgHandler());
}

2跨进程通信之与service之间

(首先讲一下两种启动方式,Service以及service与activity交互)

startService():
1、启动服务对象多次启动同时只会产生一个,onCreate()方法只会在Service第一次被创建的时候调用,多次点击启动会执行多次onStartCommand()方法,onDestroy()方法只会在Service第一次被停止的时候调用,多次点击停止不会报异常,也不再执行onDestroy()方法。
2、一旦启动,Service将一直运行在后台(run in the background indefinitely)即便启动Service的组件已被destroy。
3、停止一个started服务有两种方法:
(1)在外部使用stopService()手动停止。
(2)在服务内部(onStartCommand方法内部)使用stopSelf()方法,使服务执行完毕后自动停止。比如说,一个start的Service执行在后台下载或上传一个文件的操作,完成之后,Service应自己停止。

bindService()
仅当与另一个应用组件绑定时,绑定服务才会运行。多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。(通过 unbindService()方法来关闭这种连接)

service与activity交互

(1)startService可以通过intent传递
(2)bindservice()如果我们的服务仅供本地应用使用,不需要跨进程工作,则可以实现自有 Binder 类,让客户端通过该类直接访问服务中的公共方法。其使用开发步骤如下
创建BindService服务端,继承自Service并在类中,创建一个实现IBinder 接口的实例对象并提供公共方法给客户端调用
从 onBind() 回调方法返回此 Binder 实例。
在客户端中,从 onServiceConnected() 回调方法接收 Binder,并使用提供的方法调用绑定服务。
注意:此方式只有在客户端和服务位于同一应用和进程内才有效,如对于需要将 Activity 绑定到在后台播放音乐的自有服务的音乐应用,此方式非常有效。另一点之所以要求服务和客户端必须在同一应用内,是为了便于客户端转换返回的对象和正确调用其 API。服务和客户端还必须在同一进程内,因为此方式不执行任何跨进程编组
(3)同一个进程eventbus也可
(4)service在独立的进程中采用Messenger进行传递,或者aidl下面讲一下Messenger的使用方法,aidl放在后面跨进程通信中讲解

package com.example.shanghai.daojishiapplication.service;

import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v4.app.INotificationSideChannel;
import android.util.Log;

/**
 * 与客户端跨进程通信
 */
public class MyService extends Service {
    /** Command to the service to display a message */
    public static final int MSG_SAY_HELLO = 1;
    private static final String TAG ="wzj" ;

    /* 用于接收从客户端传递过来的数据 */
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    System.out.println("thanks,Service had receiver message from client!");
                    Messenger client=msg.replyTo;
                    Message replyMsg=Message.obtain(null,MyService.MSG_SAY_HELLO);
                    Bundle bundle=new Bundle();
                    bundle.putString("reply","ok~,I had receiver message from you! ");
                    replyMsg.setData(bundle);
                    try {
                        client.send(replyMsg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /* 创建Messenger并传入Handler实例对象 */
    final Messenger mMessenger = new Messenger(new IncomingHandler());

    /* 当绑定Service时,该方法被调用,将通过mMessenger返回一个实现IBinder接口的实例对象 */
    @Override
    public IBinder onBind(Intent intent) {
        System.out.println("Service is invoke onBind");
        return mMessenger.getBinder();
    }


}
package com.example.shanghai.daojishiapplication;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

import com.example.shanghai.daojishiapplication.service.MyService;

public class MessageActivity extends AppCompatActivity {
    /* 与服务端交互的Messenger */
    Messenger mService = null;
    /**
     * Flag indicating whether we have called bind on the service.
     */
    boolean mBound;
    private View btn;
    private StringBuffer printMessage = new StringBuffer();
    private View send;
    private View unbind;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_message);
        btn = findViewById(R.id.btn_bind);
        send = findViewById(R.id.btn_send);
        unbind = findViewById(R.id.btn_unbind);
        btn.setOnClickListener(v -> {
            System.out.println("onClick-->bindService");
            //当前Activity绑定服务端
            bindService(new Intent(MessageActivity.this, MyService.class), mConnection,
                    Context.BIND_AUTO_CREATE);
        });

        send.setOnClickListener(v -> {
            sayHello();
        });


        unbind.setOnClickListener(v -> {
            if (mBound) {
                System.out.println("onClick-->unbindService");
                unbindService(mConnection);
                mBound = false;
            }
        });
    }

    /* 实现与服务端链接的对象ServiceConnection */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            /* 通过服务端传递的IBinder对象,创建相应的Messenger
             * 通过该Messenger对象与服务端进行交互 */
            mService = new Messenger(service);
            mBound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected -- that is, its process crashed.
            mService = null;
            mBound = false;
        }
    };

    public void sayHello() {
        if (!mBound) return;
        System.out.println("sayHello");
        // 创建与服务交互的消息实体Message
        Message msg = Message.obtain(null, MyService.MSG_SAY_HELLO, 0, 0);
        msg.replyTo=mRecevierReplyMsg;
        try {
            //发送消息
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }

    }

    private static class ReceiverReplyMsgHandler extends Handler {
        private static final String TAG = "zj";

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                //接收服务端回复
                case MyService.MSG_SAY_HELLO:
                    System.out.println("receiver message from service:" + msg.getData().getString("reply"));
                    break;
                default:
                    super.handleMessage(msg);
            }
        }


    }


    private Messenger mRecevierReplyMsg = new Messenger(new ReceiverReplyMsgHandler());
}
清单文件中配置
 <service
            android:name=".service.MyService"
            android:enabled="true"
            android:exported="true"
            android:process=":remote" />

intentservice解决servcie不能执行耗时操作这一问题,service保活可以
将service设置为前台服务,或者设置两个服务相互监听,在ondestory中发送广播
在另外一个服务中接收到广播再start服务

关于service更多使用方法信息参考(https://www.jianshu.com/p/086869a2f0ac

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335