日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

安卓四大组件之内容提供者

發布時間:2024/8/26 综合教程 26 生活家
生活随笔 收集整理的這篇文章主要介紹了 安卓四大组件之内容提供者 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

內容提供者ContentProvider,是Android 的四大組件之一。內容提供者是應用程序之間共享數據的接口。應用程序創建的數據庫,默認情況下是私有的,別的應用程序訪問不到數據,如果想把數據對外提供,就要用到內容提供。ContentProvider屏蔽了數據存儲的細節,內部實現對用戶完全透明, 用戶只需要關心操作數據的uri就可以了,ContentProvider可以實現不同app之間共享。 Sql也有增刪改查的方法,但是sql只能查詢本應用下的數據庫。 而ContentProvider 還可以去增刪改查本地文件/xml文件的讀取等。Android 系統將這種機制應用到方方面面,比如:聯系人(通訊錄應用程序)Provider 專為不同應用程序提供聯系人數據;短信(短信應用程序)Provider 專為不同應用程序提供系統短信信息。當應用繼承ContentProvider 類,并重寫該類用于提供數據和存儲數據的方法,就可以向其他應用共享其數據。雖然使用其他方法也可以對外共享數據,但數據訪問方式會因數據存儲的方式而不同,如:采用文件方式對外共享數據,需要進行文件操作讀寫數據;采用SharedPreferences 共享數據,需要使用SharedPreferences API 讀寫數據。而使用ContentProvider 共享數據的好處是統一了數據訪問方式。總之,內容提供者管理了對結構化數據最常見的就是數據庫中數據的訪問,操作內容提供者是不同進程之間以數據庫數據形式交互數據的標準方式。

自定義的內容提供者包括內容提供者和訪問者兩個部分。

內容提供者,擁有自己的數據庫,將數據庫暴露出來供訪問者修改。ContenProvider的編寫基本步驟:
1. 寫一個類繼承 ContentProvider;
2. 重寫一系列的方法,包括數據庫操作的空實現;

3. 在內容提供者代碼內部定義UriMatcher -用于判斷uri是否匹配

static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 
static {
   mUriMatcher.addURI("在清單文件里面定義的authorities", "自定義匹配字符串", 成功返回的標識); 
}

4. 在增刪改查執行的時候判斷uri是否合法,在內容提供者內部實現對數據庫的增刪改查;

5. 清單文件的下面聲明provider,這里需要指定主機名,也就是對外提供的Uri,當訪問者在內容解析者中傳入同一個uri時,才可以訪問到數據庫;

<provider 
android:name="com.itheima.db.BankDBBackdoor"
android:authorities="自定義主機名" >
</provider>

訪問者,存在于另外一個工程中,可以對內提供者的數據庫進行操作。

1. 創建內容提供者解析器
ContentResolver resolver = 上下文.getContentResolver();

2.定義要訪問的Uri路徑
Uri uri = Uri.parse("content://自定義主機名/自定義匹配字符串") // “content://”是標準寫法

3.利用內容提供者解析器進行增刪改查,實現對數據庫的操作

內容提供者Uri 的書寫模板: content:// 主機名authority/path/id。具體的書寫規范如下所示:

1."content://" 這是個固定寫法,用來說明一個ContentProvider 控制這些數據。
2.主機名或授權Authority:它定義了是哪個ContentProvider 提供這些數據。
3.path:路徑,URI 下的某一個Item。
4.ID:通常定義Uri 時使用”#”號占位符代替, 使用時替換成對應的數字。#表示數據id,#代表任意數字,*用來來匹配任意文本

使用內容提供者操作系統短信和操作系統聯系人是我們開發中經常遇到的需求,而自定義內容提供者對外提供數據反而使用的場景并不多,除非我們開發的短信或者聯系人應用。一個小細節是,由于讀取和插入系統短信數據庫都涉及到可能侵犯用戶隱私,因此創建的工程必須添加相關的權限。下面就分別講解一下使用內容提供者操作系統數據庫和自定義內容提供者。

用內容提供者操作系統短信只需要關注的到系統短信數據庫的一張表,最長用的數據有body,date,type,address,各自的含義也較為直觀。body表示短信的內容,date表示發送短信或收到短信的時間,type表示是受到短信還是發送短信,address表示收到的短信來自于哪個手機號。讀取和插入系統短信數據庫需要添加如下權限:
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.WRITE_SMS"/>
使用內容觀察者操作系統聯系人時需要關注三張張數據表,rawcontact表 ,data表和 mimetype表。其中raw_contacts 表存放的是聯系人id 信息,一個聯系人就是表中的一行記錄。ontact_id在表單里應該是唯一的存在, 所以在插入的時候需要先查詢最后一條id是多少,然后在此基礎上加一。data 表中存放的是raw_contacts中的每一條id 對應的具體信息,一個聯系人可能有電話、郵件、姓名等多條信息,每一條信息在該表中都是一行記錄。為了區分不同信息的類型,因此還有一個mimetypes 表,該表存儲的是常量數據,不同類型的信息由mimetype_id 來標識。現在很多App 都可以對系統聯系人進行操作,這樣就可以直接將號碼添加到系統聯系人中,可以關聯/備份/恢復系統聯系人。讀取聯系人信息的基本步驟是,首先查詢rawcontact表,獲取聯系人的contactid,在rawcontact表中并不是每一個contact_id對應一條信息,而是一個contact_id對應多條信息,這樣可以存儲更多的信息。其次查詢根據contact_id查詢data表,獲取聯系人的數據 data1、mimetype,前者存儲相關數據,后者存儲該數據對應得數據。最后根據mimetype類型確定數據類型。修改聯系人的操作是往raw_contacts 表中插入一個id,值為n+1,作為一條新的記錄,然后往data1 表中插入具體的數據,其中id 必須為n+1。讀取和插入系統聯系人數據庫需要添加如下權限:
<uses-permission android:readPermission="android.permission.READ_CONTACTS"
<uses-permission android:writePermission="android.permission.WRITE_CONTACTS"

那么怎么才能獲取短信和聯系人的Uri呢。這時就需要看源碼了。打開Android 系統源碼,其中TelephonyProvider 就是短信的內容提供者文件。打開TelephonyProvider 下的src 文件,查看java 文件,其中的SmsProvider.java 即短信息內容提供者邏輯代碼。通過查找系統源碼,可以確定短信息內容提供者的Uri 應該為:”content://sms”。用同樣的方法,可以查到聯系人內容提供者的Uri路徑。打開Android 源碼,查看packagesproviders路徑下的文件,其中ContactsProvider 就是聯系人的內容提供者。打開ContactsProvider2.java文件,查看此內容提供者的uri 路徑。根據源碼,確定內容提供者的Uri 信息為:操作raw_contacts 表的Uri:content://com.android.contacts/raw_contacts。操作data 表的Uri:content://com.android.contacts/data。其實,平常寫代碼時不必要這么復雜,直接把Uri路徑拿來就可以用了。另外要注意的是,由于聯系人數據庫使用了視圖,所以操作數據庫表時,看到的表字段名稱和真實操作的有所不同。比如:data 表在查詢的時候沒有mimetype_id 字段,取代的是mimetype 字段。

再來講一講內容觀察者。內容提供者相當于一個監聽。觀察數據庫內容是否發生改變,如果改變,通知觀察者。內容觀察者ContentObserver,目的是觀察(捕捉)特定Uri 引起的數據庫的變化,繼而做一些相應的處理,它類似于數據庫技術中的觸發器(Trigger),當ContentObserver 所觀察的Uri 發生變化時,便會觸發它。觸發器分為表觸發器、行觸發器,相應的ContentObserver 也分為“表ContentObserver”、“行ContentObserver”,當然這是與它所監聽的Uri MIME Type 有關的。

內容觀察者的使用步驟:
1.在內容提供者類增加通知方法
getContext().getContentResolver().notifyChange(uri, null);
2.在觀察者類注冊觀察
//定義觀察的uri ,和內容提供者的Uri一直
Uri uri = Uri.parse("content://...");
//注冊觀察者
getContentResolver().registerContentObserver(uri, true, ContentObserver);

最后通過案例來演示今天的知識點。

案例一: 內容提供者操作短信

java代碼

/*
 * 添加權限
 *   <uses-permission android:name="android.permission.READ_SMS"/>
 *   <uses-permission android:name="android.permission.WRITE_SMS"/>
 */
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    /**利用內存提供者添加短信*/
    public void add(View view) {
        Uri uri = Uri.parse("content://sms");
        ContentResolver resolver = getContentResolver();
        ContentValues values = new ContentValues();
        values.put("address", "00000");
        values.put("date", System.currentTimeMillis());
        values.put("type", 1); // 表示收短信還是發短信
        values.put("body", "看到短信表示利用內容提供者添加短信成功");
        resolver.insert(uri, values);
    }
    /**利用內存提供者刪除短信*/
    public void delete(View view) {
        Uri uri = Uri.parse("content://sms");
        ContentResolver resolver = getContentResolver();
        resolver.delete(uri, "address = ?", new String[] {"00000"});
    }
}

布局文件中只定義了兩個按鈕

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="add"
        android:text="添加短信" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="delete"
        android:text="刪除短信" />

</LinearLayout>

效果展示:

添加短息:

刪除短信:

案例二: 內容提供者操作聯系人

JAVA代碼,主程序:

import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

import com.example.contact.domain.ContactInfo;
import com.example.contact.utils.ContactUtils;
//添加權限<uses-permission android:name="android.permission.READ_CONTACTS"/>
public class MainActivity extends Activity {

    private static final String TAG = "MainActivity";
    private ListView listview;
    private List<ContactInfo> contactlist;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listview = (ListView) findViewById(R.id.listview);
        contactlist = ContactUtils.getContact(this);
        Log.i(TAG, "info" + contactlist.size());
        for (ContactInfo info : contactlist) {
            Log.i(TAG, "info" + info.toString());
        }
        listview.setAdapter(new ContactAdapter());

    }

    public class ContactAdapter extends BaseAdapter {

        private ContactInfo contactInfo;

        @Override
        public int getCount() {
            return contactlist.size();
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            viewHolder holder;
            if (convertView == null) {
                holder = new viewHolder();
                convertView = View.inflate(MainActivity.this,
                        R.layout.item_contact, null);
                holder.tv_text = (TextView) convertView
                        .findViewById(R.id.tv_text);
                convertView.setTag(holder);
            } else {
                holder = (viewHolder) convertView.getTag();
            }
            contactInfo = contactlist.get(position);
            holder.tv_text.setText(contactInfo.toString());
            return convertView;
        }
    }

    public class viewHolder {
        TextView tv_text;
    }
}

聯系人工具類:

public class ContactInfo {
    private String name;
    private String phone;
    private String email;
    private String qq;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getQq() {
        return qq;
    }
    public void setQq(String qq) {
        this.qq = qq;
    }
    @Override
    public String toString() {
        return "ContactInfo [name=" + name + ", phone=" + phone + ", email="
                + email + ", qq=" + qq + "]";
    }
}

獲取系統聯系人:

import java.util.ArrayList;
import java.util.List;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;

import com.example.contact.domain.ContactInfo;

public class ContactUtils {
    public static List<ContactInfo> getContact(Context context) {        
        List<ContactInfo> list = new ArrayList<ContactInfo>();
        ContentResolver resolver = context.getContentResolver();
        Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
        Uri datauri = Uri.parse("content://com.android.contacts/data");
        Cursor cursor = resolver.query(uri, new String[] { "contact_id" },
                null, null, null);
        while (cursor.moveToNext()) {
            
            String id = cursor.getString(0);
            System.out.println("00"+id);
            if (id != null) {
                ContactInfo info = new ContactInfo();
                Cursor datacursor = resolver.query(datauri, new String[] {
                        "data1", "mimetype" }, "raw_contact_id = ?",
                        new String[] { id }, null);
                while (datacursor.moveToNext()) {
                    String data1 = datacursor.getString(0);
                    String mimetype = datacursor.getString(1);
                    if ("vnd.android.cursor.item/name".equals(mimetype)) {
                        info.setName(data1);
                    } else if ("vnd.android.cursor.item/im".equals(mimetype)) {
                        info.setQq(data1);
                    } else if ("vnd.android.cursor.item/email_v2"
                            .equals(mimetype)) {
                        info.setEmail(data1);
                    } else if ("vnd.android.cursor.item/phone_v2"
                            .equals(mimetype)) {
                        info.setPhone(data1);
                    }
                }
                datacursor.close();
                list.add(info);
            }
        }
        cursor.close();
        return list;
    }
}

布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <ListView
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

成果展示:

案例三: 內容提供者修改數據庫。通過上述知識我們知道當需要對另外一個應用程序的數據庫操作的時候可以用到內容提供者,那到底內容提供者內部是如何工作的呢?在這里給出一個案例來說明內容提供者的工作機制。首先,創建一個工程,在這個工程中新建一個數據庫,單獨寫一個類繼承ContentProvider,我們稱之為后門程序,重寫其中一系列的方法。其中包括對數據增刪改查。但此處的數據庫操作方法是空實現,當我們在另一工程中為內容解析者指定同一Uri路徑時。調用內容解析者的增刪改查方法時,會自動對該數據哭庫操作。同時,還可以在后門程序中設置內容監聽者,這樣可以隨時觀察到數據的變化。

內容提供者的主程序,不用操作任何邏輯:

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

內容提供者中創建數據庫:

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;

public class MyDBOpenhelper extends SQLiteOpenHelper {

    public MyDBOpenhelper(Context context) {
        super(context, "test.db", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
       db.execSQL("create table account (_id integer primary key autoincrement,name varchar(20),number varchar(20))");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

寫一個類ContentProvider:

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;

public class BackDoor extends ContentProvider {

    private static final int SUCCESS = 1;

    /** 判斷Uri規則 */
    static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    static {
        mUriMatcher.addURI("com.exmple.text", "account", SUCCESS);    //uri規則可自己定義,但一定和清單文件一直
    }

    @Override
    public boolean onCreate() {
        return false;
    }

    /** 增刪改查為空實現 */
    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        int code = mUriMatcher.match(uri); // 判斷Uri是否合法
        if (code == SUCCESS) {
            System.out.println("查詢數據");
            MyDBOpenhelper helper = new MyDBOpenhelper(getContext());
            SQLiteDatabase db = helper.getReadableDatabase();
            return db.query("account", projection, selection, selectionArgs,
                    null, null, sortOrder);
        } else {
            throw new IllegalArgumentException("路徑不正確");
        }
    }

    @Override
    public String getType(Uri uri) {
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        int code = mUriMatcher.match(uri);
        if (code == SUCCESS) {
            System.out.println("添加數據");
            MyDBOpenhelper helper = new MyDBOpenhelper(getContext());
            SQLiteDatabase db = helper.getWritableDatabase();
            db.insert("account", null, values);
            getContext().getContentResolver().notifyChange(uri, null); // 內容觀察者檢測數據庫是否更改
        } else {
            throw new IllegalArgumentException("路徑不正確");
        }
        return null;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int code = mUriMatcher.match(uri);
        if (code == SUCCESS) {
            System.out.println("刪除數據");
            MyDBOpenhelper helper = new MyDBOpenhelper(getContext());
            SQLiteDatabase db = helper.getWritableDatabase();
            db.delete("account", selection, selectionArgs);
            getContext().getContentResolver().notifyChange(uri, null);     // 內容觀察者檢測數據庫是否更改
        } else {
            throw new IllegalArgumentException("路徑不正確");
        }
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        int code = mUriMatcher.match(uri);
        if (code == SUCCESS) {
            System.out.println("更新數據");
            MyDBOpenhelper helper = new MyDBOpenhelper(getContext());
            SQLiteDatabase db = helper.getWritableDatabase();
            db.update("account", values, selection, selectionArgs);
            getContext().getContentResolver().notifyChange(uri, null);    // 內容觀察者檢測數據庫是否更改
        } else {
            throw new IllegalArgumentException("路徑不正確");
        }
        return 0;

    }
}

配置文件中添加provider節點:

        <!-- 注冊內容提供者數據 -->
        <provider
            android:name="com.example.provider.BackDoor"
            android:authorities="com.exmple.text" >
        </provider>

調用者的主程序:

import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    /**
     * 利用后門程序 添加一條數據
     */
    public void insert(View view) {
        ContentResolver resolver = getContentResolver();
        Uri uri = Uri.parse("content://com.exmple.text/account");
        ContentValues values = new ContentValues();
        values.put("name", "zhangsan");
        values.put("number", 10000);
        resolver.insert(uri, values);
    }

    /**
     * 利用后門程序 刪除一條數據
     */
    public void delete(View view) {
        ContentResolver resolver = getContentResolver();
        Uri uri = Uri.parse("content://com.exmple.text/account");
        resolver.delete(uri, "name=?", new String[] { "zhangsan" });
    }

    /**
     * 利用后門程序 修改數據
     */
    public void update(View view) {
        ContentResolver resolver = getContentResolver();
        Uri uri = Uri.parse("content://com.exmple.text/account");
        ContentValues values = new ContentValues();
        values.put("number", 20000);
        resolver.update(uri, values, "name=?", new String[] { "zhangsan" });
    }

    /**
     * 利用后門程序 查詢數據
     */
    public void query(View view) {
        ContentResolver resolver = getContentResolver();
        Uri uri = Uri.parse("content://com.exmple.text/account");
        Cursor cursor = resolver.query(uri, new String[] { "name", "number" },
                null, null, null);
        while (cursor.moveToNext()) {
            String name = cursor.getString(0);
            float number = cursor.getFloat(1);
            System.out.println("name:" + name + "----" + "number:" + number);
        }
        cursor.close();
    }
}

調用者的布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="insert"
        android:text="增" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="delete"
        android:text="刪" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="update"
        android:text="改" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="query"
        android:text="查" />

</LinearLayout>

運行結果:

總結

以上是生活随笔為你收集整理的安卓四大组件之内容提供者的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 爽妇综合网 | 97青青草| 奇米在线播放 | 国产91网址 | 亚洲国产精品综合久久久 | 免费看污片网站 | 精品人妻无码一区二区色欲产成人 | 一级黄色网| 黄色专区 | 国内激情 | 天天看天天爽 | 亚洲精品一区二区潘金莲 | 国产精选视频在线观看 | 91久久精品美女高潮 | 又黄又爽又刺激的视频 | 日韩av网址大全 | 色播日韩| 久久人妻一区二区 | 16一17女人毛片| 欧美一级二级片 | 免费成人av网址 | 日韩精品免费一区二区夜夜嗨 | 成年丰满熟妇午夜免费视频 | 欧洲美一区二区三区亚洲 | 好大好爽视频 | 韩国三级丰满少妇高潮 | 日韩视频一区在线观看 | av在线天堂| 日韩经典在线 | 草莓视频一区二区三区 | 国产午夜电影在线观看 | 色在线免费视频 | 久久国产精品久久久久久电车 | 久久公开视频 | 亚洲精品一区二区三区精华液 | 无码久久精品国产亚洲av影片 | 国产在线a视频 | 亚洲永久精品在线观看 | 亚洲小说春色综合另类 | 国产中文自拍 | 精品国产美女 | 天堂久久精品忘忧草 | 婷婷色婷婷开心五月四房播播 | 久草aⅴ | 在线观看日本中文字幕 | 淫品色影院 | 国产第九页 | 久久久少妇 | 色久综合网 | 少妇av在线播放 | 国产曰肥老太婆无遮挡 | 国产女人在线观看 | 蜜桃视频一区二区 | 国产亚洲二区 | 一直草 | 91av视频网站 | 亚洲一区二区视频 | 激情 小说 亚洲 图片 伦 | 九九久久国产精品 | 午夜不卡福利视频 | 中文字幕 日韩 欧美 | 欧美日韩一区二 | 黄色av电影在线 | 日韩欧美成人免费视频 | 中国人妖和人妖做爰 | 成人影片网址 | 久久高清无码视频 | 欧美美女色图 | 亚洲香蕉在线观看 | 高h喷汁呻吟3p | 波多野结衣潜藏淫欲 | 精品一久久 | 欧美久久久久久久 | 在线射 | 精品国产色 | 欧美综合视频在线观看 | 亚洲涩涩在线 | 日韩一区二区三区在线观看视频 | 亚洲精品观看 | 黑帮大佬和我的三百六十五天 | 无码人妻丰满熟妇区bbbbxxxx | 在线观看日韩一区 | 欧美久久综合网 | 久久成人免费视频 | 香蕉国产在线 | 日日夜夜精品视频 | 日本三区在线 | 男人用嘴添女人下身免费视频 | 成人小视频免费观看 | 99黄色网 | 精品久久一二三区 | 国产午夜大地久久 | 免费高清欧美大片在线观看 | 亚洲欧美一区二区三区久久 | 欧美精品色呦呦 | 国产精品vip| 国产成人福利在线 | 美女被c出水 | 91精品人妻一区二区三区蜜桃欧美 |