<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          核桃干貨 | Java后端線上問(wèn)題排查常用命令收藏

          共 26488字,需瀏覽 53分鐘

           ·

          2021-03-23 17:55



          前言

          在編寫Android布局時(shí)總會(huì)遇到這樣或者那樣的痛點(diǎn),比如:

          1. 有些布局的在很多頁(yè)面都用到了,而且樣式都一樣,每次用到都要復(fù)制粘貼一大段,有沒(méi)有辦法可以復(fù)用呢?
          2. 解決了1中的問(wèn)題之后,發(fā)現(xiàn)復(fù)用的布局外面總要額外套上一層布局,要知道布局嵌套是會(huì)影響性能的吶;
          3. 有些布局只有用到時(shí)才會(huì)顯示,但是必須提前寫好,雖然設(shè)置了為invisible或gone,還是多多少少會(huì)占用內(nèi)存的。
          要解決這些痛點(diǎn),我們可以請(qǐng)Android布局優(yōu)化三劍客出碼,它們分別是include、merge和ViewStub三個(gè)標(biāo)簽,現(xiàn)在我們就來(lái)認(rèn)識(shí)認(rèn)識(shí)它們吧。在此之前,我們先來(lái)看看我們本次項(xiàng)目的界面效果:

          界面不復(fù)雜,我們來(lái)逐個(gè)實(shí)現(xiàn)吧。

          1、include


          include的中文意思是“包含”、“包括”,當(dāng)你在一個(gè)主頁(yè)面里使用include標(biāo)簽時(shí),就表示當(dāng)前的主布局包含標(biāo)簽中的布局,這樣一來(lái),就能很好地起到復(fù)用布局的效果了。在那些常用的布局比如標(biāo)題欄和分割線等上面用上它可以極大地減少代碼量的。它有兩個(gè)主要的屬性:

          1. layout:必填屬性,為你需要插入當(dāng)前主布局的布局名稱,通過(guò)R.layout.xx的方式引用;
          2. id:當(dāng)你想給通過(guò)include添加進(jìn)來(lái)的布局設(shè)置一個(gè)id的時(shí)候就可以使用這個(gè)屬性,它可以重寫插入主布局的布局id。
          下面我們就來(lái)實(shí)戰(zhàn)一番。

          1.1 常規(guī)使用


          我們先創(chuàng)建一個(gè)ViewOptimizationActivity,然后再創(chuàng)建一個(gè)layout_include.xml布局文件,它的內(nèi)容非常簡(jiǎn)單,就一個(gè)TextView:

          <?xml version="1.0" encoding="utf-8"?>
          <TextView xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:gravity="center_vertical"
              android:textSize="14sp"
              android:background="@android:color/holo_red_light"
              android:layout_height="40dp">


          </TextView>

          現(xiàn)在我們就用include標(biāo)簽,將其添加到ViewOptimizationActivity的布局中:

          <?xml version="1.0" encoding="utf-8"?>
          <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
              tools:context=".ViewOptimizationActivity">


              <!--include標(biāo)簽的使用-->
              <TextView
                  android:textSize="18sp"
                  android:text="1、include標(biāo)簽的使用"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content" />


              <include
                  android:id="@+id/tv_include1"
                  layout="@layout/layout_include"/>


          </LinearLayout>


          沒(méi)錯(cuò),include的使用就是這么簡(jiǎn)單,只需指明要包含的布局id就行。除此之外,我們還給這個(gè)include標(biāo)簽設(shè)置了一個(gè)id,為了驗(yàn)證它就是layout_include.xml的根布局TextView的id,我們?cè)赩iewOptimizationActivity中初始化TextView,并給它設(shè)置文字:

                  TextView tvInclude1 = findViewById(R.id.tv_include1);
                  tvInclude1.setText("1.1 常規(guī)下的include布局");


          運(yùn)行之后可以可以看到如下布局:


          說(shuō)明我們?cè)O(shè)置的layout和id都是成功的。不過(guò)你可能會(huì)對(duì)id這個(gè)屬性有疑問(wèn):id我可以直接在TextView中設(shè)置啊,為什么重寫它呢?別忘了我們的目的是復(fù)用,當(dāng)你在一個(gè)主布局中使用include標(biāo)簽添加兩個(gè)以上的相同布局時(shí),id相同就會(huì)沖突了,所以重寫它可以讓我們更好地調(diào)用它和它里面的控件。還有一種情況,假如你的主布局是RelateLayout,這時(shí)為了設(shè)置相對(duì)位置,你也需要給它們?cè)O(shè)置不同的id。


          1.2 重寫根布局的布局屬性


          除了id之外,我們還可以重寫寬高、邊距和可見性(visibility)這些布局屬性。但是一定要注意,單單重寫android:layout_height或者android:layout_width是不行,必須兩個(gè)同時(shí)重寫才起作用。包括邊距也是這樣,如果我們想給一個(gè)include進(jìn)來(lái)的布局添加右邊距的話的完整寫法是這樣的:

              <include
                  android:layout_width="match_parent"
                  android:layout_height="40dp"
                  android:layout_marginEnd="40dp"
                  android:id="@+id/tv_include2"
                  layout="@layout/layout_include"/>


          初始化后設(shè)置一段文字就可以看到如下的效果了:


          可以看到,1.2顯然比1.1多了一個(gè)右邊距。

          1.3 控件ID相同時(shí)的處理


          在1.1中我們知道了id屬性可以重寫include布局的根布局id,但對(duì)于根布局里面的布局和控件是無(wú)能為力的,如果這時(shí)一個(gè)布局在主布局中include了多次,那怎么區(qū)別里面的控件呢?

          我們先創(chuàng)建一個(gè)layout_include2.xml的布局,它的根布局是FrameLayout,里面有一個(gè)TextView,它的id是tv_same:

          <?xml version="1.0" encoding="utf-8"?>
          <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:background="@android:color/holo_orange_light"
              android:layout_height="wrap_content">


              <TextView
                  android:gravity="center_vertical"
                  android:id="@+id/tv_same"
                  android:layout_width="match_parent"
                  android:layout_height="50dp" />


          </FrameLayout>

          在主布局中添加進(jìn)去:

          <?xml version="1.0" encoding="utf-8"?>
          <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
              tools:context=".ViewOptimizationActivity">


              <!--include標(biāo)簽的使用-->
              ……

              <include layout="@layout/layout_include2"/>

              <include
                  android:id="@+id/view_same"
                  layout="@layout/layout_include2"/>


          </LinearLayout>

          為了區(qū)分,這里給第二個(gè)layout_include2設(shè)置了id。也許你已經(jīng)反應(yīng)過(guò)來(lái)了,沒(méi)錯(cuò),我們就是要?jiǎng)?chuàng)建根布局的對(duì)象,然后再去初始化里面的控件:

                  TextView tvSame = findViewById(R.id.tv_same);
                  tvSame.setText("1.3 這里的TextView的ID是tv_same");
                  FrameLayout viewSame = findViewById(R.id.view_same);
                  TextView tvSame2 = viewSame.findViewById(R.id.tv_same);
                  tvSame2.setText("1.3 這里的TextView的ID也是tv_same");

          運(yùn)行之后可以看到這樣的效果:


          可見雖然控件的id雖然相同,但是使用起來(lái)是沒(méi)有沖突的。


          2、merge


          include標(biāo)簽雖然解決了布局重用的問(wèn)題,卻也帶來(lái)了另外一個(gè)問(wèn)題:布局嵌套。因?yàn)榘研枰赜玫牟季址诺揭粋€(gè)子布局之后就必須加一個(gè)根布局,如果你的主布局的根布局和你需要include的根布局都是一樣的(比如都是LinearLayout),那么就相當(dāng)于在中間多加了一層多余的布局了。那么有沒(méi)有辦法可以在使用include時(shí)不增加布局層級(jí)呢?答案當(dāng)然是有的,那就是使用merge標(biāo)簽。

          使用merge標(biāo)簽要注意一點(diǎn):必須是一個(gè)布局文件中的根節(jié)點(diǎn),看起來(lái)跟其他布局沒(méi)什么區(qū)別,但它的特別之處在于頁(yè)面加載時(shí)它的不會(huì)繪制的。打個(gè)比方,它就像是布局或者控件的搬運(yùn)工,把“貨物”搬到主布局之后就會(huì)功成身退,不會(huì)占用任何空間,因此也就不會(huì)增加布局層級(jí)了。這正如它的名字一樣,只起“合并”作用。

          2.1 merge常規(guī)使用


          我們來(lái)驗(yàn)證一下,首先創(chuàng)建一個(gè)layout_merge.xml,在根節(jié)點(diǎn)使用merge標(biāo)簽:

          <?xml version="1.0" encoding="utf-8"?>
          <merge xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content">


              <TextView
                  android:id="@+id/tv_merge1"
                  android:text="我是merge中的TextView1"
                  android:background="@android:color/holo_green_light"
                  android:gravity="center"
                  android:layout_width="wrap_content"
                  android:layout_height="40dp" />


              <TextView
                  android:layout_toEndOf="@+id/tv_merge1"
                  android:id="@+id/tv_merge2"
                  android:text="我是merge中的TextView2"
                  android:background="@android:color/holo_blue_light"
                  android:gravity="center"
                  android:layout_width="match_parent"
                  android:layout_height="40dp" />

          </merge>

          這里我使用了一些相對(duì)布局的屬性,原因后面你就知道了。我們接著在ViewOptimizationActivity的布局添加RelativeLayout,然后使用include標(biāo)簽將layout_merge.xml添加進(jìn)去:

              <RelativeLayout
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content">


                  <include
                      android:id="@+id/view_merge"
                      layout="@layout/layout_merge"/>

              </RelativeLayout>

          運(yùn)行出來(lái)的效果圖:



          2.2 merge標(biāo)簽對(duì)布局層級(jí)的影響

          在layout_merge.xml中,我們使用相對(duì)布局的屬性android:layout_toEndOf將藍(lán)色TextView設(shè)置到了綠色TextView的右邊,而layout_merge.xml的父布局是RelativeLayout,所以這個(gè)屬性是起了作用了,merge標(biāo)簽不會(huì)影響里面的控件,也不會(huì)增加布局層級(jí)。

          如果你還不放心,可以用Android Studio來(lái)檢查。我用的Android Studio是3.1版本的,可以通過(guò)Layout Inspector查看布局層級(jí),不過(guò)記得要先在真機(jī)或者模擬器上把項(xiàng)目跑起來(lái)。依次點(diǎn)擊Tools-Layout Inspector,然后選擇你要查看的Activity,就可以看到如下的層級(jí)圖:



          可以看到RelativeLayout下面直接就是兩個(gè)TextView了, merge標(biāo)簽并沒(méi)有增加布局層級(jí)。從這里也可以看出merge的局限性,即你需要明確將merge里面的布局和控件include到什么類型的布局中,才能提前設(shè)置好merge里面的布局和控件的位置。

          2.3 merge的ID


          在學(xué)習(xí)include標(biāo)簽時(shí)我們知道,它的android:id屬性可以重寫被include的根布局id,但如果根節(jié)點(diǎn)是merge呢?前面說(shuō)了merge并不會(huì)作為一個(gè)布局繪制出來(lái),所以這里給它設(shè)置id是不起作用的。我們可以在它的父布局RelativeLayout中再加一個(gè)TextView,使用android:layout_below屬性把設(shè)置到layout_merge下面:

              <RelativeLayout
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content">


                  <include
                      android:id="@+id/view_merge"
                      layout="@layout/layout_merge"/>


                  <TextView
                      android:text="我不是merge中的布局"
                      android:layout_below="@+id/view_merge"
                      android:background="@android:color/holo_purple"
                      android:gravity="center"
                      android:layout_width="match_parent"
                      android:layout_height="40dp"/>

              </RelativeLayout>

          運(yùn)行之后你會(huì)發(fā)現(xiàn)新加的TextView會(huì)把merge布局蓋住,沒(méi)有像預(yù)期那樣在其下方。如果把a(bǔ)ndroid:layout_below中的id改為layout_merge.xml中任一TextView的id(比如tv_merge1),運(yùn)行之后就可以看到如下效果:


          這也符合2.2中的情況,即父布局RelativeLayout下級(jí)布局就是include進(jìn)去的TextView了。

          3、ViewStub


          你一定遇到這樣的情況:頁(yè)面中有些布局在初始化時(shí)沒(méi)必要顯示,但是又不得不事先在布局文件中寫好,雖然設(shè)置成了invisible或gone,但是在初始化時(shí)還是會(huì)加載,這無(wú)疑會(huì)影響頁(yè)面加載速度。針對(duì)這一情況,Android為我們提供了一個(gè)利器————ViewStub。這是一個(gè)不可見的,大小為0的視圖,具有懶加載的功能,它存在于視圖層級(jí)中,但只會(huì)在setVisibility()和inflate()方法調(diào)用只會(huì)才會(huì)填充視圖,所以不會(huì)影響初始化加載速度。它有以下三個(gè)重要屬性:

          • android:layout:ViewStub需要填充的視圖名稱,為“R.layout.xx”的形式;
          • android:inflateId:重寫被填充的視圖的父布局id。
          與include標(biāo)簽不同,ViewStub的android:id屬性是設(shè)置ViewStub本身id的,而不是重寫布局id,這一點(diǎn)可不要搞錯(cuò)了。另外,ViewStub還提供了OnInflateListener接口,用于監(jiān)聽布局是否已經(jīng)加載了。

          3.1 填充布局的正確方式


          我們先創(chuàng)建一個(gè)layout_view_stub.xml,里面放置一個(gè)Switch開關(guān):

          <?xml version="1.0" encoding="utf-8"?>
          <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:background="@android:color/holo_blue_dark"
              android:layout_height="100dp">

              <Switch
                  android:id="@+id/sw"
                  android:layout_gravity="center"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content" />

          </FrameLayout>

          然后在Activity的布局中修改如下:

          <?xml version="1.0" encoding="utf-8"?>
          <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
              tools:context=".ViewOptimizationActivity">


              <!--ViewStub標(biāo)簽的使用-->
              <TextView
                  android:textSize="18sp"
                  android:text="3、ViewStub標(biāo)簽的使用"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content" />


              <ViewStub
                  android:id="@+id/view_stub"
                  android:inflatedId="@+id/view_inflate"
                  android:layout="@layout/layout_view_stub"
                  android:layout_width="match_parent"
                  android:layout_height="100dp" />

              <LinearLayout
                  android:orientation="horizontal"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content">


                  <Button
                      android:text="顯示"
                      android:id="@+id/btn_show"
                      android:layout_weight="1"
                      android:layout_width="0dp"
                      android:layout_height="wrap_content" />


                  <Button
                      android:text="隱藏"
                      android:id="@+id/btn_hide"
                      android:layout_weight="1"
                      android:layout_width="0dp"
                      android:layout_height="wrap_content" />


                  <Button
                      android:text="操作父布局控件"
                      android:id="@+id/btn_control"
                      android:layout_width="wrap_content"
                      android:layout_height="wrap_content" />

              </LinearLayout>
          </LinearLayout>

          在ViewOptimizationActivity中監(jiān)聽ViewStub的填充事件:

                  viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
                      @Override
                      public void onInflate(ViewStub viewStub, View view) {
                          Toast.makeText(ViewOptimizationActivity.this"ViewStub加載了", Toast.LENGTH_SHORT).show();
                      }
                  });

          然后通過(guò)按鈕事件來(lái)填充和顯示layout_view_stub:

              @Override
              public void onClick(View view) {
                  switch (view.getId()) {
                      case R.id.btn_show:
                          viewStub.inflate();
                          break;
                      case R.id.btn_hide:
                          viewStub.setVisibility(View.GONE);
                          break;
                      default:
                          break;
                  }
              }

          運(yùn)行之后,點(diǎn)擊“顯示”按鈕,layout_view_stub顯示了,并彈出"ViewStub加載了"的Toast;點(diǎn)擊“隱藏”按鈕,布局又隱藏掉了,但是再點(diǎn)擊一下“顯示”按鈕,頁(yè)面居然卻閃退了,查看日志,發(fā)現(xiàn)拋出了一個(gè)異常:

          java.lang.IllegalStateException: ViewStub must have a non-null ViewGroup viewParent


          我們打開ViewStub的源碼,看看是哪里拋出這個(gè)異常的。很快我們就可以定位到是在inflate()方法中

              public View inflate() {
                  final ViewParent viewParent = getParent();

                  if (viewParent != null && viewParent instanceof ViewGroup) {
                      if (mLayoutResource != 0) {
                          final ViewGroup parent = (ViewGroup) viewParent;
                          final View view = inflateViewNoAdd(parent);
                          replaceSelfWithView(view, parent);

                          mInflatedViewRef = new WeakReference<>(view);
                          if (mInflateListener != null) {
                              mInflateListener.onInflate(this, view);
                          }

                          return view;
                      } else {
                          throw new IllegalArgumentException("ViewStub must have a valid layoutResource");
                      }
                  } else {
                      throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");
                  }
              }

          注意到if語(yǔ)句中有一個(gè)replaceSelfWithView()方法,聽這名字就讓人有一種不祥的預(yù)感了,點(diǎn)進(jìn)去一看:

              private void replaceSelfWithView(View view, ViewGroup parent) {
                  final int index = parent.indexOfChild(this);
                  parent.removeViewInLayout(this);

                  final ViewGroup.LayoutParams layoutParams = getLayoutParams();
                  if (layoutParams != null) {
                      parent.addView(view, index, layoutParams);
                  } else {
                      parent.addView(view, index);
                  }
              }

          果然,ViewStub在這里調(diào)用了removeViewInLayout()方法把自己從布局移除了。到這里我們就明白了,ViewStub在填充布局成功之后就會(huì)自我銷毀,再次調(diào)用inflate()方法就會(huì)拋出IllegalStateException異常了。此時(shí)如果想要再次顯示布局,可以調(diào)用setVisibility()方法。

          為了避免inflate()方法多次調(diào)用,我們可以采用如下三種方式:

          3.1.1 捕獲異常


          我們可以捕獲異常,同時(shí)調(diào)用setVisibility()方法顯示布局。

                          try {
                              viewStub.inflate();
                          } catch (IllegalStateException e) {
                              Log.e("Tag",e.toString());
                              view.setVisibility(View.VISIBLE);
                          }

          3.1.2 通過(guò)監(jiān)聽ViewStub的填充事件

          聲明一個(gè)布爾值變量isViewStubShow,默認(rèn)值為false,布局填充成功之后,在監(jiān)聽事件onInflate方法中將其置為true。

                          if (isViewStubShow){
                              viewStub.setVisibility(View.VISIBLE);
                          }else {
                              viewStub.inflate();
                          }


          3.1.3 直接調(diào)用setVisibility()方法


          我先來(lái)看看ViewStub中的setVisibility()源碼:

              public void setVisibility(int visibility{
                  if (mInflatedViewRef != null) {
                      View view = mInflatedViewRef.get();
                      if (view != null) {
                          view.setVisibility(visibility);
                      } else {
                          throw new IllegalStateException("setVisibility called on un-referenced view");
                      }
                  } else {
                      super.setVisibility(visibility);
                      if (visibility == VISIBLE || visibility == INVISIBLE) {
                          inflate();
                      }
                  }
              }

          可以看到,在inflate()初始化mInflatedViewRef之前,如果設(shè)置visibility為VISIBLE的話是會(huì)調(diào)用inflate()方法的,在mInflatedViewRef不為null之后就不會(huì)再去調(diào)用inflate()了。

          3.2 viewStub.getVisibility()為何總是等于0?


          在顯示ViewStub中的布局時(shí),你可能會(huì)采取如下的寫法:

                          if (viewStub.getVisibility() == View.GONE){
                              viewStub.setVisibility(View.VISIBLE);
                          }else {
                              viewStub.setVisibility(View.GONE);
                          }

          恭喜你,踩到一個(gè)大坑了。這樣寫你會(huì)發(fā)現(xiàn)點(diǎn)擊“顯示”按鈕后ViewStub里面的布局不會(huì)再顯示出來(lái),也就是說(shuō)if語(yǔ)句里面的代碼沒(méi)有執(zhí)行。如果你將viewStub.getVisibility()的值打印出來(lái),就會(huì)看到它始終為0,這恰恰是View.VISIBLE的值。奇怪,我們明明寫了viewStub.setVisibility(View.GONE),layout_view_stub也隱藏了,為什么ViewStub的狀態(tài)還是可見呢?

          重新回到3.1.3,看看ViewStub中的setVisibility()源碼,首先判斷弱引用對(duì)象mInflatedViewRef是否為空,不為空則取出存放進(jìn)去的對(duì)象,也就是我們ViewStub中的View,然后調(diào)用了view的setVisibility()方法,mInflatedViewRef為空時(shí),則判斷visibility為VISIBLE或INVISIBLE時(shí)調(diào)用inflate()方法填充布局,如果為GONE的話則不予處理。這樣一來(lái),在mInflatedViewRef不為空,也就是已經(jīng)填充了布局的情況下,ViewStub中的setVisibility()方法實(shí)際上是在設(shè)置內(nèi)部視圖的可見性,而不是ViewStub本身。這樣的設(shè)計(jì)其實(shí)也符合ViewStub的特性,即填充布局之后就自我銷毀了,給其設(shè)置可見性是沒(méi)有意義的。

          3.3 操作布局控件


          仔細(xì)比較一下,其實(shí)ViewStub就像是一個(gè)懶惰的include,我們需要它加載時(shí)才加載。要操作布局里面的控件也跟include一樣,你可以先初始化ViewStub中的布局中再初始化控件:

                          //1、初始化被inflate的布局后再初始化其中的控件,
                          FrameLayout frameLayout = findViewById(R.id.view_inflate);//android:inflatedId設(shè)置的id
                          Switch sw = frameLayout.findViewById(R.id.sw);
                          sw.toggle();

          如果主布局中控件的id沒(méi)有沖突,可以直接初始化控件使用:

                          //2、直接初始化控件
                          Switch sw = findViewById(R.id.sw);
                          sw.toggle();

          好了,關(guān)于ViewStub的知識(shí)就講這么多了。


          后記


          原本以為知識(shí)點(diǎn)不難,應(yīng)該可以寫得快一點(diǎn)的,沒(méi)想到還是斷斷續(xù)續(xù)寫了四五天,寫得自己都覺(jué)得有點(diǎn)累了。希望還是能對(duì)大家有點(diǎn)幫助,不足之處還望指正。下面使用思維導(dǎo)圖總計(jì)一下,并給出GitHub上的源碼吧。



          瀏覽 66
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产寡妇亲子伦一区二区三区四区 | 91精品久久久久久久不卡 | 大香蕉最新网址 | 大香蕉第一页 | 操逼黄视频 |