• 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();
  • 相关阅读:
    JavaScript 预解析
    JavaScript 作用域
    JavaScript 函数
    SlidesJS
    1. Skippr
    HTML5 模拟现实物理效果
    实现各种 CSS3 文本动画效果
    表单填写进度提示效果
    HTML5 WebGL 实现逼真的云朵效果
    【原创】bootstrap框架的学习 第八课 -[bootstrap表单]
  • 原文地址:https://www.cnblogs.com/naray/p/5353965.html
Copyright © 2020-2023  润新知