<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Blogger Scott

    淺析Android線程模型一 --- 轉(zhuǎn)

    淺析Android線程模型一 --- 轉(zhuǎn)

    2 Android進(jìn)程

    在了解Android線程之間得先了解一下Android的進(jìn)程。當(dāng)一個(gè)程序第一次啟動(dòng)的時(shí)候,Android會(huì)啟動(dòng)一個(gè)LINUX進(jìn)程和一個(gè)主線程。默認(rèn)的情況下,所有該程序的組件都將在該進(jìn)程和線程中運(yùn)行。同時(shí),Android會(huì)為每個(gè)應(yīng)用程序分配一個(gè)單獨(dú)的LINUX用戶。Android會(huì)勁量保留一個(gè)正在運(yùn)行進(jìn)程,只在內(nèi)存資源出現(xiàn)不足時(shí),Android會(huì)參試停止一些進(jìn)程從而釋放足夠的資源給其他新的進(jìn)程使用, 也能保證用戶正在訪問的當(dāng)前進(jìn)程有足夠的資源去及時(shí)的響應(yīng)用戶的事件。Android會(huì) 根據(jù)進(jìn)程中運(yùn)行的組件類別以及組件的狀態(tài)來判斷該進(jìn)程的重要性,Android會(huì) 首先停止那些不重要的進(jìn)程。按照重要性從高到低一共有五個(gè)級(jí)別:

    l  前臺(tái)進(jìn)程

    前臺(tái)進(jìn)程是用戶當(dāng)前正在使用的進(jìn)程。只有一些前臺(tái)進(jìn)程可以在任何時(shí)候都存在。他們是最后一個(gè)被結(jié)束的,當(dāng)內(nèi)存低到根本連他們都不能運(yùn)行的時(shí)候。一般來說, 在這種情況下,設(shè)備會(huì)進(jìn)行內(nèi)存調(diào)度,中止一些前臺(tái)進(jìn)程來保持對(duì)用戶交互的響應(yīng)。

    l  可見進(jìn)程

    可見進(jìn)程不包含前臺(tái)的組件但是會(huì)在屏幕上顯示一個(gè)可見的進(jìn)程是的重要程度很高,除非前臺(tái)進(jìn)程需要獲取它的資源,不然不會(huì)被中止。

    l  服務(wù)進(jìn)程

    運(yùn)行著一個(gè)通過startService() 方法啟動(dòng)的service,這個(gè)service不屬于上面提到的2種更高重要性的。service所在的進(jìn)程雖然對(duì)用戶不是直接可見的,但是他們執(zhí)行了用戶非常關(guān)注的任務(wù)(比如播放mp3,從網(wǎng)絡(luò)下載數(shù)據(jù))。只要前臺(tái)進(jìn)程和可見進(jìn)程有足夠的內(nèi)存,系統(tǒng)不會(huì) 回收他們。

    l  后臺(tái)進(jìn)程

    運(yùn)行著一個(gè)對(duì)用戶不可見的activity(調(diào)用過 onStop() 方法).這些進(jìn)程對(duì)用戶體驗(yàn)沒有直接的影響,可以在服務(wù)進(jìn)程、可見進(jìn)程、前臺(tái)進(jìn) 程需要內(nèi)存的時(shí)候回收。通常,系統(tǒng)中會(huì)有很多不可見進(jìn)程在運(yùn)行,他們被保存在LRU (least recently used) 列表中,以便內(nèi)存不足的時(shí)候被第一時(shí)間回收。如果一個(gè)activity正 確的執(zhí)行了它的生命周期,關(guān)閉這個(gè)進(jìn)程對(duì)于用戶體驗(yàn)沒有太大的影響。

    l  空進(jìn)程

    未運(yùn)行任何程序組件。運(yùn)行這些進(jìn)程的唯一原因是作為一個(gè)緩存,縮短下次程序需要重新使用的啟動(dòng)時(shí)間。系統(tǒng)經(jīng)常中止這些進(jìn)程,這樣可以調(diào)節(jié)程序緩存和系統(tǒng)緩 存的平衡。

    Android 對(duì)進(jìn)程的重要性評(píng)級(jí)的時(shí)候,選取它最高的級(jí)別。另外,當(dāng)被另外的一個(gè)進(jìn)程依賴的時(shí)候,某個(gè)進(jìn)程的級(jí)別可能會(huì)增高。一個(gè)為其他進(jìn)程服務(wù)的進(jìn)程永遠(yuǎn)不會(huì)比被服 務(wù)的進(jìn)程重要級(jí)低。因?yàn)榉?wù)進(jìn)程比后臺(tái)activity進(jìn)程重 要級(jí)高,因此一個(gè)要進(jìn)行耗時(shí)工作的activity最好啟動(dòng)一 個(gè)service來做這個(gè)工作,而不是開啟一個(gè)子進(jìn)程――特別 是這個(gè)操作需要的時(shí)間比activity存在的時(shí)間還要長(zhǎng)的時(shí) 候。例如,在后臺(tái)播放音樂,向網(wǎng)上上傳攝像頭拍到的圖片,使用service可 以使進(jìn)程最少獲取到“服務(wù)進(jìn)程”級(jí)別的重要級(jí),而不用考慮activity目 前是什么狀態(tài)。broadcast receivers做費(fèi)時(shí)的工作的時(shí)候,也應(yīng)該啟用一個(gè)服務(wù)而不是開一個(gè)線程。

     2單線程模型

        當(dāng)一個(gè)程序第一次啟動(dòng)時(shí),Android會(huì)同時(shí)啟動(dòng)一個(gè)對(duì)應(yīng)的 主線程(Main Thread),主線程主要負(fù)責(zé)處理與UI相關(guān)的事件,如:用戶的按鍵事件,用戶接觸屏幕的事件以及屏幕繪圖事 件,并把相關(guān)的事件分發(fā)到對(duì)應(yīng)的組件進(jìn)行處理。所以主線程通常又被叫做UI線 程。在開發(fā)Android應(yīng)用時(shí)必須遵守單線程模型的原則: Android UI操作并不是線程安全的并且這些操作必須在UI線程中執(zhí)行。

    2.1 案例演示

    如果在沒有理解這樣的單線程模型的情況下,設(shè)計(jì)的程序可能會(huì)使程序性能低下,因?yàn)樗械膭?dòng)作都在同一個(gè)線 程中觸發(fā)。例如當(dāng)主線程正在做一些比較耗時(shí)的操作的時(shí)候,如正從網(wǎng)絡(luò)上下載一個(gè)大圖片,或者訪問數(shù)據(jù)庫,由于主線程被這些耗時(shí)的操作阻塞住,無法及時(shí)的響 應(yīng)用戶的事件,從用戶的角度看會(huì)覺得程序已經(jīng)死掉。如果程序長(zhǎng)時(shí)間不響應(yīng),用戶還可能得重啟系統(tǒng)。為了避免這樣的情況,Android設(shè) 置了一個(gè)5秒 的超時(shí)時(shí)間,一旦用戶的事件由于主線程阻塞而超過5秒 鐘沒有響應(yīng),Android會(huì) 彈出一個(gè)應(yīng)用程序沒有響應(yīng)的對(duì)話框。下面將通過一個(gè)案例來演示這種情況:

    本程序?qū)⒃O(shè)計(jì)和實(shí)現(xiàn)查看指定城市的當(dāng)天天氣情況的功能,

    1.  首先,需要選擇一個(gè)天氣查詢的 服務(wù)接口,目前可供選擇的接口很多,諸如YAHOO的 天氣APIGoogle提 供的天氣API。 本文將選擇GOOGLE 的 天氣查詢API。 該接口提供了多種查詢方式,可以通過指定具體城市的經(jīng)緯度進(jìn)行查詢,也可以通過城市名稱進(jìn)行查詢。

    2.  用戶在輸入框內(nèi)輸入需要查詢的 城市名稱,然后點(diǎn)擊查詢按鈕

    3.  當(dāng)用戶點(diǎn)擊查詢按鈕后,使用已 經(jīng)內(nèi)置在Android SDK中的HttpClient API來調(diào)用GOOGLE 的 天氣查詢API, 然后解析返回的指定城市的天氣信息,并把該天氣信息顯示在Title

    主要代碼如下:

    public class WeatherReport extends Activity implements OnClickListener {

        private static final String GOOGLE_API_URL = "http://www.google.com/ig/api?weather=";

        private static final String NETWORK_ERROR = "網(wǎng)絡(luò)異常";

        private EditText editText;

        @Override

        public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.main);

            editText = (EditText) findViewById(R.id.weather_city_edit);

            Button button = (Button) findViewById(R.id.goQuery);

            button.setOnClickListener(this);

        }

        @Override

        public void onClick(View v) {

            //獲得用戶輸入的城市名稱

            String city = editText.getText().toString();

            //調(diào)用Google 天氣API查詢指定城市的當(dāng)日天氣 情況

            String weather = getWetherByCity(city);

            //把天氣信息顯示在title

            setTitle(weather);

        }

        

        public String getWetherByCity(String city) {

            HttpClient httpClient = new DefaultHttpClient();

            HttpContext localContext = new BasicHttpContext();

            HttpGet httpGet = new HttpGet(GOOGLE_API_URL + city);

            try {

                HttpResponse response = httpClient.execute(httpGet, localContext);

                if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {

                    httpGet.abort();

                else {

                    HttpEntity httpEntity = response.getEntity();

                    return parseWeather(httpEntity.getContent());

                }

            catch (Exception e) {

                Log.e("WeatherReport""Failed to get weather", e);

            finally {

                httpClient.getConnectionManager().shutdown();

            }

            return NETWORK_ERROR;

        }

    }

    當(dāng)用戶輸入城市名稱,然后單擊按鈕進(jìn)行查詢后,程序會(huì)調(diào)用Google API的接口獲得指定城市的當(dāng)日天氣情況。由于需要訪問網(wǎng)絡(luò),所以當(dāng)網(wǎng)絡(luò)出現(xiàn)異常或者服務(wù)繁忙的時(shí)候都會(huì)使訪問網(wǎng)絡(luò)的動(dòng)作很耗時(shí)。本文為了 要演示超時(shí)的現(xiàn)象,只需要制造一種網(wǎng)絡(luò)異常的狀況,最簡(jiǎn)單的方式就是斷開網(wǎng)絡(luò)連接,然后啟動(dòng)該程序,同時(shí)觸發(fā)一個(gè)用戶事件,比如按一下MENU鍵, 由于主線程因?yàn)榫W(wǎng)絡(luò)異常而被長(zhǎng)時(shí)間阻塞,所以用戶的按鍵事件在5秒 鐘內(nèi)得不到響應(yīng),Android會(huì) 提示一個(gè)程序無法響應(yīng)的異常,如下圖:




     

    該對(duì)話框會(huì)詢問用戶 是繼續(xù)等待還是強(qiáng)行退出程序。當(dāng)你的程序需要去訪問未知的網(wǎng)絡(luò)的時(shí)候都會(huì)可能會(huì)發(fā)生類似的超時(shí)的情況,用戶的響應(yīng)得不到及時(shí)的回應(yīng)會(huì)大大的降低用戶體驗(yàn)。 所以我們需要參試以別的方式來實(shí)現(xiàn) 

    2.1 子線程更新UI

        顯然如果你的程序需要執(zhí)行耗時(shí)的操作的話,如果像上例一樣由主線程來負(fù)責(zé)執(zhí)行 該操作是錯(cuò)誤的。所以我們需要在onClick方 法中創(chuàng)建一個(gè)新的子線程來負(fù)責(zé)調(diào)用GOOGLE API來獲得天氣數(shù)據(jù)。剛接觸Android的 開發(fā)者最容易想到的方式就是如下:

        public void onClick(View v) {

           //創(chuàng)建一個(gè)子線程執(zhí)行耗時(shí)的從網(wǎng)絡(luò)上獲取天氣信息的操作

           new Thread() {

               @Override

               public void run() {

                  //獲得用戶輸入的城市名稱

                  String city = editText.getText().toString();

                  //調(diào)用Google 天氣API查詢指定城市的當(dāng)日天氣 情況

                  String weather = getWetherByCity(city);

                  //把天氣信息顯示在title

                  setTitle(weather);

               }

           }.start();

        }

    但是很不幸,你會(huì)發(fā) 現(xiàn)Android會(huì) 提示程序由于異常而終止。為什么在其他平臺(tái)上看起來很簡(jiǎn)單的代碼在Android上運(yùn)行的時(shí)候依然會(huì)出錯(cuò)呢?如果你觀察LogCat中打印的日志信息就會(huì)發(fā)現(xiàn)這樣的錯(cuò)誤日志:

    android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

    從錯(cuò)誤信息不難看出Android禁 止其他子線程來更新由UI thread創(chuàng)建的試圖。本例中顯示天氣信息的title實(shí)際是就是一個(gè)由UI thread所創(chuàng)建的TextView,所以參試在一個(gè)子線程中去更改TextView的時(shí)候就出錯(cuò)了。這顯示違背了單線程模型的原則:Android UI操作并不是線程安全的并且這些操作必須在UI線 程中執(zhí)行 

    2.2 Message Queue

    在單線程模型下,為 了解決類似的問題,Android設(shè) 計(jì)了一個(gè)Message Queue(消息隊(duì)列), 線程間可以通過該Message Queue并結(jié)合HandlerLooper組 件進(jìn)行信息交換。下面將對(duì)它們進(jìn)行分別介紹:

    l  Message Queue

    Message Queue是一個(gè)消息隊(duì)列,用來存放通過Handler發(fā) 布的消息。消息隊(duì)列通常附屬于某一個(gè)創(chuàng)建它的線程,可以通過Looper.myQueue()得 到當(dāng)前線程的消息隊(duì)列。Android在 第一啟動(dòng)程序時(shí)會(huì)默認(rèn)會(huì)為UI thread創(chuàng)建一個(gè)關(guān)聯(lián)的消息隊(duì)列,用來管理程序的一些上層組件,activitiesbroadcast receivers 等等。你可以在自己的子線程中創(chuàng)建HandlerUI thread通訊。

    l  Handler

    通過Handler你 可以發(fā)布或者處理一個(gè)消息或者是一個(gè)Runnable的 實(shí)例。沒個(gè)Handler都 會(huì)與唯一的一個(gè)線程以及該線程的消息隊(duì)列管理。當(dāng)你創(chuàng)建一個(gè)新的Handler時(shí)候,默認(rèn)情況下,它將關(guān)聯(lián)到創(chuàng)建它的這個(gè)線程和該線程的消息隊(duì)列。也就是說,如果你通過Handler發(fā) 布消息的話,消息將只會(huì)發(fā)送到與它關(guān)聯(lián)的這個(gè)消息隊(duì)列,當(dāng)然也只能處理該消息隊(duì)列中的消息。

    主要的方法有:

    1)   public final boolean sendMessage(Message msg)

    把消息放入該Handler所 關(guān)聯(lián)的消息隊(duì)列,放置在所有當(dāng)前時(shí)間前未被處理的消息后。

    2)   public void handleMessage(Message msg)

    關(guān)聯(lián)該消息隊(duì)列的線 程將通過調(diào)用HandlerhandleMessage方 法來接收和處理消息,通常需要子類化Handler來 實(shí)現(xiàn)handleMessage

    l  Looper

    Looper扮演著一個(gè)Handler和 消息隊(duì)列之間通訊橋梁的角色。程序組件首先通過Handler把 消息傳遞給LooperLooper把 消息放入隊(duì)列。Looper也 把消息隊(duì)列里的消息廣播給所有的HandlerHandler接 受到消息后調(diào)用handleMessage進(jìn) 行處理。

    1)   可以通過Looper類 的靜態(tài)方法Looper.myLooper得 到當(dāng)前線程的Looper實(shí) 例,如果當(dāng)前線程未關(guān)聯(lián)一個(gè)Looper實(shí) 例,該方法將返回空。

    2)   可以通過靜態(tài)方法Looper. getMainLooper方法得到主線程的Looper實(shí) 例

    線程,消息隊(duì)列,HandlerLooper之 間的關(guān)系可以通過一個(gè)圖來展示:

    在了解了消息隊(duì)列及 其相關(guān)組件的設(shè)計(jì)思想后,我們將把天氣預(yù)報(bào)的案例通過消息隊(duì)列來重新實(shí)現(xiàn):

    在了解了消息隊(duì)列及其相關(guān)組件的設(shè)計(jì)思想后,我們將把天氣預(yù)報(bào)的案例通過消息隊(duì)列來重新實(shí)現(xiàn):

    private EditText editText;

        private Handler messageHandler;

        @Override

        public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.main);

            editText = (EditText) findViewById(R.id.weather_city_edit);

            Button button = (Button) findViewById(R.id.goQuery);

            button.setOnClickListener(this);

            //得到當(dāng)前線程 的Looper實(shí)例,由于 當(dāng)前線程是UI線程也可以 通過Looper.getMainLooper()得到

            Looper looper = Looper.myLooper();

            //此處甚至可以 不需要設(shè)置Looper,因?yàn)?/span> Handler默認(rèn)就使用當(dāng) 前線程的Looper

            messageHandler = new MessageHandler(looper);

        }

     

        @Override

        public void onClick(View v) {

            //創(chuàng)建一個(gè)子線 程去做耗時(shí)的網(wǎng)絡(luò)連接工作

            new Thread() {

                @Override

                public void run() {

                    //活動(dòng)用戶輸入 的城市名稱

                    String city = editText.getText().toString();

                    //調(diào)用Google 天氣API查詢指定城 市的當(dāng)日天氣情況

                    String weather = getWetherByCity(city);

                    //創(chuàng)建一個(gè)Message對(duì)象,并把得 到的天氣信息賦值給Message對(duì)象

                    Message message = Message.obtain();

                    message.obj = weather;

                    //通過Handler發(fā)布攜帶有天 氣情況的消息

                    messageHandler.sendMessage(message);

                }

            }.start();

        }

     

        //子類化一個(gè)Handler

        class MessageHandler extends Handler {

            public MessageHandler(Looper looper) {

                super(looper);

            }

            @Override

            public void handleMessage(Message msg) {

                //處理收到的消 息,把天氣信息顯示在title

                setTitle((String) msg.obj);

            }

        }

    通過消息隊(duì)列改寫過后的天氣預(yù)報(bào)程序已經(jīng)可以成功運(yùn)行,因?yàn)?/span>HandlerhandleMessage方法實(shí) 際是由關(guān)聯(lián)有該消息隊(duì)列的UI thread調(diào)用,而在UI thread中更新title并沒有違背Android的單線程模型的原 則。

    2.3 AsyncTask

    雖然借助消息隊(duì)列已經(jīng)可以較為完美的實(shí)現(xiàn)了天氣預(yù)報(bào)的功能,但是你還是不得不自己管理子線程,尤其當(dāng)你的需要有一些復(fù)雜的邏輯以及需要頻繁的更新UI的時(shí)候,這樣的方式使得你的代碼難以閱讀和理解。

    幸運(yùn)的是Android另外提供了一個(gè)工具類:AsyncTask。它使得UI thread的使用變得異常簡(jiǎn)單。它使創(chuàng)建需要與用戶界面交互的長(zhǎng)時(shí)間運(yùn)行的任務(wù)變得更簡(jiǎn)單,不需要借助線程和Handler即可實(shí)現(xiàn)。

    1)   子類化AsyncTask

    2)   實(shí)現(xiàn)AsyncTask中定義的下面一個(gè)或幾個(gè)方法

    ?  onPreExecute(), 該方法將在執(zhí)行實(shí)際的后臺(tái)操作前被UI thread調(diào)用。可以在該方法中做一些準(zhǔn)備工作,如在界面上顯示一個(gè)進(jìn)度條。

    ?  doInBackground(Params...), 將在onPreExecute 方法執(zhí)行后馬上執(zhí)行,該方法運(yùn)行在后臺(tái)線程中。這里將主要負(fù)責(zé)執(zhí)行那些很耗時(shí)的后臺(tái)計(jì)算工作。可以調(diào)用publishProgress方法來更新實(shí)時(shí)的任務(wù)進(jìn)度。該方法是抽象方法,子類必須實(shí)現(xiàn)。

    ?  3. onProgressUpdate(Progress...),publishProgress方 法被調(diào)用后,UI thread將調(diào)用這個(gè)方法從而在界面上展示任務(wù)的進(jìn)展情況,例如通過一個(gè)進(jìn)度條進(jìn)行展示。

    ?  4. onPostExecute(Result), doInBackground 執(zhí)行完成后,onPostExecute 方法將被UI thread調(diào)用,后臺(tái)的計(jì)算結(jié)果將通過該方法傳遞到UI thread.

    為了正確的使用AsyncTask類,以下是幾條必須遵守的準(zhǔn) 則:

    1)   Task的實(shí)例 必須在UI thread中創(chuàng)建

    2)   execute方 法必須在UI thread中調(diào)用

    3)   不要手動(dòng)的調(diào)用onPreExecute(), onPostExecute(Result)doInBackground(Params...), onProgressUpdate(Progress...)這幾個(gè)方法

    4)   task只能被執(zhí)行一次,否則多次調(diào)用時(shí)將會(huì)出現(xiàn)異常

    下面我們將通過AsyncTask并且嚴(yán)格遵守上面的4條準(zhǔn)則來改寫天氣預(yù)報(bào)的例子:

        public void onCreate(Bundle savedInstanceState) {

           super.onCreate(savedInstanceState);

           setContentView(R.layout.main);

           editText = (EditText) findViewById(R.id.weather_city_edit);

           Button button = (Button) findViewById(R.id.goQuery);

           button.setOnClickListener(this);

        }

        public void onClick(View v) {

           //獲得用戶輸 入的城市名稱

           String city = editText.getText().toString();

        //必須每次都 重新創(chuàng)建一個(gè)新的task實(shí)例進(jìn)行 查詢,否則將提示如下異常信息

        //the task has already been executed (a task can be executed only once)

           new GetWeatherTask().execute(city);

        }

        class GetWeatherTask extends AsyncTask<String, Integer, String> {

           @Override

           protected String doInBackground(String... params) {

               String city = params[0];

               //調(diào)用Google 天氣API查詢指定 城市的當(dāng)日天氣情況

               return getWetherByCity(city);

           }

           protected void onPostExecute(String result) {

               //doInBackground處理的結(jié)果 即天氣信息顯示在title

               setTitle(result);

           }

        } 

    注意這行代 碼:new GetWeatherTask().execute(city); 值得一提的是必須每次都重新創(chuàng)建一個(gè)新的GetWeatherTask來執(zhí)行后臺(tái)任務(wù),否則Android會(huì)提示“a task can be executed only once”的錯(cuò)誤信息。 

    經(jīng)過改寫后的 程序不僅顯得非常的簡(jiǎn)潔,而且還減少了代碼量,大大增強(qiáng)了可讀性和可維護(hù)性。因?yàn)樨?fù)責(zé)更新UIonPostExecute方 法是由UI thread調(diào)用,所以沒有違背單線程模型的原則。良好的AsyncTask設(shè)計(jì)大大降低了我們犯錯(cuò)誤的幾率。 

    5綜述

        本文首先大致介紹了Android的單線程模型及其原則。然后通過一個(gè)真實(shí)案例展示剛接觸Android的 開發(fā)人員在不理解Android的 單線程模型下容易犯的錯(cuò)誤。最后通過幾種正確的方式實(shí)現(xiàn)該案例,進(jìn)一步認(rèn)識(shí)和理解Android的單線程模型及其原則。由于更多地關(guān)注線程模型,本文或許不足以幫助讀者全面的認(rèn)識(shí)Android技 術(shù),關(guān)于文中提到的其他技術(shù)細(xì)節(jié)以及Android的 其他相關(guān)技術(shù)可以訪問Android的 官方網(wǎng)站進(jìn)行進(jìn)一步的了解和學(xué)習(xí)。

    posted on 2011-11-12 23:51 江天部落格 閱讀(661) 評(píng)論(1)  編輯  收藏 所屬分類: Android

    Feedback

    # re: 淺析Android線程模型一 --- 轉(zhuǎn) 2012-04-28 13:10 And

    能不能把文字寫的通順一些?  回復(fù)  更多評(píng)論   

    主站蜘蛛池模板: 激情五月亚洲色图| 免费国产黄线在线观看| 久久久久亚洲AV无码观看| 国产精品视频免费一区二区| 一级毛片免费在线| 亚洲国产成人超福利久久精品| 深夜国产福利99亚洲视频| 18pao国产成视频永久免费| 黄视频在线观看免费| 亚洲欧洲专线一区| 亚洲国产成人无码av在线播放| 哒哒哒免费视频观看在线www | 国产精品视频白浆免费视频| 美女被免费视频网站| 亚洲精品无码成人片久久不卡 | 91福利免费视频| 99精品视频在线免费观看| 色播在线永久免费视频网站| 美景之屋4在线未删减免费| 亚洲色图激情文学| 亚洲国产成人手机在线观看| 亚洲一卡2卡4卡5卡6卡在线99 | 免费黄色app网站| 在线中文高清资源免费观看| 好男人看视频免费2019中文| 成全高清视频免费观看| 在线日韩av永久免费观看| 日日操夜夜操免费视频| 久久亚洲国产成人影院网站| 在线亚洲97se亚洲综合在线| 亚洲欧洲成人精品香蕉网| 亚洲人成网站在线播放影院在线| 水蜜桃亚洲一二三四在线| 亚洲一线产品二线产品| 亚洲a无码综合a国产av中文| 国产成人自产拍免费视频| 免费看男女下面日出水来| 亚洲国产精品视频| 亚洲图片校园春色| 男人天堂免费视频| 特级淫片国产免费高清视频|