精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

深入探討Android異步精髓Handler

移動開發(fā) Android
Google采用Handler把主線程和子線程精巧地聯(lián)系起來——子線程中進行耗時的業(yè)務邏輯,然后利用Handler通知主線程刷新UI。除此以外,還有別的方式可以實現(xiàn)類似的操作么?答案是肯定的,我們也可以利用AsyncTask或者IntentService進行異步的操作。Handler是Android異步操作的核心和精髓,它在眾多領域發(fā)揮著極其重要甚至是不可替代的作用。

前言

眾所周知,Android的UI是在其主線程中進行刷新的,所以Google建議開發(fā)人員切勿在主線程中進行耗時的操作否則很容易導致應用程序無響應(ANR)。鑒于此幾乎接近硬性的要求,我們常把耗時的操作(比如網(wǎng)絡請求)置于子線程中進行;但是子線程不能直接訪問UI。

至此,這個矛盾就凸顯出來了:

  • 主線程可以刷新UI,但不能執(zhí)行耗時操作
  • 子線程可以執(zhí)行耗時操作 ,但是不能直接刷新UI

嗯哼,那有沒有一個東西可以調(diào)和并化解這個矛盾呢?當然是有的,Google采用Handler把主線程和子線程精巧地聯(lián)系起來——子線程中進行耗時的業(yè)務邏輯,然后利用Handler通知主線程刷新UI。除此以外,還有別的方式可以實現(xiàn)類似的操作么?答案是肯定的,我們也可以利用AsyncTask或者IntentService進行異步的操作。這兩者又是怎么做到的呢?其實,在AsyncTask和IntentService的內(nèi)部亦使用了Handler實現(xiàn)其主要功能。拋開這兩者不談,當我們打開Android源碼的時候也隨處可見Handler的身影。所以,Handler是Android異步操作的核心和精髓,它在眾多領域發(fā)揮著極其重要甚至是不可替代的作用。

在此,對Handler的工作原理和實現(xiàn)機制進行系統(tǒng)的梳理。

ThreadLocal簡介及其使用

對于線程Thread大家都挺熟悉的了,但是對于ThreadLocal可能就要陌生許多了。雖然我們對于它不太了解,但是它早在JDK1.2版本中就已問世并且被廣泛的使用,比如hibernate,EventBus,Handler都運用了ThreadLocal進行線程相關的操作。如果單純地從ThreadLocal這個名字來看,它帶著濃濃的“本地線程”的味道; 然而,喝一口之后才發(fā)現(xiàn)根本就不是這個味兒。其實,ThreadLocal并不是用來操作什么本地線程而是用于實現(xiàn)不同線程的數(shù)據(jù)副本。當使用ThreadLocal維護變量時,它會為每個使用該變量的線程提供獨立的變量副本;每一個線程都可以獨立地改變自己的副本并且不會影響其它線程所持有的對應的副本。所以,ThreadLocal的實際作用并不與它的名字所暗含的意義相吻合,或許改稱為ThreadLocalVariable(線程本地變量)會更合適一些。

接下來,我們通過一個實例來瞅瞅ThreadLocal的使用方式

  1. /** 
  2.      * 原創(chuàng)作者: 
  3.      * 谷哥的小弟 
  4.      * 
  5.      * 博客地址: 
  6.      * http://blog.csdn.net/lfdfhl 
  7.      */ 
  8.     private void testThreadLocal(){ 
  9.         mThreadLocal.set("東京熱"); 
  10.         new HotThread1().start(); 
  11.         new HotThread2().start(); 
  12.         hot3=mThreadLocal.get(); 
  13.         try{ 
  14.             Thread.sleep(1000*4); 
  15.             Log.i(TAG,"HotThread1獲取到的變量值: "+hot1); 
  16.             Log.i(TAG,"HotThread2獲取到的變量值: "+hot2); 
  17.             Log.i(TAG,"MainThread獲取到的變量值: "+hot3); 
  18.         }catch (Exception e){ 
  19.  
  20.         } 
  21.     } 
  22.  
  23.     private class HotThread1  extends Thread{ 
  24.         @Override 
  25.         public void run() { 
  26.             super.run(); 
  27.             mThreadLocal.set("北京熱"); 
  28.             hot1=mThreadLocal.get(); 
  29.         } 
  30.     } 
  31.  
  32.     private class HotThread2  extends Thread{ 
  33.         @Override 
  34.         public void run() { 
  35.             super.run(); 
  36.             mThreadLocal.set("南京熱"); 
  37.             hot2=mThreadLocal.get(); 
  38.         } 
  39.     }  

查看輸出結果:

  1. HotThread1獲取到的變量值: 北京熱 
  2. HotThread2獲取到的變量值: 南京熱 
  3. MainThread獲取到的變量值: 東京熱  

在這段代碼中使用ThreadLocal保存String類型的數(shù)據(jù),并且在主線程和兩個子線程中為ThreadLocal設置了不同的值,然后再將這些值分別取出。結合輸出日志可以發(fā)現(xiàn):在不同的線程中訪問了同一個ThreadLocal對象,但是通過mThreadLocal.get()得到的值卻是不一樣的;也就是說:它們之間沒有發(fā)生相互的影響而是保持了彼此的獨立。明白了ThreadLocal的這個特性之后,我們再去理解Looper的工作機制就會容易得多了。

Looper、線程、消息隊列的關系

Google官方建議開發(fā)人員使用Handler實現(xiàn)異步刷新UI,我們在平常的工作中也很好地采納了這個提議:首先在主線程中建立Handler,然后在子線程中利用handler.sendMessage(message)發(fā)送消息至主線程,最終消息在handleMessage(Message msg) {}得到相應的處理。這個套路,大家都再熟悉不過了;現(xiàn)在換個角度,我們試試在子線程中建立Handler

  1. private class LooperThread  extends Thread{ 
  2.         @Override 
  3.         public void run() { 
  4.             super.run(); 
  5.             Handler handler=new Handler(); 
  6.             //doing something 
  7.         } 
  8.     }  

此處的代碼很簡單:LooperThread繼承自Thread,并且在其run( )方法中新建一個Handler。

嗯哼,再運行一下,喔哦,報錯了:

  1. Can’t create handler inside thread that has not called Looper.prepare(). 

咦,有點出師不利呢,剛開始試就出錯了…….沒事,生活不就是無盡的挫折和希望嘛,這點小事嘛也不算。既然是在調(diào)用Handler的構造方法時報的錯那就從該構造方法的源碼入手,一探究竟:

  1. public Handler() { 
  2.     this(nullfalse); 
  3.  
  4. public Handler(Callback callback) { 
  5.     this(callback, false); 
  6.  
  7. public Handler(Callback callback, boolean async) { 
  8.     if (FIND_POTENTIAL_LEAKS) { 
  9.         final Class<? extends Handler> klass = getClass(); 
  10.         if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && 
  11.                 (klass.getModifiers() & Modifier.STATIC) == 0) { 
  12.             Log.w(TAG, "The following Handler class should be static or leaks might occur"); 
  13.         } 
  14.     } 
  15.  
  16.     mLooper = Looper.myLooper(); 
  17.     if (mLooper == null) { 
  18.         throw new RuntimeException 
  19.         ("Can't create handler inside thread that has not called Looper.prepare()"); 
  20.     } 
  21.     mQueue = mLooper.mQueue; 
  22.     mCallback = callback; 
  23.     mAsynchronous = async; 
  24.  

請注意第20行代碼:

如果mLooper == null那么系統(tǒng)就會拋出剛才的錯誤:Can’t create handler inside thread that has not called Looper.prepare()。這句話的意思是:如果在線程內(nèi)創(chuàng)建handler必須調(diào)用Looper.prepare()。既然這個提示已經(jīng)提示了我們該怎么做,那就加上這一行代碼:

  1. private class LooperThread  extends Thread{ 
  2.         @Override 
  3.         public void run() { 
  4.             super.run(); 
  5.             Looper.prepare(); 
  6.             Handler handler=new Handler(); 
  7.             System.out.println("add code : Looper.prepare()"); 
  8.             //doing something 
  9.         } 
  10.     }  

嘿嘿,果然不再報錯了,運行一下:

 

既然Looper.prepare()解決了這個問題,那我們就去瞅瞅在該方法中做了哪些操作:

  1. /**Initialize the current thread as a looper. 
  2.  * This gives you a chance to create handlers that then reference 
  3.  * this looper, before actually starting the loop. Be sure to call 
  4.  * loop() after calling this method, and end it by calling quit(). 
  5.  */ 
  6. public static void prepare() { 
  7.     prepare(true); 
  8.  
  9. private static void prepare(boolean quitAllowed) { 
  10.     if (sThreadLocal.get() != null) { 
  11.         throw new RuntimeException("Only one Looper may be created per thread"); 
  12.     } 
  13.     sThreadLocal.set(new Looper(quitAllowed)); 
  14.  

從這段源碼及其注釋文檔我們可以看出:

在prepare()中利用一個Looper來初始化當前線程或者說初始化一個帶有Looper的線程。

請注意第14行代碼,它是這段源碼的核心,現(xiàn)對其詳細分析:

  1. sThreadLocal.set(new Looper(quitAllowed)); 

在該行代碼中一共執(zhí)行了兩個操作

(1) 構造Looper

  1. private Looper(boolean quitAllowed) { 
  2.     mQueue = new MessageQueue(quitAllowed); 
  3.     mThread = Thread.currentThread(); 
  4.  

在Looper的構造方法中初始化了一個消息隊列MessageQueue和一個線程Thread。從這可看出:一個Looper對應著一個消息隊列以及當前線程。

當收到消息Message后系統(tǒng)會將其存入消息隊列中等候處理。至于Looper,它在Android的消息機制中擔負著消息輪詢的職責,它會不間斷地查看MessageQueue中是否有新的未處理的消息;若有則立刻處理,若無則進入阻塞。

(2) 將此Looper保存到sThreadLocal中。

此處的sThreadLocal是定義在Looper類中的一個ThreadLocal類型變量

  1. static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); 

Looper是framework中的一個類,sThreadLocal是它的一個static final變量。當在某一個Thread中執(zhí)行Looper.prepare()時系統(tǒng)就會將與該Thread所對應的Looper保存到sThreadLocal中。不同的線程對著不同的Looper,但它們均由系統(tǒng)保存在sThreadLocal中并且互不影響,相互獨立;并且可以通過sThreadLocal.get()獲取不同線程所對應的Looper.

在調(diào)用prepare()方法后需要調(diào)用loop()方法開始消息的輪詢,并且在需要的時候調(diào)用quit()方法停止消息的輪詢

假若再次執(zhí)行Looper.prepare()系統(tǒng)發(fā)現(xiàn)sThreadLocal.get()的值不再為null于是拋出異常:

Only one Looper may be created per thread,一個線程只能創(chuàng)建一個Looper!

小結:

  1. 一個線程對應一個Looper
  2. 一個Looper對應一個消息隊列
  3. 一個線程對應一個消息隊列
  4. 線程,Looper,消息隊列三者一一對應

所以,在一個子線程中使用Handler的方式應該是這樣的:

  1. class LooperThread extends Thread {  
  2.     public Handler mHandler; 
  3.     public void run() {  
  4.         Looper.prepare();  
  5.         mHandler = new Handler() {  
  6.             public void handleMessage(Message msg) {  
  7.  
  8.             }  
  9.         }; 
  10.         Looper.loop();  
  11.       }  
  12.   }  

看到這個范例,有的人可能心里就犯嘀咕了:為什么我們平常在MainActivity中使用Handler時并沒有調(diào)用Looper.prepare()也沒有報錯呢?

這是因為UI線程是主線程,系統(tǒng)會自動調(diào)用Looper.prepareMainLooper()方法創(chuàng)建主線程的Looper和消息隊列MessageQueue

Message的發(fā)送和處理過程

在討論完Looper、線程、消息隊列這三者的關系之后我們再來瞅瞅Android消息機制中對于Message的發(fā)送和處理。

平常最常用的方式:

handler.sendMessage(message)——>發(fā)送消息

handleMessage(Message msg){}——>處理消息

先來分析消息的入隊。

Handler可以通過post()、postAtTime()、postDelayed()、postAtFrontOfQueue()等方法發(fā)送消息,除了postAtFrontOfQueue()之外這幾個方法均會執(zhí)行到sendMessageAtTime(Message msg, long uptimeMillis)方法,源碼如下:

  1. public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 
  2.     MessageQueue queue = mQueue; 
  3.     if (queue == null) { 
  4.         RuntimeException e = new RuntimeException( 
  5.                 this + " sendMessageAtTime() called with no mQueue"); 
  6.         Log.w("Looper", e.getMessage(), e); 
  7.         return false
  8.     } 
  9.     return enqueueMessage(queue, msg, uptimeMillis); 
  10.  
  11. public final boolean sendMessageAtFrontOfQueue(Message msg) { 
  12.     MessageQueue queue = mQueue; 
  13.     if (queue == null) { 
  14.         RuntimeException e = new RuntimeException( 
  15.                 this + " sendMessageAtTime() called with no mQueue"); 
  16.         Log.w("Looper", e.getMessage(), e); 
  17.         return false
  18.     } 
  19.     return enqueueMessage(queue, msg, 0); 
  20.  
  21. private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { 
  22.     msg.target = this; 
  23.     if (mAsynchronous) { 
  24.         msg.setAsynchronous(true); 
  25.     } 
  26.     return queue.enqueueMessage(msg, uptimeMillis); 
  27.  

在這里可以看到sendMessageAtTime()內(nèi)部又調(diào)用了enqueueMessage(),在該方法內(nèi)的重要操作:

  • ***步:

給msg設置了target,請參見代碼第25行此處的this就是當前Handler對象本身。在這就指明了該msg的來源——它是由哪個Handler發(fā)出的,與此同時也指明了該msg的歸宿——它該由哪個Handler處理。不難發(fā)現(xiàn),哪個Handler發(fā)出了消息就由哪個Handler負責處理。

  • 第二步:

將消息放入消息隊列中,請參見代碼第29行在enqueueMessage(msg,uptimeMillis)中將消息Message存放進消息隊列中,距離觸發(fā)時間最短的message排在隊列最前面,同理距離觸發(fā)時間最長的message排在隊列的最尾端。若調(diào)用sendMessageAtFrontOfQueue()方法發(fā)送消息它會直接調(diào)用該enqueueMessage(msg,uptimeMillis)讓消息入隊只不過時間為延遲時間為0,也就是說該消息會被插入到消息隊列頭部優(yōu)先得到執(zhí)行。直覺告訴我們此處的消息隊列mQueue就是該線程所對應的消息隊列。可是光有直覺是不夠的甚至是不可靠的。我們再回過頭瞅瞅Handler的構造方法,從源碼中找到確切的依據(jù) 

  1. public Handler(Callback callback, boolean async) { 
  2.     if (FIND_POTENTIAL_LEAKS) { 
  3.         final Class<? extends Handler> klass = getClass(); 
  4.         if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && 
  5.                 (klass.getModifiers() & Modifier.STATIC) == 0) { 
  6.             Log.w(TAG, "The following Handler class should be static or leaks might occur"); 
  7.         } 
  8.     } 
  9.  
  10.     mLooper = Looper.myLooper(); 
  11.     if (mLooper == null) { 
  12.         throw new RuntimeException 
  13.         ("Can't create handler inside thread that has not called Looper.prepare()"); 
  14.     } 
  15.     mQueue = mLooper.mQueue; 
  16.     mCallback = callback; 
  17.     mAsynchronous = async; 
  18.  

(1) 獲取Looper,請參見代碼第10行

(2) 利用Looper的消息隊列為mQueue賦值,請參見代碼第15行

(3) 為mCallback賦值,,請參見代碼第16行

(4) 為mAsynchronous賦值,,請參見代碼第17行

嗯哼,看到了吧,這個mQueue就是從Looper中取出來的。在之前我們也詳細地分析了Looper、線程、消息隊列這三者的一一對應關系,所以此處的mQueue正是線程所對應的消息隊列。

看完了消息的入隊,再來分析消息的出隊。

請看Looper中的loop()方法源碼: 

  1. public static void loop() { 
  2.     final Looper me = myLooper(); 
  3.     if (me == null) { 
  4.         throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); 
  5.     } 
  6.     final MessageQueue queue = me.mQueue; 
  7.  
  8.     // Make sure the identity of this thread is that of the local process, 
  9.     // and keep track of what that identity token actually is
  10.     Binder.clearCallingIdentity(); 
  11.     final long ident = Binder.clearCallingIdentity(); 
  12.  
  13.     for (;;) { 
  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.  
  20.         // This must be in a local variable, in case a UI event sets the logger 
  21.         final Printer logging = me.mLogging; 
  22.         if (logging != null) { 
  23.             logging.println(">>>>> Dispatching to " + msg.target + " " + 
  24.                     msg.callback + ": " + msg.what); 
  25.         } 
  26.  
  27.         final long traceTag = me.mTraceTag; 
  28.         if (traceTag != 0) { 
  29.             Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); 
  30.         } 
  31.         try { 
  32.             msg.target.dispatchMessage(msg); 
  33.         } finally { 
  34.             if (traceTag != 0) { 
  35.                 Trace.traceEnd(traceTag); 
  36.             } 
  37.         } 
  38.  
  39.         if (logging != null) { 
  40.             logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); 
  41.         } 
  42.  
  43.         // Make sure that during the course of dispatching the 
  44.         // identity of the thread wasn't corrupted. 
  45.         final long newIdent = Binder.clearCallingIdentity(); 
  46.         if (ident != newIdent) { 
  47.             Log.wtf(TAG, "Thread identity changed from 0x" 
  48.                     + Long.toHexString(ident) + " to 0x" 
  49.                     + Long.toHexString(newIdent) + " while dispatching to " 
  50.                     + msg.target.getClass().getName() + " " 
  51.                     + msg.callback + " what=" + msg.what); 
  52.         } 
  53.  
  54.         msg.recycleUnchecked(); 
  55.     } 
  56.  

我們發(fā)現(xiàn)關于消息的處理是在一個死循環(huán)中就行的,請參見代碼第13-55行。也就是說在該段代碼中Looper一直在輪詢消息隊列MessageQueue。假若消息隊列中沒有未處理的消息(即queue.next()==null)則其進入阻塞block狀態(tài),假若消息隊列中有待處理消息(即queue.next()!=null)則利用msg.target.dispatchMessage(msg)將該消息派發(fā)至對應的Handler。

到了這,可能有的人會有一個疑問:系統(tǒng)怎么知道把消息發(fā)送給哪個Handler呢?

嘿嘿,還記不記得enqueueMessage()中系統(tǒng)給msg設置了target從而確定了其目標Handler么?嗯哼,所以只要通過msg.target.dispatchMessage(msg)就可以將消息派發(fā)至對應的Handler了。那在dispatchMessage()中又會對消息做哪些操作呢?我們繼續(xù)跟進源碼

  1. public void dispatchMessage(Message msg) { 
  2.     if (msg.callback != null) { 
  3.         handleCallback(msg); 
  4.     } else { 
  5.         if (mCallback != null) { 
  6.             if (mCallback.handleMessage(msg)) { 
  7.                 return
  8.             } 
  9.         } 
  10.         handleMessage(msg); 
  11.     } 
  12.  

哇哈,看到這,心情就舒暢多了,基本上回到了我們熟悉的地方;在此處對Message消息進行了處理,我們來瞅瞅主要的步驟

  • ***步:

處理Message的回調(diào)callback,請參見代碼第3行

比如調(diào)用handler.post(Runnable runnable)時,該runnable就會被系統(tǒng)封裝為Message的callback。

關于這點在源碼中也有非常直觀的體現(xiàn):

  1. private static Message getPostMessage(Runnable r) { 
  2.    Message m = Message.obtain(); 
  3.    m.callback = r; 
  4.    return m; 
  5.  
  • 第二步:

處理Handler的回調(diào)callback,請參見代碼第6行

比如執(zhí)行Handler handler=Handler(Callback callback)時就會將callback賦值給mCallback,關于這點已經(jīng)在介紹Handler構造方法時分析過了,不再贅述。

第三步:

調(diào)用handleMessage()處理消息Message,請參見代碼第10行

handleMessage()的源碼如下:

  1. public void handleMessage(Message msg) { 
  2.  
  3.  

嗯哼,它是一個空的方法。所以Handler的子類需要覆寫該方法,并在其中處理接收到的消息。

梳理Handler工作機制

至此,關于Handler的異步機制及其實現(xiàn)原理已經(jīng)分析完了。在此,對其作一個全面的梳理和總結。

Android異步消息機制中主要涉及到:Thread、Handler、MessageQueue、Looper,在整個機制中它們扮演著不同的角色也承擔著各自的不同責任。

  • Thread負責業(yè)務邏輯的實施。

線程中的操作是由各自的業(yè)務邏輯所決定的,視具體情況進行。

  • Handler負責發(fā)送消息和處理消息。

通常的做法是在主線程中建立Handler并利用它在子線程中向主線程發(fā)送消息,在主線程接收到消息后會對其進行處理

  • MessageQueue負責保存消息。

Handler發(fā)出的消息均會被保存到消息隊列MessageQueue中,系統(tǒng)會根據(jù)Message距離觸發(fā)時間的長短決定該消息在隊列中位置。在隊列中的消息會依次出隊得到相應的處理。

  • Looper負責輪詢消息隊列。

Looper使用其loop()方法一直輪詢消息隊列,并在消息出隊時將其派發(fā)至對應的Handler.

為了更好地理解這幾者的相互關系及其作用,請參見如下示圖 

 

 

 

使用Handler的錯誤姿勢及其潛在風險

關于Handler的具體用法,尤其是那些常規(guī)的使用方式在此就不再一一列舉了。

責任編輯:龐桂玉 來源: Android開發(fā)中文站
相關推薦

2012-02-28 14:43:43

2009-12-23 16:13:00

WPF Attache

2010-11-22 14:18:32

MySQL鎖機制

2010-07-21 09:38:15

PHP緩存技術

2009-11-20 17:17:08

Oracle函數(shù)索引

2021-05-17 05:36:02

CSS 文字動畫技巧

2010-01-26 13:47:57

Android電話功能

2011-02-25 09:23:00

Java類加載器

2023-01-12 17:18:06

數(shù)據(jù)庫多云

2015-09-02 08:57:56

JavaHashMap工作原理

2009-08-27 11:27:58

foreach語句C# foreach語

2010-03-31 14:58:03

云計算

2010-03-05 13:44:00

Python序列

2009-12-14 14:40:10

Ruby全局域變量

2024-01-26 06:42:05

Redis數(shù)據(jù)結構

2009-12-11 11:08:31

靜態(tài)路由策略

2009-12-07 16:07:03

PHP類的繼承

2009-11-12 13:56:54

2013-07-11 09:45:48

扁平化扁平化設計

2009-10-16 09:17:39

屏蔽布線系統(tǒng)
點贊
收藏

51CTO技術棧公眾號

一区二区精品在线| 欧美在线视频a| 91香蕉视频在线观看视频| 午夜av在线免费观看| 99re这里只有精品视频首页| 国产97在线播放| 成熟的女同志hd| 天堂av一区二区三区在线播放| 在线免费不卡视频| 嫩草影院中文字幕| 国产精品四虎| 成人免费毛片app| 国产精品久久网| 国产一级片视频| 四虎成人精品永久免费av九九| 在线不卡欧美精品一区二区三区| 99热在线这里只有精品| 影音先锋在线播放| 国产精品久久久久久亚洲毛片| 国产九区一区在线| 国产精品国产一区二区三区四区| 国产精品久久久免费| 美女撒尿一区二区三区| 最新中文字幕av| 任我爽精品视频在线播放| 91精品国产乱码| 久久久精品麻豆| 制服丝袜专区在线| 亚洲一区二区三区小说| 精品久久免费观看| av网在线观看| 久久久久99精品一区| 国产成人av一区二区三区| 一级做a爱片性色毛片| 免费精品视频| 91高清视频在线免费观看| 欧美卡一卡二卡三| 欧美岛国激情| 色午夜这里只有精品| 91精彩刺激对白露脸偷拍| 国产美女撒尿一区二区| 欧美成人三级在线| 中文字幕久久av| 高清亚洲高清| 欧美午夜片在线看| 成人免费观看毛片| 免费电影日韩网站| 欧美性猛交xxxxx免费看| 午夜免费福利小电影| free性欧美| 亚洲国产va精品久久久不卡综合| 91黄色在线看| 成人免费网站观看| 亚洲r级在线视频| 玩弄中年熟妇正在播放| 3344国产永久在线观看视频| 亚洲影视资源网| 成人午夜免费在线视频| 激情网站在线| 亚洲第一主播视频| 日本在线xxx| 在线观看v片| 色噜噜狠狠色综合欧洲selulu| 国产日韩成人内射视频| 日韩漫画puputoon| 欧美日韩不卡在线| 91日韩精品视频| 日韩精品免费视频一区二区三区| 精品免费99久久| 午夜剧场免费看| 综合亚洲自拍| 中文字幕在线国产精品| 免费在线观看黄色小视频| 91精品国产视频| 久久久久久久久久久久av| 女人十八岁毛片| 男女男精品网站| 91美女高潮出水| 人妻少妇精品无码专区| 91啪亚洲精品| 亚洲mv在线看| 天天干在线视频论坛| 午夜不卡av在线| 中文久久久久久| 精品视频成人| 亚洲精品国偷自产在线99热| 欧美黄色一级生活片| 91精品国产视频| 性日韩欧美在线视频| 国产精品第六页| 国产一区二区三区在线看麻豆 | 日韩中文影院| 欧美精品自拍偷拍动漫精品| 男人网站在线观看| 不卡中文一二三区| 欧美国产极速在线| 在线免费一区二区| 成人在线视频一区二区| 日韩av不卡播放| 黄色污污视频在线观看| 在线中文字幕一区| 中国极品少妇xxxx| 欧美激情777| 91精品国产精品| 国产又爽又黄免费软件| 久久在线免费观看| 黄色网址在线免费看| jizz内谢中国亚洲jizz| 日韩欧美中文字幕公布| 中文字幕成人动漫| 亚洲国产清纯| 成人免费自拍视频| 你懂的视频在线免费| 亚洲一区二区欧美日韩| 在线观看免费黄网站| 日韩高清在线免费观看| 欧美成人免费va影院高清| 波多野结衣家庭主妇| 不卡的看片网站| 国产人妻互换一区二区| 国产精品成人国产| 亚洲老头老太hd| 精品一区二区三区四| 精品一区二区免费在线观看| 欧美日韩一区二区三区在线视频 | 亚洲国产精品一区| 91精品一区二区| av影片在线看| 色狠狠av一区二区三区| 丰满少妇在线观看资源站| 亚洲一本视频| aa成人免费视频| 米奇精品一区二区三区| 欧美三级视频在线观看| 亚洲a v网站| 免费视频一区二区三区在线观看| 国产日韩精品推荐| 电影k8一区二区三区久久| 欧美一级二级三级蜜桃| www.99re7| 国模无码大尺度一区二区三区| 一区二区三区四区免费视频| 成人黄色在线| 色久欧美在线视频观看| 中文字幕一区二区免费| 国产欧美日韩在线看| 又色又爽又高潮免费视频国产| 亚洲亚洲免费| 国产91网红主播在线观看| 男女污污视频在线观看| 在线视频亚洲一区| 娇妻被老王脔到高潮失禁视频| 丝袜美腿亚洲综合| 一区二区不卡在线| 日韩综合av| 久久综合久久美利坚合众国| www.天堂av.com| 亚洲无人区一区| 欧美一区二区三区成人精品| 老妇喷水一区二区三区| 天天综合色天天综合色hd| 国产成人免费| 欧美老肥婆性猛交视频| 天堂网在线中文| 欧美性猛交xxxx偷拍洗澡| 日韩毛片无码永久免费看| 久久99精品国产麻豆婷婷| 亚洲免费视频播放| 理论片一区二区在线| 国产精品ⅴa在线观看h| 黄色网页网址在线免费| 精品国产凹凸成av人网站| 国产成人自拍视频在线| 久久精品亚洲精品国产欧美| 中文字幕在线观看日 | 男人靠女人免费视频网站| 久久99精品久久久久久园产越南| 国产精自产拍久久久久久蜜| av香蕉成人| 亚洲精品福利免费在线观看| 波多野结衣日韩| 最好看的中文字幕久久| 91精品又粗又猛又爽| 美日韩精品视频| 香蕉视频在线网址| 日本韩国欧美超级黄在线观看| 国产精品普通话| 国产乱妇乱子在线播视频播放网站| 亚洲韩国日本中文字幕| 亚洲无码久久久久| 午夜亚洲国产au精品一区二区| 蜜臀久久99精品久久久久久| 国产寡妇亲子伦一区二区| 欧美v在线观看| 五月天久久777| 久久久久久久有限公司| 精品国产伦一区二区三区观看说明 | 精品视频色一区| www.av视频在线观看| 国产精品久久久一本精品| 91玉足脚交白嫩脚丫| 激情文学综合丁香| 农村妇女精品一二区| 欧美日韩综合| 一区二区三区视频| 国产精品一区高清| av在线不卡观看| 欧美视频在线视频精品| 555www成人网| 欧美videosex性欧美黑吊| 中文字幕av一区中文字幕天堂 | www.18av.com| 凹凸成人精品亚洲精品密奴| 久久精品人人做人人爽电影| 日韩国产在线不卡视频| 91精品国产综合久久香蕉最新版 | 欧美视频在线观看| 亚洲一区二三| 欧美日韩亚洲在线观看| 久久精品日产第一区二区三区| 最新国产精品精品视频| 国产一区二区丝袜| 日韩三区免费| 日本不卡视频在线播放| av电影免费在线看| 久久网福利资源网站| 在线观看免费黄色| 国产一区二区三区久久精品| 欧美日韩国产综合视频 | 欧美成人三区| 国产一区二区三区欧美| 国产永久免费高清在线观看视频| 日韩成人在线网站| 欧美一级在线免费观看| 精品国精品国产尤物美女| a毛片在线免费观看| 欧美夫妻性生活| 一级黄色大片免费观看| 欧美吻胸吃奶大尺度电影| chinese国产精品| 欧美日韩亚洲国产一区| 五月婷婷激情网| 天天色综合天天| 波多野结衣国产| 欧美午夜激情在线| 国产精品suv一区| 日本道在线观看一区二区| 亚洲国产av一区二区三区| 色嗨嗨av一区二区三区| 亚洲午夜在线播放| 欧美日韩亚洲综合在线 | 国产麻豆视频一区二区| 日韩精品aaa| 国产69精品久久久久777| 精品伦一区二区三区| 成人激情免费电影网址| 国产不卡一二三| 91蝌蚪porny九色| 国产熟女一区二区| 亚洲人成伊人成综合网小说| 久久久精品国产sm调教网站| 性做久久久久久| 欧美一级淫片免费视频黄| 欧美在线一二三| 97超视频在线观看| 欧美va亚洲va在线观看蝴蝶网| 黄频网站在线观看| 国产小视频91| 黄色免费在线观看网站| 欧美激情精品久久久久久久变态| 韩国精品一区| 国产精品视频一| 亚洲专区**| 鲁丝一区二区三区免费| 日本在线电影一区二区三区| 成人在线观看毛片| 国产精品三上| 涩多多在线观看| 99re这里只有精品6| 国产又粗又长又硬| 亚洲线精品一区二区三区| 久久久久在线视频| 欧美一区二区三区啪啪| 亚洲av成人精品毛片| 中文字幕国产日韩| 成人性生交大片免费看网站 | 亚洲一区二区天堂| 日韩精品一区二区三区蜜臀| 麻豆影视在线| 欧美巨大黑人极品精男| 日韩久久一区二区三区| 91偷拍精品一区二区三区| 免费成人高清在线视频theav| 国产精品一区在线免费观看| 亚洲一区二区成人| 污污网站在线观看视频| 99久久精品国产导航| 911国产在线| 欧美特级www| 国产熟女一区二区三区五月婷| 亚洲开心激情网| 欧美另类tv| 91精品国产综合久久香蕉最新版 | 国产91丝袜在线播放| 一级黄色毛毛片| 精品久久中文字幕久久av| 国产伦一区二区| 亚洲天堂网在线观看| av丝袜在线| av成人在线电影| 午夜av一区| 韩国中文字幕av| 2023国产精品视频| 久久免费播放视频| 欧美夫妻性生活| 日本在线免费| 国产精品第七影院| 日韩成人一级| 国产婷婷一区二区三区| 国产精品一区二区果冻传媒| 婷婷国产成人精品视频| 色狠狠一区二区| 欧美777四色影视在线| 91超碰caoporn97人人| 亚洲不卡在线| 400部精品国偷自产在线观看| 蜜臀久久久99精品久久久久久| 亚洲久久久久久| 亚洲成在线观看| 亚洲国产精品久久久久久久| 久久中文字幕在线| 国产剧情一区二区在线观看| 亚洲精品在线观看免费| 视频在线在亚洲| www.中文字幕av| 色婷婷综合中文久久一本| 视频国产在线观看| 26uuu日韩精品一区二区| 久久超级碰碰| 男人和女人啪啪网站| 99久久99久久免费精品蜜臀| 久久综合亚洲色hezyo国产| 欧美成人一级视频| wwwwxxxx在线观看| 精品欧美一区二区在线观看视频| 一区二区三区国产盗摄| 在线精品一区二区三区| 欧美日韩国产精品一区二区不卡中文| 天天操天天干天天干| 97香蕉超级碰碰久久免费的优势| 久久动漫网址| 欧美三级午夜理伦三级| 国产丝袜美腿一区二区三区| 五月婷婷丁香在线| 神马久久久久久| www.成人免费视频| 欧美视频在线观看| 亚洲系列中文字幕| 亚洲av成人无码一二三在线观看| 自拍偷拍亚洲图片| 欧美亚洲动漫精品| 免费看污黄网站| 欧美成人福利| 精品美女在线观看| 国产精品伦子伦| 国产一区二区观看| 精品粉嫩超白一线天av| 免费涩涩18网站入口| 亚洲精品88| 国产精品福利网站| 日韩一区欧美| 肉丝美足丝袜一区二区三区四| 亚洲成a人v欧美综合天堂下载 | avove在线播放| 精品动漫一区二区三区在线观看| 国产污视频在线播放| 欧美一区2区三区4区公司二百| 蜜桃一区二区三区在线| 欧美激情精品久久| 亚洲欧美国产高清va在线播| 日本在线一区二区| 久久人人爽人人爽人人av| 久久综合99re88久久爱| 一区二区久久精品66国产精品 | 粉嫩13p一区二区三区| 国产精品21p| 久久亚洲成人精品| 天天躁日日躁狠狠躁欧美| 天天操狠狠操夜夜操| 欧美日韩在线免费观看| 麻豆网站视频在线观看| 精品免费视频123区| 九一九一国产精品| 国产区在线观看视频| 日韩视频精品在线| 精品国产影院| 亚洲第一天堂久久| 色悠久久久久综合欧美99| 色www永久免费视频首页在线| 日本亚洲自拍|