转载请注明出处: http://blog.csdn.net/a992036795/article/details/51610936

一、简介:
ContentProvider 在android中的作用是对外共享数据,也就是说可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider对应用中的数据进行增、删、该、查。使用ContentProvider的好处是,统一了数据的访问方式。
ContentProvider的体层实现实际是Binder。

二、使用:
一般ContentProvider的实现都是对SqliteOpenHelp的进一步包装,通过Uri映射来判断选择需要操作数据库中的那个表,并且进行增、删、改、查处理。

我们先来看以一下ContentProvider的定义:

** * Content providers are one of the primary building blocks of Android applications, providing * content to applications. They encapsulate data and provide it to applications through the single * {@link ContentResolver} interface. A content provider is only required if you need to share * data between multiple applications. For example, the contacts data is used by multiple * applications and must be stored in a content provider. If you don't need to share data amongst * multiple applications you can use a database directly via * {@link android.database.sqlite.SQLiteDatabase}. * * 

When a request is made via * a {@link ContentResolver} the system inspects the authority of the given URI and passes the * request to the content provider registered with the authority. The content provider can interpret * the rest of the URI however it wants. The {@link UriMatcher} class is helpful for parsing * URIs.

* *

The primary methods that need to be implemented are: *

    *
  • {@link #onCreate} which is called to initialize the provider
  • *
  • {@link #query} which returns data to the caller
  • *
  • {@link #insert} which inserts new data into the content provider
  • *
  • {@link #update} which updates existing data in the content provider
  • *
  • {@link #delete} which deletes data from the content provider
  • *
  • {@link #getType} which returns the MIME type of data in the content provider
  • *

* *

class="caution">Data access methods (such as {@link #insert} and * {@link #update}) may be called from many threads at once, and must be thread-safe. * Other methods (such as {@link #onCreate}) are only called from the application * main thread, and must avoid performing lengthy operations. See the method * descriptions for their expected thread behavior.

* *

Requests to {@link ContentResolver} are automatically forwarded to the appropriate * ContentProvider instance, so subclasses don't have to worry about the details of * cross-process calls.

* * <div class="special reference"> *

Developer Guides

*

For more information about using content providers, read the * "{@docRoot}guide/topics/providers/content-providers.html">Content Providers * developer guide.

*/public abstract class ContentProvider implements ComponentCallbacks2 { private static final String TAG = "ContentProvider";

通过注释我们大概可以了解到:
我们自定义一个ContentProvider,需要实现它的onCreate、query、insert、update、delete、getType方法。
因为它底层实现是Binder、其实对源码进行分析的话、可以看到如果是夸进程调用的话,OnCreate将发生在主线程、而其他方法将发生在Binder线程池中。
这一点,我们可以通过在方法打印进程名会得到证实。

06-08 01:46:21.903 3016-3016/com.blueberry.process1 I/SimpleContentProvider: onCreate: current thread: main06-08 01:46:21.920 3016-3032/com.blueberry.process1 I/SimpleContentProvider: insert: current thread: Binder_206-08 01:46:22.968 3016-3032/com.blueberry.process1 I/SimpleContentProvider: query: current thread: Binder_2

这是我写的一个例子的测试结果。下面我们将自己写一个ContentProvider。
首先我们先定义个SQLiteOpenHelp,来创建1个数据库,其中存在2张表。
下面给出类的定义:

/** * Created by blueberry on 2016/6/7. */public class UserInfoDbHelper extends SQLiteOpenHelper {    private static final String TAG = "UserInfoDbHelper";    private static final String DB_NAME = "userinfo.db"; /*数据库名*/    private static final int DB_VERSION = 1;/*版本号*/    public static final String TABLE_USER_INFO = "userinfo";/*用户信息表*/    public static final String TABLE_COMPANY = "company";/*公司表*/    public static final String TEL_COLUMN = "tel_num";/*电话号码*/    public static final String DESC_COLUMN = "desc";/*描述*/    public static final String COMP_ID_COLUMN = "comp_id";/*公司id*/    public static final String ID_COLUMN = "id";/*公司的id*/    public static final String BUSINESS_COLUMN = "business";/*公司的业务*/    public static final String ADDR_COLUMN = "addr";/*公司位置*/    //  表 userinfo    //  | 字段名            | 类型          |意义             |    //  | Tel_num           | TEXT         |电话号码          |    //  | Desc              | TEXT         |描述              |    //  | comp_id           | INTEGER      | 公司id           |    //    //  表 company    //  |字段名              |类型           |意义             |    //  |Id                 |INTEGER        |公司的id          |    //  |Business           | TEXT          |公司的业务        |    //  | Addr              | TEXT          | 公司位置         |    private static final String POSTCODE_TABLE_SQL ="CREATE TABLE IF NOT EXISTS "+TABLE_USER_INFO +" ("            +TEL_COLUMN+" TEXT ,"            +COMP_ID_COLUMN+" INTEGER ,"            +DESC_COLUMN+" TEXT"            +")" ;    private static final String COMPANY_TABLE_SQL ="CREATE TABLE IF NOT EXISTS "+TABLE_COMPANY+" ("            +ID_COLUMN +" INTEGER PRIMEARY KEY ,"            +BUSINESS_COLUMN+" TEXT ,"            +ADDR_COLUMN+" TEXT" +")" ;    public UserInfoDbHelper(Context context) {        super(context, DB_NAME , null, DB_VERSION);    }    @Override    public void onCreate(SQLiteDatabase db) {        db.execSQL(POSTCODE_TABLE_SQL);        db.execSQL(COMPANY_TABLE_SQL);    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {    }}

可以看到创建了2张表,一张为userinfo 一张为 company。字段名已在注释列出。

下面继续给出自定一ContentProvider的定义:

/** * Created by blueberry on 2016/6/7. */public class SimpleContentProvider extends ContentProvider {    private static final String TAG = "SimpleContentProvider";    public static final String AUTHORITY = "com.blueberry.test08.provider";    /*该ContentProvider返回的数据类型定义,数据集合*/    private static final String CONTENT_TYPE ="vnd.android.cursor.dir/vnd."+AUTHORITY;    /*单项数据*/    private static final String CONTNET_TYPE_ITEM ="vnd.android.cursor.item/vnd."+AUTHORITY ;    public static final Uri USERINFO_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"            + UserInfoDbHelper.TABLE_USER_INFO);    public static final Uri COMPANY_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"            + UserInfoDbHelper.TABLE_COMPANY);    public static final int USERINFO_CODE = 0;    public static final int USERINFO_ITEM_CODE = 1;    public static final int COMPANY_CODE = 2;    public static final int COMPANY_ITEM_CODE = 3;    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);    static {        /**         * 这里使用2种通配符 "*"表示匹配任意长度的任意字符,"#"表示匹配任意长度的数字         * 因此,content://com.blueberry.test08.provider/company 表示查询company表中的所有数据         * 而 conent://com.blueberry.test08.provider/company/# 表示根据一个数字id 查询一条信息         */        sUriMatcher.addURI(AUTHORITY, "userinfo", USERINFO_CODE);        sUriMatcher.addURI(AUTHORITY, "userinfo/*", USERINFO_ITEM_CODE);        sUriMatcher.addURI(AUTHORITY, "company", COMPANY_CODE);        sUriMatcher.addURI(AUTHORITY, "company/#", COMPANY_ITEM_CODE);    }    private SQLiteDatabase mDatabase;    /**     * 夸进程时发生在主线程     *     * @return     */    @Override    public boolean onCreate() {        Log.i(TAG, "onCreate: current thread: " + Thread.currentThread().getName());        /*返回一个可读写的数据库*/        mDatabase = new UserInfoDbHelper(getContext()).getWritableDatabase();        return true;    }    /**     * 夸进程时发生在工作线程     *     * @param uri     * @param projection     * @param selection     * @param selectionArgs     * @param sortOrder     * @return     */    @Nullable    @Override    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {        Log.i(TAG, "query: current thread: " + Thread.currentThread().getName());        Cursor cursor = null;        switch (sUriMatcher.match(uri)) {            case USERINFO_CODE:                cursor = mDatabase.query(UserInfoDbHelper.TABLE_USER_INFO, projection, selection, selectionArgs, null, null, sortOrder);                break;            case USERINFO_ITEM_CODE:                String tel = uri.getPathSegments().get(1);                cursor = mDatabase.query(UserInfoDbHelper.TABLE_USER_INFO, projection, "tel_num = ?", new String[]{tel}, null, null, sortOrder);                break;            case COMPANY_CODE:                cursor = mDatabase.query(UserInfoDbHelper.TABLE_COMPANY, projection, selection, selectionArgs, null, null, sortOrder);                break;            case COMPANY_ITEM_CODE:                String cid = uri.getPathSegments().get(1);                cursor = mDatabase.query(UserInfoDbHelper.TABLE_COMPANY, projection, "id = ?", new String[]{cid}, null, null, sortOrder);                break;        }        return cursor;    }    /**     * 夸进程时发生在工作线程     *     * @param uri     * @param values     * @return     */    @Nullable    @Override    public Uri insert(Uri uri, ContentValues values) {        Log.i(TAG, "insert: current thread: " + Thread.currentThread().getName());        long newId = 0;        Uri newUri = null;        switch (sUriMatcher.match(uri)) {            case USERINFO_CODE:                newId = mDatabase.insert(UserInfoDbHelper.TABLE_USER_INFO, null, values);                newUri = Uri.parse("content://" + AUTHORITY + "/" + UserInfoDbHelper.TABLE_USER_INFO + "/" + newId);                break;            case COMPANY_CODE:                newId = mDatabase.insert(UserInfoDbHelper.TABLE_COMPANY, null, values);                newUri = Uri.parse("content://" + AUTHORITY + "/" + UserInfoDbHelper.TABLE_COMPANY + "/" + newId);                break;        }        if (newId > 0) return newUri;        throw new IllegalArgumentException("Failed to insert row info" + uri);    }    /**     * 夸进程时发生在工作线程     *     * @param uri     * @return     */    @Nullable    @Override    public String getType(Uri uri) {        Log.i(TAG, "getType: current thread: " + Thread.currentThread().getName());        switch (sUriMatcher.match(uri)){            case USERINFO_CODE:            case COMPANY_CODE:                return CONTENT_TYPE;            case USERINFO_ITEM_CODE:            case COMPANY_ITEM_CODE:                return CONTNET_TYPE_ITEM;            default:                throw new RuntimeException("错误的 uri");        }    }    @Nullable    @Override    public Bundle call(String method, String arg, Bundle extras) {        return super.call(method, arg, extras);    }    /**     * 夸进程时发生在工作线程     *     * @param uri     * @param selection     * @param selectionArgs     * @return     */    @Override    public int delete(Uri uri, String selection, String[] selectionArgs) {        Log.i(TAG, "delete: current thread: " + Thread.currentThread().getName());        return 0;    }    /**     * 夸进程时发生在工作线程     *     * @param uri     * @param values     * @param selection     * @param selectionArgs     * @return     */    @Override    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {        Log.i(TAG, "update: current thread: " + Thread.currentThread().getName());        return 0;    }}

我这里只是测试,所以只实现了query和inser方法。这里主要用了一个 UriMatcher类。

这里对上面的程序简要分析一下:
我们先来简要看一下Uri,Uri代表了要操作的数据表的绝对路径,Uri主要包含两部分信息,一是需要操作的ContentProvider,二是对ContentProvider中的哪个表进行操作。一个Uri的组成为:

ContentProvider的Schema已经由Android固定设置为content://, Authority用于唯一标示这个ContentProvider,外部调用者可以根据这个标示来找到它,这里的path就是要查询的数据表,最后的id是可选字段,例如,我们操作特定的数据项时就会指定一个查询条件,如果所有联系人的uri为 content://contacts/people,某个联系人的Uri:content://contacts/people/5,这个5 就是联系人的id,也就对应了查询的关键字。

这里我们的Authority为 com.blueberry.test08.provider。

接下来我们看以UriMatcher
我们来看一下这个类的定义:

/**Utility class to aid in matching URIs in content providers.

To use this class, build up a tree of UriMatcher objects.For example:

    private static final int PEOPLE = 1;    private static final int PEOPLE_ID = 2;    private static final int PEOPLE_PHONES = 3;    private static final int PEOPLE_PHONES_ID = 4;    private static final int PEOPLE_CONTACTMETHODS = 7;    private static final int PEOPLE_CONTACTMETHODS_ID = 8;    private static final int DELETED_PEOPLE = 20;    private static final int PHONES = 9;    private static final int PHONES_ID = 10;    private static final int PHONES_FILTER = 14;    private static final int CONTACTMETHODS = 18;    private static final int CONTACTMETHODS_ID = 19;    private static final int CALLS = 11;    private static final int CALLS_ID = 12;    private static final int CALLS_FILTER = 15;    private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);    static    {        sURIMatcher.addURI("contacts", "people", PEOPLE);        sURIMatcher.addURI("contacts", "people/#", PEOPLE_ID);        sURIMatcher.addURI("contacts", "people/#/phones", PEOPLE_PHONES);        sURIMatcher.addURI("contacts", "people/#/phones/#", PEOPLE_PHONES_ID);        sURIMatcher.addURI("contacts", "people/#/contact_methods", PEOPLE_CONTACTMETHODS);        sURIMatcher.addURI("contacts", "people/#/contact_methods/#", PEOPLE_CONTACTMETHODS_ID);        sURIMatcher.addURI("contacts", "deleted_people", DELETED_PEOPLE);        sURIMatcher.addURI("contacts", "phones", PHONES);        sURIMatcher.addURI("contacts", "phones/filter/*", PHONES_FILTER);        sURIMatcher.addURI("contacts", "phones/#", PHONES_ID);        sURIMatcher.addURI("contacts", "contact_methods", CONTACTMETHODS);        sURIMatcher.addURI("contacts", "contact_methods/#", CONTACTMETHODS_ID);        sURIMatcher.addURI("call_log", "calls", CALLS);        sURIMatcher.addURI("call_log", "calls/filter/*", CALLS_FILTER);        sURIMatcher.addURI("call_log", "calls/#", CALLS_ID);    }

Starting from API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, paths can start with a leading slash. For example:

        sURIMatcher.addURI("contacts", "/people", PEOPLE);

Then when you need to match against a URI, call {@link #match}, providingthe URL that you have been given. You can use the result to build a query,return a type, insert or delete a row, or whatever you need, without duplicatingall of the if-else logic that you would otherwise need. For example:

    public String getType(Uri url)    {        int match = sURIMatcher.match(url);        switch (match)        {            case PEOPLE:                return "vnd.android.cursor.dir/person";            case PEOPLE_ID:                return "vnd.android.cursor.item/person";... snip ...                return "vnd.android.cursor.dir/snail-mail";            case PEOPLE_ADDRESS_ID:                return "vnd.android.cursor.item/snail-mail";            default:                return null;        }    }
instead of:
    public String getType(Uri url)    {        List pathSegments = url.getPathSegments();        if (pathSegments.size() >= 2) {            if ("people".equals(pathSegments.get(1))) {                if (pathSegments.size() == 2) {                    return "vnd.android.cursor.dir/person";                } else if (pathSegments.size() == 3) {                    return "vnd.android.cursor.item/person";... snip ...                    return "vnd.android.cursor.dir/snail-mail";                } else if (pathSegments.size() == 3) {                    return "vnd.android.cursor.item/snail-mail";                }            }        }        return null;    }
*/public class UriMatcher{

可以看到,注释中已经把他的用法说的查不到了。
UriMather 会根据uri来匹配出对应的 code来使得我们判断该查询那张表,

这里我们定义了四个 code. 分别对用与 用户信息查询、单个用户信息查询、公司查询、单个公司查询。

 public static final int USERINFO_CODE = 0;    public static final int USERINFO_ITEM_CODE = 1;    public static final int COMPANY_CODE = 2;    public static final int COMPANY_ITEM_CODE = 3;

我们通过如下方法将 对应信息添加进去:

    static {        /**         * 这里使用2种通配符 "*"表示匹配任意长度的任意字符,"#"表示匹配任意长度的数字         * 因此,content://com.blueberry.test08.provider/company 表示查询company表中的所有数据         * 而 conent://com.blueberry.test08.provider/company/# 表示根据一个数字id 查询一条信息         */        sUriMatcher.addURI(AUTHORITY, "userinfo", USERINFO_CODE);        sUriMatcher.addURI(AUTHORITY, "userinfo/*", USERINFO_ITEM_CODE);        sUriMatcher.addURI(AUTHORITY, "company", COMPANY_CODE);        sUriMatcher.addURI(AUTHORITY, "company/#", COMPANY_ITEM_CODE);    }

我们接着来看一下getType方法,根据UriMather推荐的方法,如果查询的是数据集合, 我们返回的类型应该是 vnd.android.cursor.dir/….. 如果是查询单个数据我们返回的类型应该是 vnd.android.cursor.item/….

  /*该ContentProvider返回的数据类型定义,数据集合*/    private static final String CONTENT_TYPE ="vnd.android.cursor.dir/vnd."+AUTHORITY;    /*单项数据*/    private static final String CONTNET_TYPE_ITEM ="vnd.android.cursor.item/vnd."+AUTHORITY ; /**     * 夸进程时发生在工作线程     *     * @param uri     * @return     */    @Nullable    @Override    public String getType(Uri uri) {        Log.i(TAG, "getType: current thread: " + Thread.currentThread().getName());        switch (sUriMatcher.match(uri)){            case USERINFO_CODE:            case COMPANY_CODE:                return CONTENT_TYPE;            case USERINFO_ITEM_CODE:            case COMPANY_ITEM_CODE:                return CONTNET_TYPE_ITEM;            default:                throw new RuntimeException("错误的 uri");        }    }

接着来看 他的query 和 insert方法:

 /**     * 夸进程时发生在工作线程     *     * @param uri     * @param projection     * @param selection     * @param selectionArgs     * @param sortOrder     * @return     */    @Nullable    @Override    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {        Log.i(TAG, "query: current thread: " + Thread.currentThread().getName());        Cursor cursor = null;        switch (sUriMatcher.match(uri)) {            case USERINFO_CODE:                cursor = mDatabase.query(UserInfoDbHelper.TABLE_USER_INFO, projection, selection, selectionArgs, null, null, sortOrder);                break;            case USERINFO_ITEM_CODE:                String tel = uri.getPathSegments().get(1);                cursor = mDatabase.query(UserInfoDbHelper.TABLE_USER_INFO, projection, "tel_num = ?", new String[]{tel}, null, null, sortOrder);                break;            case COMPANY_CODE:                cursor = mDatabase.query(UserInfoDbHelper.TABLE_COMPANY, projection, selection, selectionArgs, null, null, sortOrder);                break;            case COMPANY_ITEM_CODE:                String cid = uri.getPathSegments().get(1);                cursor = mDatabase.query(UserInfoDbHelper.TABLE_COMPANY, projection, "id = ?", new String[]{cid}, null, null, sortOrder);                break;        }        return cursor;    }    /**     * 夸进程时发生在工作线程     *     * @param uri     * @param values     * @return     */    @Nullable    @Override    public Uri insert(Uri uri, ContentValues values) {        Log.i(TAG, "insert: current thread: " + Thread.currentThread().getName());        long newId = 0;        Uri newUri = null;        switch (sUriMatcher.match(uri)) {            case USERINFO_CODE:                newId = mDatabase.insert(UserInfoDbHelper.TABLE_USER_INFO, null, values);                newUri = Uri.parse("content://" + AUTHORITY + "/" + UserInfoDbHelper.TABLE_USER_INFO + "/" + newId);                break;            case COMPANY_CODE:                newId = mDatabase.insert(UserInfoDbHelper.TABLE_COMPANY, null, values);                newUri = Uri.parse("content://" + AUTHORITY + "/" + UserInfoDbHelper.TABLE_COMPANY + "/" + newId);                break;        }        if (newId > 0) return newUri;        throw new IllegalArgumentException("Failed to insert row info" + uri);    }

可以看到,利用UriMatcher得到要怎样查询,然后代用了 database的方法。

最后说一个方法:

 @Nullable    @Override    public Bundle call(String method, String arg, Bundle extras) {        return super.call(method, arg, extras);    }

可以利用这个方法,扩展出一些查询方式。

最后我们来看以下在清单文件中的注册:

  <provider            android:authorities="com.blueberry.test08.provider"            android:name=".SimpleContentProvider"            android:permission="com.blueberry.permission.provider"            android:process="com.blueberry.process1"            android:multiprocess="false"            >        provider>

这里主要的字段为 authorities ,他是ContentProvider的唯一标识。
permission,它分为 读权限,和写权限 对应为 android:readpermission 和
android:writepermission 。 multiprocess如果设置为true标识每个调用进程都拥有一个示例,负责只有所有进程只有一个示例。process字段使得它运行在一个名为com.blueberry.process1的进程中。

最后我们来看一下调用程序:

public class MainActivity extends AppCompatActivity {    private EditText etUserDesc,etUserPhoneNumber,etUserCompanyId;    private EditText etCompanyId,etCompanyBussiness,etCompanyAddress ;    private Button btnSubmitUserInfo,btnSubmitCompany;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        etUserDesc = (EditText) findViewById(R.id.et_user_desc);        etUserPhoneNumber = (EditText) findViewById(R.id.et_user_phone_number);        etUserCompanyId = (EditText) findViewById(R.id.et_user_company_id);        etCompanyId = (EditText) findViewById(R.id.et_company_id);        etCompanyBussiness  = (EditText) findViewById(R.id.et_company_bussiness);        etCompanyAddress = (EditText) findViewById(R.id.et_company_address);        btnSubmitUserInfo = (Button) findViewById(R.id.btn_save_userinfo);        btnSubmitCompany = (Button) findViewById(R.id.btn_save_company);        btnSubmitUserInfo.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                //存数用户信息数据                saveUserInfoRecord();                btnSubmitUserInfo.postDelayed(new Runnable() {                    @Override                    public void run() {                        queryUserInfo();                    }                },1000);            }        });        btnSubmitCompany.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                saveCompanyInfo();                btnSubmitCompany.postDelayed(new Runnable() {                    @Override                    public void run() {                      queryCompanyInfo();                    }                },1000) ;            }        });    }    /**     * 通过电话号码查询相关信息     */    private void queryUserInfo() {        Uri queryUri = Uri.parse("content://com.blueberry.test08.provider/userinfo/123456") ;        Cursor cursor = getContentResolver().query(queryUri,                new String[]{UserInfoDbHelper.DESC_COLUMN,UserInfoDbHelper.COMP_ID_COLUMN,UserInfoDbHelper.TEL_COLUMN}                ,null,null,null);        if(cursor.moveToFirst()){            Toast.makeText(this,                    " 描述信息"+cursor.getString(0)                    +" 公司id"+cursor.getString(1)                    +" 电话来自"+cursor.getString(2),Toast.LENGTH_SHORT).show();        }        cursor.close();    }    /**     * 存储用户信息到ContentProvider     */    private void saveUserInfoRecord() {        ContentValues newRecord = new ContentValues();        newRecord.put(UserInfoDbHelper.DESC_COLUMN,etUserDesc.getText().toString());        newRecord.put(UserInfoDbHelper.COMP_ID_COLUMN,etUserCompanyId.getText().toString());        newRecord.put(UserInfoDbHelper.TEL_COLUMN,etUserPhoneNumber.getText().toString());        getContentResolver().insert(SimpleContentProvider.USERINFO_CONTENT_URI,newRecord) ;    }    private void saveCompanyInfo() {        ContentValues newRecord = new ContentValues();        newRecord.put(UserInfoDbHelper.ID_COLUMN,etCompanyId.getText().toString());        newRecord.put(UserInfoDbHelper.BUSINESS_COLUMN,etCompanyBussiness.getText().toString());        newRecord.put(UserInfoDbHelper.ADDR_COLUMN,etCompanyAddress.getText().toString());        getContentResolver().insert(SimpleContentProvider.COMPANY_CONTENT_URI,newRecord);    }    private void queryCompanyInfo(){        Cursor cursor = getContentResolver().query(SimpleContentProvider.COMPANY_CONTENT_URI,                new String[]{UserInfoDbHelper.ID_COLUMN,UserInfoDbHelper.BUSINESS_COLUMN,UserInfoDbHelper.ADDR_COLUMN}                ,null,null,null);        StringBuffer sb = new StringBuffer();        while (cursor.moveToNext()){            sb.append("id: "+cursor.getString(0)+" business: "+cursor.getString(1)+" address: "+cursor.getString(2));            sb.append("\n");        }        Toast.makeText(this,sb.toString(),Toast.LENGTH_LONG).show();    }}

布局:

<?xml version="1.0" encoding="utf-8"?><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"    tools:context="com.blueberry.test08.MainActivity">    <EditText        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/et_user_desc"        android:hint="请输入用户描述信息"        android:contentDescription="用户描述信息"        />    <EditText        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/et_user_phone_number"        android:hint="输入用户电话号码"        android:contentDescription="用户电话号码"        />    <EditText        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/et_user_company_id"        android:hint="用户公司id"        android:contentDescription="用户公司id"        />    <Button        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/btn_save_userinfo"        android:text="存储用户信息"        />    <EditText        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/et_company_id"        android:hint="公司id"        />    <EditText        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/et_company_bussiness"        android:hint="请输入公司业务"        android:contentDescription="公司业务"        />    <EditText        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/et_company_address"        android:hint="请输入公司地址"        android:contentDescription="请输入公司地址"        />    <Button        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/btn_save_company"        android:text="保存公司信息"        />LinearLayout>

更多相关文章

  1. 说说在 Android(安卓)中如何发送 HTTP 请求
  2. 自定义Android,toast,以及多线程toast
  3. android 线程更新view及数据传送
  4. Android(安卓)Tthread 建立线程使用方法
  5. Android——线程创建以及handler
  6. android调试与内存泄漏
  7. Android(安卓)IPC机制及Binder原理
  8. Android(安卓)adb setuid提权漏洞的分析
  9. Android启动流程以及分类

随机推荐

  1. android创建txt文件,读取txt文件内容
  2. Android录音上————AudioRecord实现录
  3. android之Handler整理
  4. android客户端与服务端交互的工具类
  5. android的短信发送全过程源代码分析
  6. 打开Android(安卓)Studio报错 "required
  7. Android(安卓)APK签名对比及说明
  8. Android(安卓)使用 URL 和 AsyncTask 加
  9. Android中Service(服务)和Thread(线程)的关
  10. Android(安卓)判断SD卡是否存在及容量查