青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

羅朝輝(飄飄白云)

關(guān)注嵌入式操作系統(tǒng),移動平臺,圖形開發(fā)。-->加微博 ^_^

  C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
  85 隨筆 :: 0 文章 :: 169 評論 :: 0 Trackbacks
Android多線程分析之三:Handler,Looper的實現(xiàn)

羅朝輝 (http://m.shnenglu.com/kesalin/)

本文遵循“署名-非商業(yè)用途-保持一致”創(chuàng)作公用協(xié)議

在前文《
Android多線程分析之二:Thread的實現(xiàn)》中已經(jīng)詳細(xì)分析了Android Thread 是如何創(chuàng)建,運(yùn)行以及銷毀的,其重點(diǎn)是對相應(yīng) native 方法進(jìn)行分析,今天我將聚焦于 Android Framework 層多線程相關(guān)的類:Handler, Looper, MessageQueue, Message 以及它們與Thread 之間的關(guān)系。可以用一個不太妥當(dāng)?shù)谋扔鱽硇稳菟鼈冎g的關(guān)聯(lián):如果把 Thread 比作生產(chǎn)車間,那么 Looper 就是放在這車間里的生產(chǎn)線,這條生產(chǎn)線源源不斷地從 MessageQueue 中獲取材料 Messsage,并分發(fā)處理 Message (由于Message 通常是完備的,所以 Looper 大多數(shù)情況下只是調(diào)度讓 Message 的 Handler 去處理 Message)。正是因為消息需要在 Looper 中處理,而 Looper 又需運(yùn)行在 Thread 中,所以不能隨隨便便在非 UI 線程中進(jìn)行 UI 操作。 UI 操作通常會通過投遞消息來實現(xiàn),只有往正確的 Looper 投遞消息才能得到處理,對于 UI 來說,這個 Looper 一定是運(yùn)行在 UI 線程中。

在編寫 app 的過程中,我們常常會這樣來使用 Handler:
Handler mHandler = new Handler();
mHandler.post(new Runnable(){
    @Override
    public void run() {
        // do somework
    }
});

或者如這系列文章第一篇中的示例那樣: 
    private Handler mHandler= new Handler(){
        @Override
        public void handleMessage(Message msg) {
            Log.i("UI thread", " >> handleMessage()");

            switch(msg.what){
            case MSG_LOAD_SUCCESS:
                Bitmap bitmap = (Bitmap) msg.obj;
                mImageView.setImageBitmap(bitmap);

                mProgressBar.setProgress(100);
                mProgressBar.setMessage("Image downloading success!");
                mProgressBar.dismiss();
                break;

            case MSG_LOAD_FAILURE:
                mProgressBar.setMessage("Image downloading failure!");
                mProgressBar.dismiss();
                break;
            }
        }
    };

    Message msg = mHandler.obtainMessage(MSG_LOAD_FAILURE, null);
    mHandler.sendMessage(msg);

那么,在 Handler 的 post/sendMessage 背后到底發(fā)生了什么事情呢?下面就來解開這個謎團(tuán)。

首先我們從 Handler 的構(gòu)造函數(shù)開始分析:
    final MessageQueue mQueue; 
    final Looper mLooper; 
    final Callback mCallback; 
    final boolean mAsynchronous;

    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

    public Handler(Callback callback, boolean async) {
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

    public Handler() {
        this(nullfalse);
    }

上面列出了 Handler 的一些成員變量:

mLooper:線程的消息處理循環(huán),注意:并非每一個線程都有消息處理循環(huán),因此 Framework 中線程可以分為兩種:有 Looper 的和無 Looper 的。為了方便 app 開發(fā),F(xiàn)ramework 提供了一個有 Looper 的 Thread 實現(xiàn):HandlerThread。在前一篇《Thread的實現(xiàn)》中也提到了兩種不同 Thread 的 run() 方法的區(qū)別。
/**
 * Handy class for starting a new thread that has a looper. The looper can then be 
 * used to create handler classes. Note that start() must still be called.
 
*/
public class HandlerThread extends Thread {
    Looper mLooper;
    /**
     * Call back method that can be explicitly overridden if needed to execute some
     * setup before Looper loops.
     
*/
    protected void onLooperPrepared() {
    }

    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

    /**
     * This method returns the Looper associated with this thread. If this thread not been started
     * or for any reason is isAlive() returns false, this method will return null. If this thread 
     * has been started, this method will block until the looper has been initialized.  
     * 
@return The looper.
     
*/
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }

        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
}

這個 HandlerThread 與 Thread 相比,多了一個類型為 Looper 成員變量 mLooper,它是在 run() 函數(shù)中由 Looper::prepare() 創(chuàng)建的,并保存在 TLS 中:
     /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {
@link #loop()} after calling this method, and end it by calling
      * {
@link #quit()}.
      
*/
    public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

然后通過 Looper::myLooper() 獲取創(chuàng)建的 Looper:
    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     
*/
    public static Looper myLooper() {
        return sThreadLocal.get();
    }

最后通過 Looper::Loop() 方法運(yùn)行消息處理循環(huán):從 MessageQueue 中取出消息,并分發(fā)處理該消息,不斷地循環(huán)這個過程。這個方法將在后面介紹。

Handler 的成員變量 mQueue 是其成員變量 mLooper 的成員變量,這里只是為了簡化書寫,單獨(dú)拿出來作為 Handler 的成員變量;成員變量 mCallback 提供了另一種使用Handler 的簡便途徑:只需實現(xiàn)回調(diào)接口 Callback,而無需子類化Handler,下面會講到的:
    /**
     * Callback interface you can use when instantiating a Handler to avoid
     * having to implement your own subclass of Handler.
     
*/
    public interface Callback {
        public boolean handleMessage(Message msg);
    }

成員變量 mAsynchronous 是標(biāo)識是否異步處理消息,如果是的話,通過該 Handler obtain 得到的消息都被強(qiáng)制設(shè)置為異步的。

同是否有無 Looper 來區(qū)分 Thread 一樣,Handler 的構(gòu)造函數(shù)也分為自帶 Looper 和外部 Looper 兩大類:如果提供了 Looper,在消息會在該 Looper 中處理,否則消息就會在當(dāng)前線程的 Looper 中處理,注意這里要確保當(dāng)前線程一定有 Looper。所有的 UI thread 都是有 Looper 的,因為 view/widget 的實現(xiàn)中大量使用了消息,需要 UI thread 提供 Looper 來處理,可以參考view.java:

view.java

    public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            return attachInfo.mHandler.post(action);
        }
        // Assume that post will succeed later
        ViewRootImpl.getRunQueue().post(action);
        return true;
    }

ViewRootImpl.java

    private void performTraversals() {
        .
        // Execute enqueued actions on every traversal in case a detached view enqueued an action
        getRunQueue().executeActions(attachInfo.mHandler);
      
    }

    static RunQueue getRunQueue() {
        RunQueue rq = sRunQueues.get();
        if (rq != null) {
            return rq;
        }
        rq = new RunQueue();
        sRunQueues.set(rq);
        return rq;
    }

    /**
     * The run queue is used to enqueue pending work from Views when no Handler is
     * attached.  The work is executed during the next call to performTraversals on
     * the thread.
     * @hide
     
*/
    static final class RunQueue {
    
        void executeActions(Handler handler) {
            synchronized (mActions) {
                final ArrayList<HandlerAction> actions = mActions;
                final int count = actions.size();

                for (int i = 0; i < count; i++) {
                    final HandlerAction handlerAction = actions.get(i);
                    handler.postDelayed(handlerAction.action, handlerAction.delay);
                }

                actions.clear();
            }
        }
    }

從上面的代碼可以看出,作為所有控件基類的 view 提供了 post 方法,用于向 UI Thread 發(fā)送消息,并在 UI Thread 的 Looper 中處理這些消息,而 UI Thread  一定有 Looper 這是由 ActivityThread 來保證的:
public final class ActivityThread {

    final Looper mLooper = Looper.myLooper();
}

UI 操作需要向 UI 線程發(fā)送消息并在其 Looper 中處理這些消息。這就是為什么我們不能在非 UI 線程中更新 UI 的原因,在控件在非 UI 線程中構(gòu)造 Handler 時,要么由于非 UI 線程沒有 Looper 使得獲取 myLooper 失敗而拋出 RunTimeException,要么即便提供了 Looper,但這個 Looper 并非 UI 線程的 Looper 而不能處理控件消息。為此在 ViewRootImpl 中有一個強(qiáng)制檢測 UI 操作是否是在 UI 線程中處理的方法 checkThread():該方法中的 mThread 是在 ViewRootImpl 的構(gòu)造函數(shù)中賦值的,它就是 UI 線程;該方法中的 Thread.currentThread() 是當(dāng)前進(jìn)行 UI 操作的線程,如果這個線程不是非 UI 線程就會拋出異常CalledFromWrongThreadException。
    void checkThread() {
        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can touch its views.");
        }
    }

如果修改《使用Thread異步下載圖像》中示例,下載完圖像 bitmap 之后,在 Thread 的 run() 函數(shù)中設(shè)置 ImageView 的圖像為該 bitmap,即會拋出上面提到的異常:
W/dalvikvm(796): threadid=11: thread exiting with uncaught exception (group=0x40a71930)
E/AndroidRuntime(796): FATAL EXCEPTION: Thread-75
E/AndroidRuntime(796): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
E/AndroidRuntime(796):     at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:4746)
E/AndroidRuntime(796):     at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:823)
E/AndroidRuntime(796):     at android.view.View.requestLayout(View.java:15473)
E/AndroidRuntime(796):     at android.view.View.requestLayout(View.java:15473)
E/AndroidRuntime(796):     at android.view.View.requestLayout(View.java:15473)
E/AndroidRuntime(796):     at android.view.View.requestLayout(View.java:15473)
E/AndroidRuntime(796):     at android.view.View.requestLayout(View.java:15473)
E/AndroidRuntime(796):     at android.widget.ImageView.setImageDrawable(ImageView.java:406)
E/AndroidRuntime(796):     at android.widget.ImageView.setImageBitmap(ImageView.java:421)
E/AndroidRuntime(796):     at com.example.thread01.MainActivity$2$1.run(MainActivity.java:80)

Handler 的構(gòu)造函數(shù)暫且介紹到這里,接下來介紹:handleMessage 和 dispatchMessage:
    /**
     * Subclasses must implement this to receive messages.
     
*/
    public void handleMessage(Message msg) {
    }

    /**
     * Handle system messages here.
     
*/
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

前面提到有兩種方式來設(shè)置處理消息的代碼:一種是設(shè)置 Callback 回調(diào),一種是子類化 Handler。而子類化 Handler 其子類就要實現(xiàn) handleMessage 來處理自定義的消息,如前面的匿名子類示例一樣。dispatchMessage 是在 Looper::Loop() 中被調(diào)用,即它是在線程的消息處理循環(huán)中被調(diào)用,這樣就能讓 Handler 不斷地處理各種消息。在 dispatchMessage 的實現(xiàn)中可以看到,如果 Message 有自己的消息處理回調(diào),那么就優(yōu)先調(diào)用消息自己的消息處理回調(diào):
    private static void handleCallback(Message message) {
        message.callback.run();
    }

否則看Handler 是否有消息處理回調(diào) mCallback,如果有且 mCallback 成功處理了這個消息就返回了,否則就調(diào)用 handleMessage(通常是子類的實現(xiàn)) 來處理消息。

在分析 Looper::Loop() 這個關(guān)鍵函數(shù)之前,先來理一理 Thread,Looper,Handler,MessageQueue 的關(guān)系:Thread 需要有 Looper 才能處理消息(也就是說 Looper 是運(yùn)行在 Thread 中),這是通過在自定義 Thread 的 run() 函數(shù)中調(diào)用 Looper::prepare() 和 Looper::loop() 來實現(xiàn),然后在 Looper::loop() 中不斷地從 MessageQueue 獲取由 Handler 投遞到其中的 Message,并調(diào)用 Message 的成員變量 Handler 的 dispatchMessage 來處理消息。

下面先來看看 Looper 的構(gòu)造函數(shù):
    final MessageQueue mQueue;
    final Thread mThread;
    volatile boolean mRun;

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mRun = true;
        mThread = Thread.currentThread();
    }

Looper 的構(gòu)造函數(shù)很簡單,創(chuàng)建MessageQueue,保存當(dāng)前線程到 mThread 中。但它是私有的,只能通過兩個靜態(tài)函數(shù) prepare()/prepareMainLooper() 來調(diào)用,前面已經(jīng)介紹了 prepare(),下面來介紹 prepareMainLooper():
    /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {
@link #prepare()}
     
*/
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

prepareMainLooper 是通過調(diào)用 prepare 實現(xiàn)的,不過傳入的參數(shù)為 false,表示 main Looper 不允許中途被中止,創(chuàng)建之后將looper 保持在靜態(tài)變量 sMainLooper 中。整個 Framework 框架只有兩個地方調(diào)用了 prepareMainLooper 方法:

第一處是在 SystemServer.java 中的 ServerThread,ServerThread 的重要性就不用說了,絕大部分 Android Service 都是這個線程中初始化的。這個線程是在 Android 啟動過程中的 init2() 方法啟動的:
    public static final void init2() {
        Slog.i(TAG, "Entered the Android system server!");
        Thread thr = new ServerThread();
        thr.setName("android.server.ServerThread");
        thr.start();
    }
class ServerThread extends Thread {
    @Override
    public void run() {
        
        Looper.prepareMainLooper();
        
        Looper.loop();
        Slog.d(TAG, "System ServerThread is exiting!");
    }
}

第二處是在 ActivityThread.java 的 main() 方法中:
    public static void main(String[] args) {
        .
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        AsyncTask.init();

        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

ActivityThread 的重要性也不言而喻,它是 Activity 的主線程,也就是 UI 線程。注意這里的 AsyncTask.init() ,在后面介紹 AsyncTask 時會詳細(xì)介紹的,這里只提一下:AsyncTask 能夠進(jìn)行 UI 操作正是由于在這里調(diào)用了 init()。

有了前面的鋪墊,這下我們就可以來分析 Looper::Loop() 這個關(guān)鍵函數(shù)了:
   /**
     * Run the message queue in this thread. Be sure to call
     * {
@link #quit()} to end the loop.
     
*/
    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;
        
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            msg.target.dispatchMessage(msg);

            msg.recycle();
        }
    }

loop() 的實現(xiàn)非常簡單,一如前面一再說過的那樣:不斷地從 MessageQueue 中獲取消息,分發(fā)消息,回收消息。從上面的代碼可以看出,loop() 僅僅是一個不斷循環(huán)作業(yè)的生產(chǎn)流水線,而 MessageQueue 則為它提供原材料 Message,讓它去分發(fā)處理。至于 Handler 是怎么提交消息到 MessageQueue 中,MessageQueue 又是怎么管理消息的,且待下文分解。
posted on 2014-07-12 11:00 羅朝輝 閱讀(3017) 評論(0)  編輯 收藏 引用 所屬分類: 移動開發(fā)
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲私拍自拍| 久久精品水蜜桃av综合天堂| 在线一区免费观看| 欧美在线亚洲| 亚洲啪啪91| 夜夜嗨av一区二区三区网站四季av| 一区二区高清在线| 日韩一区二区高清| 久久一区精品| 国产中文一区| 亚洲男人天堂2024| 亚洲人成小说网站色在线| 欧美精品日韩一区| 亚洲国产视频一区二区| 久久精品国产99精品国产亚洲性色| 午夜视频一区在线观看| 国产精品豆花视频| 这里只有视频精品| 先锋影音久久| 91久久久久久久久久久久久| 久久久亚洲国产天美传媒修理工| 亚洲午夜在线观看视频在线| 黄色精品一区二区| 久久er精品视频| 蜜桃精品久久久久久久免费影院| 国产在线精品成人一区二区三区| 欧美激情视频给我| 久久伊人亚洲| 精品动漫一区| 久久久久久久综合色一本| 欧美11—12娇小xxxx| 亚洲人成网站999久久久综合| 夜夜嗨av一区二区三区中文字幕 | 久久综合九色99| 亚洲午夜精品一区二区三区他趣| 亚洲激情国产| 国产喷白浆一区二区三区| 久久国产欧美日韩精品| 欧美二区视频| 在线播放不卡| 最新中文字幕一区二区三区| 国产色视频一区| 玖玖综合伊人| 欧美国产高清| 欧美18av| 欧美看片网站| 欧美一区二区三区视频| 欧美亚洲综合网| 伊人久久婷婷色综合98网| 国产精品99久久99久久久二8| 国产麻豆视频精品| 久热精品视频在线免费观看| 国产精品免费一区豆花| 久久综合九色综合欧美就去吻| 久久久久免费观看| 99在线视频精品| 麻豆成人综合网| 蜜乳av另类精品一区二区| 欧美欧美全黄| 亚洲二区在线视频| 国产精品扒开腿做爽爽爽视频| 性欧美精品高清| 久久综合网络一区二区| 久久午夜色播影院免费高清| 国产手机视频精品| 午夜国产不卡在线观看视频| 亚洲欧洲精品一区二区精品久久久| 欧美一级播放| 久久国产欧美| 韩国女主播一区| 久久久久久久尹人综合网亚洲| 老色批av在线精品| 在线观看亚洲专区| 亚洲自拍偷拍视频| 亚洲国产精品免费| 亚洲欧美日本伦理| 久久www成人_看片免费不卡| 国产区亚洲区欧美区| 久久精品青青大伊人av| 亚洲女同在线| 国产农村妇女毛片精品久久麻豆 | 欧美高清自拍一区| 国产欧美一级| 久久九九全国免费精品观看| 欧美不卡在线| 亚洲裸体视频| 免费观看亚洲视频大全| 亚洲三级视频| 午夜精品区一区二区三| 欧美日韩99| 欧美黄色aaaa| 亚洲色诱最新| 欧美日本成人| 午夜精品www| 欧美国产日本韩| 亚洲欧美日韩综合| 影音国产精品| 欧美日韩一区二区免费在线观看| 欧美国产综合视频| 亚洲视频日本| 精品动漫一区| 国产精品国产三级国产普通话蜜臀| 欧美影院成年免费版| 性一交一乱一区二区洋洋av| 国内精品视频一区| 欧美激情综合色| 性欧美xxxx大乳国产app| 亚洲福利国产精品| 久久国产精品亚洲va麻豆| 亚洲精品中文字幕有码专区| 国产免费亚洲高清| 欧美久久久久久蜜桃| 西西裸体人体做爰大胆久久久| 亚洲国产视频一区二区| 日韩午夜免费视频| 欧美三级电影一区| 亚洲欧美999| 亚洲国产婷婷香蕉久久久久久99| 欧美一区免费视频| 亚洲视频网站在线观看| 亚洲国产日韩综合一区| 国产精品一区二区三区乱码| 欧美精品成人| 男人天堂欧美日韩| 久久精品亚洲精品| 午夜视频在线观看一区| 一区二区日韩伦理片| 性色av一区二区三区在线观看| 亚洲精品女av网站| 国产精品普通话对白| 久久久91精品国产| 欧美一区二区私人影院日本 | 99视频一区二区三区| 欧美激情亚洲自拍| 欧美不卡在线视频| 美国十次成人| 美女91精品| 免费成人av在线| 欧美mv日韩mv国产网站| 免费一级欧美在线大片| 久久综合精品一区| 蜜桃视频一区| 亚洲大片在线观看| 亚洲电影观看| 亚洲精品五月天| 久久久青草婷婷精品综合日韩| 亚洲欧美日韩区| 午夜一区二区三区不卡视频| 午夜在线观看欧美| 欧美一区二区三区成人| 久久av红桃一区二区小说| 久久国产精品一区二区三区四区| 久久岛国电影| 久久一二三四| 欧美国产日韩亚洲一区| 亚洲精品国产精品国产自| 亚洲日本va午夜在线影院| 亚洲精品资源| 亚洲综合电影一区二区三区| 欧美一区二区三区的| 欧美一区二区三区在线| 久久夜色精品亚洲噜噜国产mv| 毛片一区二区三区| 欧美日韩国产在线看| 国产精品女主播| 一区精品在线| 一区二区久久久久| 欧美伊人影院| 亚洲第一网站| 亚洲图片欧美午夜| 久久久久九九九| 欧美精品一区二区三| 国产伦一区二区三区色一情| 伊人久久久大香线蕉综合直播| 亚洲精品乱码久久久久久蜜桃91| 亚洲自拍偷拍视频| 国产精品99久久久久久人| 欧美亚洲一级片| 亚洲第一精品夜夜躁人人爽| 亚洲午夜精品久久久久久浪潮| 欧美在线资源| 欧美特黄一级大片| 精品69视频一区二区三区| 在线视频一区观看| 老司机午夜免费精品视频| 一本色道久久综合一区| 久久久久久久久久久久久女国产乱| 欧美日韩美女| 亚洲国产裸拍裸体视频在线观看乱了中文 | 久久久成人精品| 久久久高清一区二区三区| 亚洲国产欧美不卡在线观看| 亚洲欧美在线aaa| 欧美黑人国产人伦爽爽爽| 国产一区二区精品丝袜| 在线观看中文字幕不卡| 亚洲欧美日韩国产精品| 欧美黑人一区二区三区| 欧美在线影院在线视频| 国产精品激情|