国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Android進階之Handle和Looper消息機制原理和源碼分析(不走彎路)

移動開發 Android
App中一般多會有多個線程,多線程之間難免需要進行通信。在我們平時開發中線程通信用的最多的就是Handler,例如子線程進行數據處理,在主線程中進行UI更新。

[[417195]]

本文轉載自微信公眾號「Android開發編程」,作者Android開發編程 。轉載本文請聯系Android開發編程公眾號。

前言

App中一般多會有多個線程,多線程之間難免需要進行通信。在我們平時開發中線程通信用的最多的就是Handler,例如子線程進行數據處理,在主線程中進行UI更新。

當然了除了Handler這種通信方式外,線程間的通信還有其他幾種方式:管道Pip、共享內存、通過文件及數據庫等。

我們主要來看下Handler以及其實現原理

一、Looper死循環詳解

1、死循環為什么不會導致應用卡死ANR

線程默認沒有Looper的,如果需要使用Handler就必須為線程創建Looper。

我們經常提到的主線程,也叫UI線程,它就是ActivityThread,ActivityThread被創建時就會初始化Looper,這也是在主線程中默認可以使用Handler的原因。

  1. public static void main(String[] args) { 
  2.     Looper.prepareMainLooper();//創建Looper和MessageQueue對象,用于處理主線程的消息 
  3.     ActivityThread thread = new ActivityThread(); 
  4.     thread.attach(false);//建立Binder通道 (創建新線程) 
  5.     if (sMainThreadHandler == null) { 
  6.         sMainThreadHandler = thread.getHandler(); 
  7.     } 
  8.     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 
  9.     Looper.loop(); 
  10.     //如果能執行下面方法,說明應用崩潰或者是退出了... 
  11.     throw new RuntimeException("Main thread loop unexpectedly exited"); 

這個死循環會不會導致應用卡死,即使不會的話,它會慢慢的消耗越來越多的資源嗎?

①對于線程即是一段可執行的代碼,當可執行代碼執行完成后,線程生命周期便該終止了,線程退出。而對于主線程,我們是絕不希望會被運行一段時間,自己就退出,那么如何保證能一直存活呢?簡單做法就是可執行代碼是能一直執行下去的,死循環便能保證不會被退出,例如,binder線程也是采用死循環的方法,通過循環方式不同與Binder驅動進行讀寫操作,當然并非簡單地死循環,無消息時會休眠。但這里可能又引發了另一個問題,既然是死循環又如何去處理其他事務呢?通過創建新線程的方式。真正會卡死主線程的操作是在回調方法onCreate/onStart/onResume等操作時間過長,會導致掉幀,甚至發生ANR,looper.loop本身不會導致應用卡死。

②主線程的死循環一直運行是不是特別消耗CPU資源呢?其實不然,這里就涉及到Linux pipe/epoll機制,簡單說就是在主線程的MessageQueue沒有消息時,便阻塞在loop的queue.next()中的nativePollOnce()方法里,此時主線程會釋放CPU資源進入休眠狀態,直到下個消息到達或者有事務發生,通過往pipe管道寫端寫入數據來喚醒主線程工作。這里采用的epoll機制,是一種IO多路復用機制,可以同時監控多個描述符,當某個描述符就緒(讀或寫就緒),則立刻通知相應程序進行讀或寫操作,本質同步I/O,即讀寫是阻塞的。所以說,主線程大多數時候都是處于休眠狀態,并不會消耗大量CPU資源

2、主線程的消息循環機制是什么

主線程進入死循環之前便創建了新binder線程,在代碼ActivityThread.main()中:

  1. public static void main(String[] args) { 
  2. //創建Looper和MessageQueue對象,用于處理主線程的消息 
  3.  Looper.prepareMainLooper(); 
  4.  //創建ActivityThread對象 
  5.  ActivityThread thread = new ActivityThread();  
  6.  //建立Binder通道 (創建新線程) 
  7.  thread.attach(false); 
  8.  Looper.loop(); //消息循環運行 
  9.  throw new RuntimeException("Main thread loop unexpectedly exited"); 
  • Activity的生命周期都是依靠主線程的Looper.loop,當收到不同Message時則采用相應措施:一旦退出消息循環,那么你的程序也就可以退出了。從消息隊列中取消息可能會阻塞,取到消息會做出相應的處理。如果某個消息處理時間過長,就可能會影響UI線程的刷新速率,造成卡頓的現象。
  • thread.attach(false)方法函數中便會創建一個Binder線程(具體是指ApplicationThread,Binder的服務端,用于接收系統服務AMS發送來的事件),該Binder線程通過Handler將Message發送給主線程。「Activity 啟動過程」比如收到msg=H.LAUNCH_ACTIVITY,則調用ActivityThread.handleLaunchActivity()方法,最終會通過反射機制,創建Activity實例,然后再執行Activity.onCreate()等方法;
  • 再比如收到msg=H.PAUSE_ACTIVITY,則調用ActivityThread.handlePauseActivity()方法,最終會執行Activity.onPause()等方法。
  • 主線程的消息又是哪來的呢?當然是App進程中的其他線程通過Handler發送給主線程

二、Handler機制原理詳解

Handler機制,主要牽涉到的類有如下四個,它們分工明確,但又相互作用

Message:消息

Hanlder:消息的發起者

Looper:消息的遍歷者

MessageQueue:消息隊列

1、 Looper.prepare()

  1. public static void prepare() { 
  2.         prepare(true); 
  3.     } 
  4.     private static void prepare(boolean quitAllowed) { 
  5.         // 規定了一個線程只有一個Looper,也就是一個線程只能調用一次Looper.prepare() 
  6.         if (sThreadLocal.get() != null) { 
  7.             throw new RuntimeException("Only one Looper may be created per thread"); 
  8.         } 
  9.         // 如果當前線程沒有Looper,那么就創建一個,存到sThreadLocal中 
  10.         sThreadLocal.set(new Looper(quitAllowed)); 
  11.     } 

從上面的代碼可以看出,一個線程最多只有一個Looper對象。當沒有Looper對象時,去創建一個Looper,并存放到sThreadLocal中,sThreadLocal是一個static的ThreadLocal對象,關于它的詳細使用,以后有機會再介紹,這里只要知道,它存儲了Looper對象的副本,并且可以通過它取得當前線程在之前存儲的Looper的副本。如下圖:

接下來看Looper的構造方法:

  1. private Looper(boolean quitAllowed) { 
  2.         // 創建了MessageQueue,并供Looper持有 
  3.         mQueue = new MessageQueue(quitAllowed); 
  4.         // 讓Looper持有當前線程對象 
  5.         mThread = Thread.currentThread(); 
  6.     } 

這里主要就是創建了消息隊列MessageQueue,并讓它供Looper持有,因為一個線程最大只有一個Looper對象,所以一個線程最多也只有一個消息隊列。然后再把當前線程賦值給mThread。

MessageQueue的構造方法沒有什么可講的,它就是一個消息隊列,用于存放Message。

所以Looper.prepare()的作用主要有以下三點:

  • 創建Looper對象
  • 創建MessageQueue對象,并讓Looper對象持有
  • 讓Looper對象持有當前線程

2、new Handler()

Handler有很多構造方法,主要是提供自定義Callback、Looper等,我們先從最簡單的無參構造方法看起:

  1. public Handler() { 
  2.         this(nullfalse); 
  3.     } 
  4.     public Handler(Callback callback, boolean async) { 
  5.       // 不相關代碼 
  6.        ...... 
  7.         //得到當前線程的Looper,其實就是調用的sThreadLocal.get 
  8.         mLooper = Looper.myLooper(); 
  9.         // 如果當前線程沒有Looper就報運行時異常 
  10.         if (mLooper == null) { 
  11.             throw new RuntimeException( 
  12.                 "Can't create handler inside thread that has not called Looper.prepare()"); 
  13.         } 
  14.         // 把得到的Looper的MessagQueue讓Handler持有 
  15.         mQueue = mLooper.mQueue; 
  16.         // 初始化Handler的Callback,其實就是最開始圖中的回調方法的2 
  17.         mCallback = callback; 
  18.         mAsynchronous = async; 
  19.     } 

首先,調用了Looper.myLooper,其實就是調用sThreadLocal.get方法,會得到當前線程調用sThreadLocal.set保存的Looper對象,讓Handler持有它。接下來就會判斷得到的Looper對象是否為空,如果為空,就會報

"Can't create handler inside thread that has not called Looper.prepare(),這不就是我們之前在沒有調用Looper.prepare就在子線程中創建Handler時報的錯誤嘛。的確,當我們沒有調用Looper.prepare(),則當前線程中是沒有Looper對象的。

然后,讓Handler持有得到的Looper對象的MessageQueue和設置處理回調的Callback對象(最開始圖中的回調方法2)。

到這里,默認的Handler的創建過程就結束了,主要有以下幾點:

  • 創建Handler對象
  • 得到當前線程的Looper對象,并判斷是否為空
  • 讓創建的Handler對象持有Looper、MessageQueu、Callback的引用

3、Looper.loop()

  1. public static void loop() { 
  2.         // 得到當前線程的Looper對象 
  3.         final Looper me = myLooper(); 
  4.         if (me == null) { 
  5.             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); 
  6.         } 
  7.         // 得到當前線程的MessageQueue對象 
  8.         final MessageQueue queue = me.mQueue; 
  9.         // 無關代碼 
  10.         ...... 
  11.         // 死循環 
  12.         for (;;) { 
  13.             // 不斷從當前線程的MessageQueue中取出Message,當MessageQueue沒有元素時,方法阻塞 
  14.             Message msg = queue.next(); // might block 
  15.             if (msg == null) { 
  16.                 // No message indicates that the message queue is quitting. 
  17.                 return
  18.             } 
  19.             // Message.target是Handler,其實就是發送消息的Handler,這里就是調用它的dispatchMessage方法 
  20.             msg.target.dispatchMessage(msg); 
  21.             // 回收Message 
  22.             msg.recycleUnchecked(); 
  23.         } 
  24.     } 

首先還是判斷了當前線程是否有Looper,然后得到當前線程的MessageQueue。接下來,就是最關鍵的代碼了,寫了一個死循環,不斷調用MessageQueue的next方法取出MessageQueue中的Message,注意,當MessageQueue中沒有消息時,next方法會阻塞,導致當前線程掛起,后面會講到。

拿到Message以后,會調用它的target的dispatchMessage方法,這個target其實就是發送消息時用到的Handler。所以就是調用Handler的dispatchMessage方法,代碼如下:

  1. public void dispatchMessage(Message msg) { 
  2.         // 如果msg.callback不是null,則調用handleCallback 
  3.         if (msg.callback != null) { 
  4.             handleCallback(msg); 
  5.         } else { 
  6.             // 如果 mCallback不為空,則調用mCallback.handleMessage方法 
  7.             if (mCallback != null) { 
  8.                 if (mCallback.handleMessage(msg)) { 
  9.                     return
  10.                 } 
  11.             } 
  12.             // 調用Handler自身的handleMessage,這就是我們常常重寫的那個方法 
  13.             handleMessage(msg); 
  14.         } 
  15.     } 

可以看出,這個方法就是從MessageQueue中取出Message以后,進行分發處理。

首先,判斷msg.callback是不是空,其實msg.callback是一個Runnable對象,是Handler.post方式傳遞進來的參數,后面會講到。而hanldeCallback就是調用的Runnable的run方法。

然后,判斷mCallback是否為空,這是一個Handler.Callback的接口類型,之前說了Handler有多個構造方法,可以提供設置Callback,如果這里不為空,則調用它的hanldeMessage方法,注意,這個方法有返回值,如果返回了true,表示已經處理 ,不再調用Handler的handleMessage方法;如果mCallback為空,或者不為空但是它的handleMessage返回了false,則會繼續調用Handler的handleMessage方法,該方法就是我們經常重寫的那個方法。

關于從MessageQueue中取出消息以后的分發,如下面的流程圖所示:

所以Looper.loop的作用就是:

從當前線程的MessageQueue從不斷取出Message,并調用其相關的回調方法。

4、發送消息

使用Handler發送消息主要有兩種,一種是sendXXXMessage方式,還有一個postXXX方式,不過兩種方式最后都會調用到sendMessageDelayed方法,所以我們就以最簡單的sendMessage方法來分析。

我們先來看Handler的sendMessage方法:

  1. public final boolean sendMessage(Message msg) 
  2.         return sendMessageDelayed(msg, 0); 
  3.     } 
  4.     public final boolean sendMessageDelayed(Message msg, long delayMillis) 
  5.         if (delayMillis < 0) { 
  6.             delayMillis = 0; 
  7.         } 
  8.         return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); 
  9.     } 
  10.     public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 
  11.         // 這里拿到的MessageQueue其實就是創建時的MessageQueue,默認情況是當前線程的Looper對象的MessageQueue 
  12.         // 也可以指定 
  13.         MessageQueue queue = mQueue; 
  14.         if (queue == null) { 
  15.             RuntimeException e = new RuntimeException( 
  16.                     this + " sendMessageAtTime() called with no mQueue"); 
  17.             Log.w("Looper", e.getMessage(), e); 
  18.             return false
  19.         } 
  20.         // 調用enqueueMessage,把消息加入到MessageQueue中 
  21.         return enqueueMessage(queue, msg, uptimeMillis); 
  22.     } 
  23. 主要實現是調用enqueueMessage來實現的,看看該方法: 
  24.     private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { 
  25.         // 把當前Handler對象,也就是發起消息的handler作為Message的target屬性 
  26.         msg.target = this; 
  27.         if (mAsynchronous) { 
  28.             msg.setAsynchronous(true); 
  29.         } 
  30.         // 調用MessageQueue中的enqueueMessage方法 
  31.         return queue.enqueueMessage(msg, uptimeMillis); 
  32.     } 

首先,把當前Handler作為Message的target屬性,方便Looper從MessageQueue中取出Message時進行消息處理。然后調用了MessageQueue的enqueueMessage方法,把handler發送的消息加入到MessageQueue,供Looper去取出來處理。我們記下來看看。

MessageQueue的enqueueMessage方法:

  1. MessageQueue的enqueueMessage方法: 
  2.    boolean enqueueMessage(Message msg, long when) { 
  3.         if (msg.target == null) { 
  4.             throw new IllegalArgumentException("Message must have a target."); 
  5.         } 
  6.         // 一個Message,只能發送一次 
  7.         if (msg.isInUse()) { 
  8.             throw new IllegalStateException(msg + " This message is already in use."); 
  9.         } 
  10.         synchronized (this) { 
  11.             if (mQuitting) { 
  12.                 IllegalStateException e = new IllegalStateException( 
  13.                         msg.target + " sending message to a Handler on a dead thread"); 
  14.                 Log.w("MessageQueue", e.getMessage(), e); 
  15.                 msg.recycle(); 
  16.                 return false
  17.             } 
  18.             // 標記Message已經使用了 
  19.             msg.markInUse(); 
  20.             msg.when = when
  21.             // 得到當前消息隊列的頭部 
  22.             Message p = mMessages; 
  23.             boolean needWake; 
  24.             // 我們這里when為0,表示立即處理的消息 
  25.             if (p == null || when == 0 || when < p.when) { 
  26.                 // 把消息插入到消息隊列的頭部 
  27.                 msg.next = p; 
  28.                 mMessages = msg; 
  29.                 needWake = mBlocked; 
  30.             } else { 
  31.                 // 根據需要把消息插入到消息隊列的合適位置,通常是調用xxxDelay方法,延時發送消息 
  32.                 needWake = mBlocked && p.target == null && msg.isAsynchronous(); 
  33.                 Message prev; 
  34.                 for (;;) { 
  35.                     prev = p; 
  36.                     p = p.next
  37.                     if (p == null || when < p.when) { 
  38.                         break; 
  39.                     } 
  40.                     if (needWake && p.isAsynchronous()) { 
  41.                         needWake = false
  42.                     } 
  43.                 } 
  44.                 // 把消息插入到合適位置 
  45.                 msg.next = p; // invariant: p == prev.next 
  46.                 prev.next = msg; 
  47.             } 
  48.             // 如果隊列阻塞了,則喚醒 
  49.             if (needWake) { 
  50.                 nativeWake(mPtr); 
  51.             } 
  52.         } 
  53.         return true
  54.     } 

首先,判斷了Message是否已經使用過了,如果使用過,則直接拋出異常,這是可以理解的,如果MessageQueue中已經存在一個Message,但是還沒有得到處理,這時候如果再發送一次該Message,可能會導致處理前一個Message時,出現問題。

然后,會判斷when,它是表示延遲的時間,我們這里沒有延時,所以為0,滿足if條件。把消息插入到消息隊列的頭部。如果when不為0,則需要把消息加入到消息隊列的合適位置。

最后會去判斷當前線程是否已經阻塞了,如果阻塞了,則需要調用本地方法去喚醒它。

以上是sendMessage的全部過程,其實就是把Message加入到MessageQueue的合適位置。那我們來簡單看看post系列方法:

  1. public final boolean post(Runnable r) 
  2.       return  sendMessageDelayed(getPostMessage(r), 0); 
  3.    } 
  4.    private static Message getPostMessage(Runnable r) { 
  5.        // 構造一個Message,并讓其callback執行傳來的Runnable 
  6.        Message m = Message.obtain(); 
  7.        m.callback = r; 
  8.        return m; 
  9.    } 

可以看到,post方法只是先調用了getPostMessage方法,用Runnable去封裝一個Message,然后就調用了sendMessageDelayed,把封裝的Message加入到MessageQueue中。

所以使用handler發送消息的本質都是:把Message加入到Handler中的MessageQueue中去。

三、Handler 是如何能夠線程切換

Handler創建的時候會采用當前線程的Looper來構造消息循環系統,Looper在哪個線程創建,就跟哪個線程綁定,并且Handler是在他關聯的Looper對應的線程中處理消息的。

那么Handler內部如何獲取到當前線程的Looper呢—–ThreadLocal。

ThreadLocal可以在不同的線程中互不干擾的存儲并提供數據,通過ThreadLocal可以輕松獲取每個線程的Looper。當然需要注意的是:

①線程是默認沒有Looper的,如果需要使用Handler,就必須為線程創建Looper。我們經常提到的主線程,也叫UI線程,它就是ActivityThread;

②ActivityThread被創建時就會初始化Looper,這也是在主線程中默認可以使用Handler的原因。

系統為什么不允許在子線程中訪問UI?這是因為Android的UI控件不是線程安全的,如果在多線程中并發訪問可能會導致UI控件處于不可預期的狀態,那么為什么系統不對UI控件的訪問加上鎖機制呢?缺點有兩個:①首先加上鎖機制會讓UI訪問的邏輯變得復雜 ②鎖機制會降低UI訪問的效率,因為鎖機制會阻塞某些線程的執行。所以最簡單且高效的方法就是采用單線程模型來處理UI操作。

四、Handler造成內存泄露

1、引起內存泄露原因

Java使用有向圖機制,通過GC自動檢查內存中的對象(什么時候檢查由虛擬機決定),如果GC發現一個或一組對象為不可到達狀態,則將該對象從內存中回收。也就是說,一個對象不被任何引用所指向,則該對象會在被GC發現的時候被回收;另外,如果一組對象中只包含互相的引用,而沒有來自它們外部的引用(例如有兩個對象A和B互相持有引用,但沒有任何外部對象持有指向A或B的引用),這仍然屬于不可到達,同樣會被GC回收。

Android中使用Handler造成內存泄露的原因

  1. Handler mHandler = new Handler() { 
  2.     @Override 
  3.     public void handleMessage(Message msg) { 
  4.         mImageView.setImageBitmap(mBitmap); 
  5.     } 

上面是一段簡單的Handler的使用。當使用內部類(包括匿名類)來創建Handler的時候,Handler對象會隱式地持有一個外部類對象(通常是一個Activity)的引用(不然你怎么可能通過Handler來操作Activity中的View?)。而Handler通常會伴隨著一個耗時的后臺線程(例如從網絡拉取圖片)一起出現,這個后臺線程在任務執行完畢(例如圖片下載完畢)之后,通過消息機制通知Handler,然后Handler把圖片更新到界面。然而,如果用戶在網絡請求過程中關閉了Activity,正常情況下,Activity不再被使用,它就有可能在GC檢查時被回收掉,但由于這時線程尚未執行完,而該線程持有Handler的引用(不然它怎么發消息給Handler?),這個Handler又持有Activity的引用,就導致該Activity無法被回收(即內存泄露),直到網絡請求結束(例如圖片下載完畢)。另外,如果你執行了Handler的postDelayed()方法,該方法會將你的Handler裝入一個Message,并把這條Message推到MessageQueue中,那么在你設定的delay到達之前,會有一條MessageQueue -> Message -> Handler -> Activity的鏈,導致你的Activity被持有引用而無法被回收。

2、解決方法

①在關閉Activity的時候停掉你的后臺線程。線程停掉了,就相當于切斷了Handler和外部連接的線,Activity自然會在合適的時候被回收;

②如果你的Handler是被delay的Message持有了引用,那么使用相應的Handler的removeCallbacks()方法,把消息對象從消息隊列移除就行了;

③將Handler聲明為靜態類,由于Handler不再持有外部類對象的引用,導致程序不允許你在Handler中操作Activity中的對象了。所以你需要在Handler中增加一個對Activity的弱引用(WeakReference)

  1. private static class MyHandler extends Handler {   
  2.         WeakReference<MainActivity> mActivity;   
  3.         MyHandler(MainActivity mActivity){   
  4.             this.mActivity = new WeakReference<MainActivity>(mActivity);   
  5.         }   
  6.         @Override   
  7.         public void handleMessage(Message msg) {   
  8.             switch(msg.what){   
  9.             case IMAGE_FAILURE:   
  10.                 Toast.makeText(mActivity.get()   
  11.                         , "Image Failure", Toast.LENGTH_LONG).show();   
  12.                 break;           
  13.             }   
  14.         }   
  15.     }  

總結

Handler消息機制主要的四個類的功能:

  • Message:信息的攜帶者,持有了Handler,存在MessageQueue中,一個線程可以有多個。
  • Hanlder:消息的發起者,發送Message以及消息處理的回調實現,一個線程可以有多個Handler對象。
  • Looper:消息的遍歷者,從MessageQueue中循環取出Message進行處理,一個線程最多只有一個。
  • MessageQueue:消息隊列,存放了Handler發送的消息,供Looper循環取消息,一個線程最多只有一個。

 

責任編輯:武曉燕 來源: Android開發編程
相關推薦

2021-09-09 06:55:43

AndroidViewDragHel原理

2021-08-17 13:41:11

AndroidView事件

2021-09-01 06:48:16

AndroidGlide緩存

2012-04-16 09:50:08

2015-09-24 17:41:15

Windows 10

2009-06-25 13:37:54

2021-10-15 09:19:17

AndroidSharedPrefe分析源碼

2021-09-06 13:12:05

前端JavaScript編程

2021-09-05 07:35:58

lifecycleAndroid組件原理

2014-05-22 15:38:27

Android消息處理機制Looper

2014-05-22 15:07:44

Android消息處理機制Looper

2014-05-22 15:41:59

Android消息處理機制Looper

2014-05-22 15:48:50

Android消息處理機制Looper

2014-05-22 15:04:00

Android消息處理機制Looper

2014-05-22 15:00:16

Android消息處理機制Looper

2021-09-02 07:00:01

Glide流程Android

2014-05-22 15:18:25

Android消息處理機制Looper

2014-05-22 15:15:53

Android消息處理機制Looper

2014-05-22 15:33:31

Android消息處理機制Looper

2014-05-22 15:45:58

Android消息處理機制Looper
點贊
收藏

51CTO技術棧公眾號

日本伊人色综合网| 久久91超碰青草是什么| 美国毛片一区二区三区| 国产九九精品| 久久日韩精品一区二区五区| 色av中文字幕一区| 亚洲天堂免费电影| 中文字幕va一区二区三区| 亚洲性夜色噜噜噜7777| 最新亚洲国产精品| 国产不卡人人| 欧美变态tickle挠乳网站| 国产午夜视频在线观看| 色综合天天综合色综合av| 日本高清中文字幕| 亚洲一区二区偷拍精品| 女人体1963| 午夜久久电影网| 国内在线精品| 欧美日韩视频在线第一区| 岛国大片在线观看| 在线不卡a资源高清| 91麻豆免费在线视频| 欧美成人性福生活免费看| 青草在线视频| 亚洲电影第1页| xxxxxx欧美| 欧美另类交人妖| 深爱激情综合网| 91精品视频在线免费观看| 午夜国产一区| 日韩少妇中文字幕| 国产精品自产自拍| 日韩av资源在线| 亚洲美女精品一区| 成人全视频高清免费观看| 精品国产1区2区3区| 91伊人久久| 国外色69视频在线观看| 国产精品精品| 久久伊人一区| 国产乱色国产精品免费视频| 天天摸天天碰天天添| 欧美韩国日本综合| 夜色福利刺激| 91麻豆精品国产91久久久| 周于希免费高清在线观看 | 国产成人精品一区二区三区视频| 久久香蕉国产线看观看av| 亚洲成aⅴ人片久久青草影院| 亚洲aaaaaa| 麻豆国产精品一区二区三区 | 中文在线日韩| 亚洲a∨一区二区三区| 97久久超碰国产精品电影| 午夜爽爽视频| 精品久久久久一区二区国产| 久久精品一级| 亚洲综合大片69999| 国产精品乡下勾搭老头1| 成年人在线免费观看视频网站| 欧美久久久久中文字幕| 国产精品视频一区视频二区| 91偷拍精品一区二区三区| 国产最新精品精品你懂的| 激情 小说 亚洲 图片: 伦| 在线一区二区三区四区五区| 国产三级一区| 国产亚洲精品美女久久久m| 91免费国产视频网站| 国产对白叫床清晰在线播放| 精品国产一区二区在线| 精品91视频| 一本色道久久亚洲综合精品蜜桃 | 国产综合欧美在线看| 午夜精品久久久久99热蜜桃导演| 久久精品日产第一区二区三区精品版| 亚洲国产99| 亚洲欧美国产高清va在线播| 波多野结依一区| 青青草国产免费| 综合操久久久| 亚洲丁香婷深爱综合| 欧美在线网站| 天天干天天干天天干天天干天天干| 日韩精品在线看| 中文字幕一区二区三区欧美日韩 | 成人av高清在线| 糖心vlog在线免费观看| 欧美区视频在线观看| 中文一区一区三区免费在线观看| 夜夜爽av福利精品导航| 国产精品午夜在线观看| 国产一区毛片| 黄色av网站在线播放| 国产成人在线免费看| 97视频国产在线| 91精品国产欧美一区二区| 成人国产一区二区三区精品| 国内自拍视频一区二区三区| 国产精品视频首页| 久久青青视频| 欧美天天影院| 免费在线看污| 日韩三级电影网站| 日韩av在线看| 91免费观看国产| 亚洲小说图片| 天堂av资源在线观看| 国产伦精品一区二区三区照片91| 欧美天堂一区二区三区| 日韩激情在线观看| 成人va天堂| 在线免费看黄色| 国产一区二区三区免费不卡| 久久久久99精品国产片| 一二三四视频在线中文| 精品这里只有精品| 午夜精品免费在线观看| 嫩草伊人久久精品少妇av杨幂| 69av成年福利视频| 综合视频在线| 亚洲欧美精品| 一区二区三区视频在线看| 中文字幕高清在线| 日韩欧美一区电影| 精品一区在线| 完全免费av在线播放| 国产精品pans私拍| 国产精品久久网站| gogo亚洲高清大胆美女人体| 国产激情99| 少妇人妻在线视频| 亚洲一区二区不卡视频| 欧美亚洲另类在线一区二区三区| 欧美成人福利| caoporn97在线视频| 性感av在线播放| 日韩欧美国产精品一区二区三区| 女性隐私黄www网站视频| 日本手机在线视频| 精品无码一区二区三区在线| 大陆极品少妇内射aaaaa| 亚洲加勒比久久88色综合| 5858s免费视频成人| 欧美人成免费网站| 亚洲欧洲日本在线| 精东粉嫩av免费一区二区三区| 日韩欧美高清一区二区三区| 国产区在线视频| 黄网站欧美内射| 欧美激情国产日韩| 国产亚洲视频在线| 成人综合婷婷国产精品久久| 免费黄网站在线播放| www.中文字幕在线| 欧美日韩国产成人| 成人免费视频网站在线观看| sese综合| 特级毛片在线观看| 免费在线国产精品| 欧美午夜一区二区三区| 毛片一区二区| 超碰在线中文字幕| 黄色一级片网址| 亚洲第一免费网站| 国产综合一区二区| 性欧美18xxxhd| 久久综合中文色婷婷| 亚洲福利在线看| 国产一区二区三区黄视频| 亚洲啊v在线| 亚洲这里只有精品| 久久久久久12| 91九色最新地址| 久久影院亚洲| 色爱综合av| 天天夜夜亚洲| 日本一区视频在线播放| 日韩h在线观看| 国产精品综合一区二区三区| 豆花视频一区| 国产精品一二三在线观看| 2018日韩中文字幕| 欧美视频一二三| 中文欧美字幕免费| 五月开心六月丁香综合色啪| 青青色在线视频| 男女曰b免费视频| 91久久精品日日躁夜夜躁国产| 中文字幕国产日韩| 夜夜嗨av一区二区三区网页| 午夜在线精品偷拍| 亚洲人成网站77777在线观看| 日本成人伦理电影| 欧美被日视频| 久草在线青青草| 日韩一二三四| 国产福利第一视频在线播放| 国产伦精品一区二区三区四区视频_ |