Glide源码分析二——Request相关

RequestManagerRetriever

Glide在构造时创建了RequestManagerRetriever,用于根据参数(Application、Activity、FragmentActivity、Fragment、View)获取RequestManager。

如果没有创建RequestManager,则会通过RequestManagerFactory创建。

// RequestManagerRetriever.java

private volatile RequestManager applicationManager;

public RequestManagerRetriever(@Nullable RequestManagerFactory factory) {
    // 如果没有
    this.factory = factory != null ? factory : DEFAULT_FACTORY;
    handler = new Handler(Looper.getMainLooper(), this /* Callback */);
}


// RequestManager工厂类
public interface RequestManagerFactory {
    @NonNull
    RequestManager build(
        @NonNull Glide glide,
        @NonNull Lifecycle lifecycle,
        @NonNull RequestManagerTreeNode requestManagerTreeNode,
        @NonNull Context context);
}

private static final RequestManagerFactory DEFAULT_FACTORY =
      new RequestManagerFactory() {
        @NonNull
        @Override
        public RequestManager build(
            @NonNull Glide glide,
            @NonNull Lifecycle lifecycle,
            @NonNull RequestManagerTreeNode requestManagerTreeNode,
            @NonNull Context context) {
          return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
        }
      };
      
      
public RequestManager get(@NonNull Context context) {
    if (context == null) {
      // ... 省略抛异常代码
    } else if (Util.isOnMainThread() && !(context instanceof Application)) {
    
      // 如果是在主线程,且context不是Application,则获取对应页面(Activity、Fragment)的RequestManager(该RequestManger对应着一个RequestManagerFragment)
      
      if (context instanceof FragmentActivity) {
        return get((FragmentActivity) context);
      } else if (context instanceof Activity) {
        return get((Activity) context);
      } else if (context instanceof ContextWrapper
          && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }

    // 如果是在子线程或context是Application,则返回ApplicationManager(跟随应用生命周期)
    return getApplicationManager(context);
}

private RequestManager getApplicationManager(@NonNull Context context) {
    
    if (applicationManager == null) {
      synchronized (this) {
        if (applicationManager == null) {
          Glide glide = Glide.get(context.getApplicationContext());
          
          // 利用工厂类创建一个跟随应用声明周期的RequestManger
          applicationManager =
              factory.build(
                  glide,
                  new ApplicationLifecycle(),
                  new EmptyRequestManagerTreeNode(),
                  context.getApplicationContext());
        }
      }
    }

    return applicationManager;
}

public RequestManager get(FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      
      // 获取SupportFragmentManger,用于查找或添加SupportRequestMangerFragment,之后利用SupportRequestMangerFragment获取RequestManger
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
}

private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {

    // 获取SupportRequestManagerFragment
    SupportRequestManagerFragment current =
        getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
        
    // 从SupportRequestManagerFragment中获取RequestManger
    RequestManager requestManager = current.getRequestManager();
    
    // 如果SupportRequestManagerFragment没有RequetManger,则创建RequestManager并设置给SupportRequestManagerFragment
    if (requestManager == null) {
      
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
}


// 正在通过FragmentManger添加的RequestManagerFragment,之后会通过handler从该集合中移除
final Map<android.app.FragmentManager, RequestManagerFragment> pendingRequestManagerFragments =
      new HashMap<>();
      
final Map<FragmentManager, SupportRequestManagerFragment> pendingSupportRequestManagerFragments =
      new HashMap<>();

@NonNull
private SupportRequestManagerFragment getSupportRequestManagerFragment(
      @NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
    
    // 是否有已经添加了的RequeetFragment
    SupportRequestManagerFragment current =
        (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      
      // 是否有正在添加的RSupportequestFragment,没有的话,创建一个,并通过FragmentManager添加,同时放入pendingSupportRequestManagerFragments中,待添加完成后会通过Handler从集合中移除
      current = pendingSupportRequestManagerFragments.get(fm);
      if (current == null) {
        current = new SupportRequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {
          current.getGlideLifecycle().onStart();
        }
        pendingSupportRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        
        // handler发送消息,从列表中移除正在添加的fragment
        handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
}


其他get(Activity)、get(Fragment)、get(View)都差不多

public RequestManager get(@NonNull View view) {
    if (Util.isOnBackgroundThread()) {
      return get(view.getContext().getApplicationContext());
    }

    ...
    // 找到context对应的Activity
    Activity activity = findActivity(view.getContext());
    
    if (activity == null) {
      return get(view.getContext().getApplicationContext());
    }

    
    if (activity instanceof FragmentActivity) {
      // 递归遍历view的parent,如果view的哪个parent是已经Added的SupportFragment的rootView,则返回该Fragment
      Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
      
      // 获取Fragment或Activity的SupportRequestManagerFragment的RequestManaager
      return fragment != null ? get(fragment) : get((FragmentActivity) activity);
    }

    // 和findSupportFragment(...)类似,只是这里返回的是android.app.Fragment
    android.app.Fragment fragment = findFragment(view, activity);
    if (fragment == null) {
      return get(activity);
    }
    return get(fragment);
}


// 临时map,存储Fragment和它的rootView
private final ArrayMap<View, Fragment> tempViewToSupportFragment = new ArrayMap<>();

// 递归遍历view的parent,如果view或view的哪个parent是已经Added的Fragment的rootView,则返回该Fragment   
private Fragment findSupportFragment(@NonNull View target, @NonNull FragmentActivity activity) {
    tempViewToSupportFragment.clear();
    
    // 获取Activity已添加的所有Fragment及每个Fragment的子Fragment,及对应的fragment的RootView
    findAllSupportFragmentsWithViews(
        activity.getSupportFragmentManager().getFragments(), tempViewToSupportFragment);
        
    // 如果view或者view的parent是某个已Added的fragment的rootView,则返回该Fragment    
    Fragment result = null;
    View activityRoot = activity.findViewById(android.R.id.content);
    View current = target;
    while (!current.equals(activityRoot)) {
      result = tempViewToSupportFragment.get(current);
      if (result != null) {
        break;
      }
      if (current.getParent() instanceof View) {
        current = (View) current.getParent();
      } else {
        break;
      }
    }

    tempViewToSupportFragment.clear();
    return result;
}

// 遍历topLevelFragments及每个Fragment的子Fragment,将Fragment和对应的rootView放入临时map中
private static void findAllSupportFragmentsWithViews(
      @Nullable Collection<Fragment> topLevelFragments, @NonNull Map<View, Fragment> result) {
    if (topLevelFragments == null) {
      return;
    }
    for (Fragment fragment : topLevelFragments) {
      FragmentManager may contain null values, see #1991.
      if (fragment == null || fragment.getView() == null) {
        continue;
      }
      result.put(fragment.getView(), fragment);
      findAllSupportFragmentsWithViews(fragment.getChildFragmentManager().getFragments(), result);
    }
}

get(view)的主要工作是:
遍历该View及其parent,如果该view或其parent是该view所在的Activity的某个已经added的Fragment的rootView,则返回该Fragment的SupportRequestManagerFragment/RequestManagerFragment的RequestManager;如果该view所在的Activity没有添加Fragment或该view及其parent不是某个Fragment的rootView,则获取该view所在的Activity的SupportRequestManagerFragment/RequestManagerFragment的RequestManager。

public RequestManager get(@NonNull Fragment fragment) {
    
    if (Util.isOnBackgroundThread()) {
      return get(fragment.getContext().getApplicationContext());
    } else {
      FragmentManager fm = fragment.getChildFragmentManager();
      
      // 找到Fragment已添加的SupportRequestManagerFragment,并返回其RequestManager
      return supportFragmentGet(fragment.getContext(), fm, fragment, fragment.isVisible());
    }
}

get(androidx.fragment.app.Fragment)和get(android.app.Fragment)差不多,都是找到Fragment已添加的SupportRequestManagerFragment/RequestManagerFragment,并返回其RequestManager。

RequestManagerFragment

内含lifecycle,当RequestManagerFragment声明周期发生变化时,会通过lifecycle通知LifecycleListener,而RequestManager实现了LifecycleListener,并在创建时被添加到了lifecycle。

RequestManger

用于生成RequestBuilder、控制Request,内部使用RequestTracker控制Request的开始、暂停、销毁等。

RequestManager(
      Glide glide,
      Lifecycle lifecycle,
      RequestManagerTreeNode treeNode,
      RequestTracker requestTracker,
      ConnectivityMonitorFactory factory,
      Context context) {
      
    this.glide = glide;
    this.lifecycle = lifecycle;
    this.requestTracker = requestTracker;
    if (Util.isOnBackgroundThread()) {
      mainHandler.post(addSelfToLifecycle);
    } else {
      lifecycle.addListener(this);
    }
    ...
    
}

public synchronized void pauseRequests() {
    requestTracker.pauseRequests();
}

public synchronized void resumeRequests() {
    requestTracker.resumeRequests();
}

synchronized void track(Target<?> target, Request request) {
    targetTracker.track(target);

    // 内部调用Request#begin()开始请求数据
    requestTracker.runRequest(request);
}

...

@Override
public synchronized void onStart() {
    resumeRequests();
    targetTracker.onStart();
}

...

public <ResourceType> RequestBuilder<ResourceType> as(Class<ResourceType> resourceClass) {
    return new RequestBuilder<>(glide, this, resourceClass, context);
}

public RequestBuilder<Drawable> asDrawable() {
    return as(Drawable.class);
}

public RequestBuilder<Drawable> load(@Nullable String string) {
    return asDrawable().load(string);
}

...

RequestBuilder

用于生成Request。

// load方法会保存请求参数model
public RequestBuilder<TranscodeType> load(@Nullable Object model) {
    return loadGeneric(model);
}


private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
}

// 构造request,并启动
private <Y extends Target<TranscodeType>> Y into(
      Y target,
      RequestListener<TranscodeType> targetListener,
      BaseRequestOptions<?> options,
      Executor callbackExecutor) {
    ...

    Request request = buildRequest(target, targetListener, options, callbackExecutor);

    Request previous = target.getRequest();
    
    // 如果request和target之前的request一样,且之前的request未完成或能使用内存中已完成的request,则复用reqeust
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      
      // 如果请求完成,调用begin()重新开始确保重新传递结果,触发 RequestListeners 和 Targets。如果请求失败,调用begin()重新开始将重新启动请求,给它一次完成的机会。如果请求已经在运行,我们可以让它继续运行而不会中断。
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        
        previous.begin();
      }
      return target;
    }

    // 清除requestManager中保存的target和对应的Request(如果有的话,会分别从targetTracker和requestTracker中移除target和request,并将target.setRequest(null))
    requestManager.clear(target);
    target.setRequest(request);
    // 将target和对应的request保存在requestManager中,并启动请求(request.begin())
    requestManager.track(target, request);

    return target;
}

// buildRequest(...)直接走的这个方法
private Request buildRequestRecursive(
      Object requestLock,
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      BaseRequestOptions<?> requestOptions,
      Executor callbackExecutor) {

    ... // 省略一些代码

    Request mainRequest =
        buildThumbnailRequestRecursive(
            requestLock,
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions,
            callbackExecutor);

    if (errorRequestCoordinator == null) {
      return mainRequest;
    }

    ... // 省略一些代码
}

private Request buildThumbnailRequestRecursive(
      Object requestLock,
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      BaseRequestOptions<?> requestOptions,
      Executor callbackExecutor) {
    if (thumbnailBuilder != null) {
      ...
      return coordinator;
    } else if (thumbSizeMultiplier != null) {
      ...
      return coordinator;
    } else {
      // Base case: no thumbnail.
      return obtainRequest(
          requestLock,
          target,
          targetListener,
          requestOptions,
          parentCoordinator,
          transitionOptions,
          priority,
          overrideWidth,
          overrideHeight,
          callbackExecutor);
    }
}

private Request obtainRequest(
      Object requestLock,
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      BaseRequestOptions<?> requestOptions,
      RequestCoordinator requestCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      Executor callbackExecutor) {
      
    // 返回一个SingleRequest
    return SingleRequest.obtain(
        context,
        glideContext,
        requestLock,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListeners,
        requestCoordinator,
        glideContext.getEngine(), // 获取engine
        transitionOptions.getTransitionFactory(),
        callbackExecutor);
}

SingleRequest

public final class SingleRequest<R> implements Request, SizeReadyCallback, ResourceCallback {
    
    
    public static <R> SingleRequest<R> obtain(
      ...
      Object model,
      Class<R> transcodeClass,
      BaseRequestOptions<?> requestOptions,
      int overrideWidth,
      int overrideHeight,
      Target<R> target,
      RequestListener<R> targetListener,
      Engine engine,
      Executor callbackExecutor) {
        return new SingleRequest<>(
            ...
            model,
            transcodeClass,
            requestOptions,
            overrideWidth,
            overrideHeight,
            target,
            targetListener,
            engine,
            callbackExecutor);
    }

    private SingleRequest(
      ...
      @Nullable Object model,
      Class<R> transcodeClass,
      BaseRequestOptions<?> requestOptions,
      int overrideWidth,
      int overrideHeight,
      Target<R> target,
      RequestListener<R> targetListener,
      Engine engine,
      Executor callbackExecutor) {
        this.model = model;
        this.transcodeClass = transcodeClass;
        this.requestOptions = requestOptions;
        this.overrideWidth = overrideWidth;
        this.overrideHeight = overrideHeight;
        this.target = target;
        this.targetListener = targetListener;
        this.engine = engine;
        this.callbackExecutor = callbackExecutor;
        status = Status.PENDING;
        ...
    }
    
    
  // 开始执行请求
  @Override
  public void begin() {
    synchronized (requestLock) {
      ...
      if (model == null) {
        ...
        onLoadFailed(new GlideException("Received null model"), logLevel);
        return;
      }

      if (status == Status.RUNNING) {
        throw new IllegalArgumentException("Cannot restart a running request");
      }

      // 如果我们在请求完成后重新启动请求时(通常通过诸如 notifyDataSetChanged 之类的方式,它启动对相同目标或视图的相同请求),我们可以简单地使用我们上次检索到的资源和大小并跳过获取新大小, 开始新的加载等。如果用户需要在视图大小更改后重新启动请求,则需要在开始新加载之前显式清除视图或目标。
      if (status == Status.COMPLETE) {
        onResourceReady(resource, DataSource.MEMORY_CACHE);
        return;
      }

      // 如果请求不是运行中或完成状态,重新启动它可以被看作是一个新的请求,且可以从头开始执行。
      status = Status.WAITING_FOR_SIZE;
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        // 如果设置了overrideWidth和overrideHeight,则修改status为running,并通过engine开始加载图片
        onSizeReady(overrideWidth, overrideHeight);
      } else {
        // 没有size,则先通过Target获取大小
        target.getSize(this);
      }

      if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
          && canNotifyStatusChanged()) {
          
          // 获取placeHolderDrawable,并回调target#onLoadStarted(drawable),如果是ImageViewTarget则会让ImageView加载drawable
        target.onLoadStarted(getPlaceholderDrawable());
      }
      
    }
  }
  
  
  public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    synchronized (requestLock) {
      
      if (status != Status.WAITING_FOR_SIZE) {
        return;
      }
      status = Status.RUNNING;

      ... // 省略部分对width和height的操作,主要是乘以sizeMultiplier
      
      // 加载图片
      loadStatus =
          engine.load(
              glideContext,
              model,
              requestOptions.getSignature(),
              this.width,
              this.height,
              requestOptions.getResourceClass(),
              transcodeClass,
              priority,
              requestOptions.getDiskCacheStrategy(),
              requestOptions.getTransformations(),
              requestOptions.isTransformationRequired(),
              requestOptions.isScaleOnlyOrNoTransform(),
              requestOptions.getOptions(),
              requestOptions.isMemoryCacheable(),
              requestOptions.getUseUnlimitedSourceGeneratorsPool(),
              requestOptions.getUseAnimationPool(),
              requestOptions.getOnlyRetrieveFromCache(),
              this,
              callbackExecutor);

      ...
    }
  }
  
  
  public void onResourceReady(Resource<?> resource, DataSource dataSource) {
    ...
    Resource<?> toRelease = null;
    try {
      synchronized (requestLock) {
        loadStatus = null;
        if (resource == null) {
          GlideException exception = new GlideException("...");
          onLoadFailed(exception);
          return;
        }

        // transcodeClass就是我们想要的类型,例如Drawable、Bitmap...
        Object received = resource.get();
        if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
          toRelease = resource;
          this.resource = null;
          GlideException exception = new GlideException("..."));
          onLoadFailed(exception);
          return;
        }

        ...
        
        // 资源准备好后通知target加载资源
        onResourceReady((Resource<R>) resource, (R) received, dataSource);
      }
    } finally {
      // 资源没有被使用需要释放掉
      if (toRelease != null) {
        engine.release(toRelease);
      }
    }
  }
  
  private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
    
    boolean isFirstResource = isFirstReadyResource();
    
    // 修改状态为complete
    status = Status.COMPLETE;
    this.resource = resource;

    isCallingCallbacks = true;
    try {
    
      // 是否有任何RequestListener已经通过onResourceReady(...)通知target加载了资源
      boolean anyListenerHandledUpdatingTarget = false;
      if (requestListeners != null) {
        for (RequestListener<R> listener : requestListeners) {
          anyListenerHandledUpdatingTarget |=
              listener.onResourceReady(result, model, target, dataSource, isFirstResource);
        }
      }
      anyListenerHandledUpdatingTarget |=
          targetListener != null
              && targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);

      // 如果还没有通过RequestListener#onResourceReady(...)更新target,则直接调用Target#onResourceReady(...)通知target加载资源
      if (!anyListenerHandledUpdatingTarget) {
        Transition<? super R> animation = animationFactory.build(dataSource, isFirstResource);
        target.onResourceReady(result, animation);
      }
    } finally {
      isCallingCallbacks = false;
    }

    // 通知父RequestCoordinator请求成功了
    notifyLoadSuccess();
  }
    
}

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

推荐阅读更多精彩内容