Android 内容提供器(Content Provider)

一、简介

  Content Provider主要提供数据对外共享,通过内容提供器(Content Provider)可以将应用中的数据提供给其它应用共享(存储与读取)。也可以通过内容提供器(Content Provider)对其它应用的数据进行存储与读取。

  简单的说就是在Android里内置了一个包含数据的数据库,通常是SQLite形式的数据库,由Android OS内置的功能进行驱动。

  通过Android内容提供器(Content Provider),可以访问可共享的数据结构,称为数据库(Database)。基本的操作步骤如下:

  • 获取打开数据库的权限。
  • 查询数据。
  • 访问数据。

  在访问数据库时,可对数据进行添、删、改、查操作,这些操作的权限及级别,都存储于工程的清单(AndroidManifest.xml)文件中。

二、数据库与数据库管理系统

  内容提供器通过数据库管理系统(DBMS)为Android应用程序提供数据结构的。DBMS可以管理数据库,并为用户提供创建数据库的途径,为读写操作提供数据的。

  在Android中,使用SQLite数据库,其数据库管理系统为RDBMS,SQLite是关系型数据库。在数据库中,表中存储的二维数据称为记录(Record)。

三、Android 内置的内容提供器

  1. 联系人数据库内容提供器
  2. Android MediaStore内容提供器

四、定义内容提供器

  在使用内容提供器前,必须在Android应用程序中进行注册。这个操作可以通过AndroidManifest.xml文件的<provider>标签指定。<provider>标签的定义是在应用启动时,需要访问哪些内容提供器。例如:一个用于Images内容提供器的<provider>标签:

1 <provider android:name="MediaStore.Images.ImageColumns" />

  所有的内容提供器都针对一个数据库,为开发者提供一个可进行公用访问的唯一引用,或者说一个地址,这个地址称为URI。在Android中,数据库表中指向数据的位置常量通常是CONTENT_URI。

  数据库中包含多个表,会为每一个表提供一个唯一的URI。例如:

1 android.provider.Contacts.Phones.CONTENT_URI
  1. 第一个词android代表Android OS。
  2. 第二个词provider代表组件类型。
  3. 第三个词Contents代表数据库。
  4. 第四个词Phones代表数据库中的一个表。
  5. 第五个词CONTENT_URI代表表中指向数据位置的常量。

  看似很复杂,其实理解起来就一句话:在Android OS中某个组件类型中的数据库的一个表,数据在表中的位置。

五、定义安全权限  

  在AndroidManifest.xml文件定义读取数据库的安全权限,定义读取联系人安全权限示例如下:

1 <uses-permission android:name="android.permission.READ_CONTACTS" />

 六、自定义内容提供器示例

  定义一个ContentProvider需要以下必个步骤:

  1. 创建一个类,继承于ContentProvider基类;
  2. 定义一个CONTENT_URI静态常量,以public static final修饰,初始值最好以类名全名。比如:
    1 public static final String CONTENT_URI = "naray.myproviderdemo.userprovider"

    此变量用于指定数据库在外访问的唯一地址。

  3. 定义数据库表的数据列,如果,使用的是android的内部数据,必须定义一个为_id的列为主键;
  4. 创建数据存储系统,Content Provider可以使用Sqlite数据库,或者Android的文件系统存储。也可以是其它的存储方式。
  5. 覆盖实现基类Content Provider类的抽象方法。
  6. 在AndroidManifest.xml清单文件中,添加provider标签,指定Content Provider。

  下面自定义一个Content Provider,存储数据为姓名与电话:

  UserInfo类,用于声名数据库表的数据结构与声名指定此数据库的唯一引用:

 1 public class UserInfo implements BaseColumns
 2 {
 3     public static final String AUTHORITY = "naray.myproviderdemo.UserProvider";
 4 
 5     public static final class User
 6     {
 7         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
 8         public static final String NAME = "NAME";
 9         public static final String PHONE = "PHONE";
10     }
11 }

  PS:CONTENT_URI是为使用者提供一个公用的数据库的唯一引用,一般以类名为初始值。

  UserProvider使用Sqlite存储数据(DataBaseHelper):

 1 public class DataBaseHelper extends SQLiteOpenHelper
 2 {
 3     // local member var
 4     private String mDBName;
 5     private String mTableName;
 6     private SQLiteDatabase.CursorFactory mFactory;
 7     private int mVersion;
 8 
 9 
10     // construceor
11     public DataBaseHelper(Context context, String name, String tableName,
12                           SQLiteDatabase.CursorFactory factory, int version)
13     {
14         super(context, name, factory, version);
15         mDBName = name;
16         mTableName = tableName;
17         mFactory = factory;
18         mVersion = version;
19     }
20 
21     // inherit baseclass member method
22     @Override
23     public void onCreate(SQLiteDatabase db)
24     {
25         String sql = "create table " + mTableName + " ( _id INTEGER PRIMARY KEY AUTOINCREMENT, " +
26                 "NAME TEXT, PHONE TEXT);";
27         db.execSQL(sql);
28     }
29 
30     @Override
31     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
32     {
33 
34     }
35 }

 

  UserProvider类,是继承于Content Provider类,定义一个内容提供器:

 1 public class UserProvider extends ContentProvider
 2 {
 3     // local member var
 4     private DataBaseHelper mDBHelper;
 5     private SQLiteDatabase mSqlDB;
 6     private static final String sDataBaseName = "user.db";
 7     private static final String sTableName = "user";
 8     private static final int sVersion = 1;
 9 
10     // inherit baseclass member method
11     @Override
12     public boolean onCreate()
13     {
14         mDBHelper = new DataBaseHelper(getContext(), sDataBaseName, sTableName, null, sVersion);
15         return false;
16     }
17 
18     @Nullable
19     @Override
20     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
21     {
22         SQLiteQueryBuilder sqLiteQueryBuilder = new SQLiteQueryBuilder();
23         SQLiteDatabase db = mDBHelper.getReadableDatabase();
24         sqLiteQueryBuilder.setTables(sTableName);
25         Cursor cursor = db.query(sTableName, projection, selection, selectionArgs, null, null, sortOrder);
26         cursor.setNotificationUri(getContext().getContentResolver(), uri);
27 
28         return cursor;
29     }
30 
31     @Nullable
32     @Override
33     public String getType(Uri uri)
34     {
35         return null;
36     }
37 
38     @Nullable
39     @Override
40     public Uri insert(Uri uri, ContentValues values)
41     {
42         mSqlDB = mDBHelper.getWritableDatabase();
43         long rowId = mSqlDB.insert(sTableName, null, values);
44         if (0 < rowId)
45         {
46             Uri rowUri = ContentUris.appendId(UserInfo.User.CONTENT_URI.buildUpon(), rowId).build();
47             getContext().getContentResolver().notifyChange(rowUri, null);
48             return rowUri;
49         }
50         return null;
51     }
52 
53     @Override
54     public int delete(Uri uri, String selection, String[] selectionArgs)
55     {
56         return 0;
57     }
58 
59     @Override
60     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
61     {
62         return 0;
63     }
64 }

  下面是显示UI元素的界面,MainActivity:

 1 public class MainActivity extends FragmentActivity
 2 {
 3     @Override
 4     public void onCreate(Bundle savedInstanceStata)
 5     {
 6         super.onCreate(savedInstanceStata);
 7         setContentView(R.layout.activity_fragment);
 8 
 9         // fragment manager
10         FragmentManager fm = getSupportFragmentManager();
11         Fragment fragment = fm.findFragmentById(R.id.fragmentContainter);
12         if (null == fragment)
13         {
14             fragment = new MainFragment();
15             fm.beginTransaction().add(R.id.fragmentContainter, fragment).commit();
16         }
17     }
18 }

  MainActivity委托MainFragment构建界面(MainFragment):

 1 public class MainFragment extends Fragment implements View.OnClickListener
 2 {
 3     // local member var
 4     private EditText mNameEditText;
 5     private EditText mTelEditText;
 6     private final ContentValues mContentVals = new ContentValues();
 7 
 8     // constructor
 9     public MainFragment()
10     {
11     }
12 
13     // inherit baseclass member method
14     @Override
15     public View onCreateView(LayoutInflater inflater, ViewGroup containter, Bundle savedInstanceState)
16     {
17         View view = inflater.inflate(R.layout.fragment_main, null);
18 
19         // 存储UI元素
20         mNameEditText = (EditText) view.findViewById(R.id.name);
21         mTelEditText = (EditText) view.findViewById(R.id.tel);
22 
23         // 添加事件代理的UI元素
24         Button insert = (Button) view.findViewById(R.id.insert);
25         insert.setOnClickListener(this);
26 
27         Button query = (Button) view.findViewById(R.id.query);
28         query.setOnClickListener(this);
29 
30         return view;
31     }
32 
33     // inherit View.OnClickListener interface member method
34     @Override
35     public void onClick(View view)
36     {
37         switch (view.getId())
38         {
39             case R.id.insert:
40             {
41                 mContentVals.put(UserInfo.User.NAME, mNameEditText.getText().toString());
42                 mContentVals.put(UserInfo.User.PHONE, mTelEditText.getText().toString());
43                 Uri resUri = getActivity().getContentResolver().insert(UserInfo.User.CONTENT_URI, mContentVals);
44                 if (null != resUri)
45                 {
46                     Toast.makeText(getActivity(), "添加数据成功", Toast.LENGTH_SHORT).show();
47                 }
48                 else
49                 {
50                     Toast.makeText(getActivity(), "添加数据失败", Toast.LENGTH_SHORT).show();
51                 }
52                 break;
53             }
54             case R.id.query:
55             {
56                 ArrayList<String> data = new ArrayList<>();
57                 Cursor cursor = getActivity().getContentResolver().query(UserInfo.User.CONTENT_URI, null, null, null, null);
58                 if (null != cursor)
59                 {
60                     if (cursor.moveToFirst())
61                     {
62                         do
63                         {
64                             String name = cursor.getString(cursor.getColumnIndex(UserInfo.User.NAME));
65                             data.add(name);
66                         } while (cursor.moveToNext());
67                     }
68                     cursor.close();
69                 }
70                 // 获取Fragment管理系统对象
71                 FragmentManager fm = getFragmentManager();
72                 // 创建一个fragment对象
73                 UserListFragment userListFragment = UserListFragment.newInstance(data);
74                 // 通过Fragment管理器,将新创建的fragment对象添加到指定的布局容器中
75                 fm.beginTransaction().add(R.id.user_list, userListFragment).commit();
76                 Toast.makeText(getActivity(), "查询数据", Toast.LENGTH_SHORT).show();
77                 break;
78             }
79             default:
80                 Toast.makeText(getActivity(), "Without event in element.", Toast.LENGTH_SHORT).show();
81         }
82     }
83 }

 

  显示数据数据的列表数据界面(UserListFragment):

 1 public class UserListFragment extends ListFragment
 2 {
 3     public static final String sExtra_Users_Key = "users";
 4 
 5     // member method
 6     public static UserListFragment newInstance(ArrayList<String> data)
 7     {
 8         Bundle args = new Bundle();
 9         args.putStringArrayList(sExtra_Users_Key, data);
10         UserListFragment userListFragment = new UserListFragment();
11         userListFragment.setArguments(args);
12 
13         return userListFragment;
14     }
15 
16     // inherit baseclass member method
17     @Override
18     public void onCreate(Bundle savedInstanceState)
19     {
20         super.onCreate(savedInstanceState);
21         ArrayList<String> data = getArguments().getStringArrayList(sExtra_Users_Key);
22         if (null != data)
23         {
24             ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(),
25                     android.R.layout.simple_list_item_1, data);
26             setListAdapter(adapter);
27         }
28     }
29 }

  MianFramgent界面容器(activity_fragment):

1 <FrameLayout
2     xmlns:android="http://schemas.android.com/apk/res/android"
3     android:id="@+id/fragmentContainter"
4     android:layout_width="match_parent"
5     android:layout_height="match_parent">
6 
7 </FrameLayout>

  主界面显示UI样式(fragment_main):

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout
 3     xmlns:android="http://schemas.android.com/apk/res/android"
 4     android:orientation="vertical"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent">
 7 
 8     <LinearLayout
 9         android:layout_width="match_parent"
10         android:layout_height="wrap_content">
11 
12         <TextView
13             android:layout_width="wrap_content"
14             android:layout_height="wrap_content"
15             android:text="@string/main_name"
16             android:textColor="#000"
17             android:textSize="14sp"/>
18 
19         <EditText
20             android:id="@+id/name"
21             android:layout_width="match_parent"
22             android:layout_height="wrap_content"
23             android:textSize="14sp"
24             android:textColor="#000"/>
25 
26     </LinearLayout>
27 
28     <LinearLayout
29         android:layout_width="match_parent"
30         android:layout_height="wrap_content">
31 
32         <TextView
33             android:layout_width="wrap_content"
34             android:layout_height="wrap_content"
35             android:text="@string/main_tel"
36             android:textColor="#000"
37             android:textSize="14sp"/>
38 
39         <EditText
40             android:id="@+id/tel"
41             android:layout_width="match_parent"
42             android:layout_height="wrap_content"
43             android:textSize="14sp"
44             android:textColor="#000"/>
45 
46     </LinearLayout>
47 
48     <LinearLayout
49         android:layout_width="match_parent"
50         android:layout_height="wrap_content"
51         android:orientation="horizontal"
52         android:gravity="center">
53 
54         <Button
55             android:id="@+id/insert"
56             android:layout_width="wrap_content"
57             android:layout_height="wrap_content"
58             android:text="@string/main_insert"
59             android:textColor="#000"/>
60 
61         <Button
62             android:id="@+id/query"
63             android:layout_width="wrap_content"
64             android:layout_height="wrap_content"
65             android:text="@string/main_query"
66             android:textColor="#000"/>
67 
68     </LinearLayout>
69 
70     <FrameLayout
71         android:id="@+id/user_list"
72         android:layout_width="match_parent"
73         android:layout_height="wrap_content">
74 
75         </FrameLayout>
76 
77 </LinearLayout>

  在主界面布局XML文件中,有这样一段代码:

1 <FrameLayout
2         android:id="@+id/user_list"
3         android:layout_width="match_parent"
4         android:layout_height="wrap_content">
5 
6         </FrameLayout>

  使用FrameLayout在界面内部再嵌入一个fragment,用于显示列表数据的UI元素,动态载入UserListFragment:

1 // 获取Fragment管理系统对象
2 FragmentManager fm = getFragmentManager();
3 // 创建一个fragment对象
4 UserListFragment userListFragment = UserListFragment.newInstance(data);
5 // 通过Fragment管理器,将新创建的fragment对象添加到指定的布局容器中
6 fm.beginTransaction().add(R.id.user_list, userListFragment).commit();

 

posted @ 2017-05-07 14:56  naray  阅读(773)  评论(0编辑  收藏  举报