android基础学习12——内容提供者ContentProvider的使用
2017-06-12 22:39
721 查看
内容提供者(ContentProvider)是Android系统四大组件之一,用于保存和检索数据,是Android系统中不同应用程序之间共享数据的接口。在Android系统中,应用程序之间是相互独立的,分别运行在自己的进程中,相互之间没有数据交换。若应用程序之间需要共享数据,就需要用到ContentProvider。ContentProvider是不同应用程序之间进行数据交换的标准API,它以Uri的形式对外提供数据,允许其他应用操作本应用数据。其他应用则使用ContentResolver,并根据ContentProvider提供的Uri操作指定数据。接下来通过一个案例“读取联系人信息”使用内容提供者暴露数据。该案例实现了查询自己暴露的数据,并将数据捆绑到ListView控件中的功能。
activity.xml
在layout文件夹下创建一个list_item.xml文件
在drawble文件夹下添加一张名为default_avater的图片作为联系人的图片
创建数据库
创建PersonDBProvider类继承ContentProvider,用于实现暴露数据库程序的功能
创建数据库逻辑操作类
MainActivity
需要注意的是,当执行耗时操作时,应创建一个子线程将耗时操作放在子线程中,然后使用handler实现子线程与UI线程的通信。
在清单文件中注册PersonDBProvider
运行程序能看到如图所示
activity.xml
<?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:id="@+id/ll_root" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.lenovo.contentprovider.MainActivity"> <ListView android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="match_parent"> </ListView> </LinearLayout>
在layout文件夹下创建一个list_item.xml文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="60dip" android:gravity="center_vertical" android:orientation="horizontal"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dip" android:src="@drawable/default_avatar"/> <LinearLayout android:layout_width="fill_parent" android:layout_height="60dip" android:layout_marginLeft="20dip" android:gravity="center_vertical" android:orientation="vertical"> <TextView android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dip" android:text="姓名" android:textColor="#000000" android:textSize="18sp"/> <TextView android:id="@+id/tv_phone" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dip" android:layout_marginTop="3dp" android:text="电话" android:textColor="#88000000" android:textSize="16sp" /> </LinearLayout> </LinearLayout>
在drawble文件夹下添加一张名为default_avater的图片作为联系人的图片
创建数据库
package com.example.lenovo.contentprovider; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; /** * Created by lenovo on 2017/6/8. */ public class PersonSQLiteOpenHelper extends SQLiteOpenHelper { private static final String TAG="PersonSQLiteOpenHelper"; //数据库的构造方法,用来定义数据库的名称、数据库查询的结果集、数据库的版本 public PersonSQLiteOpenHelper(Context context){ super(context,"person.db",null,3); } //数据库第一次被创建的时候调用的方法 public void onCreate(SQLiteDatabase db){ //初始化数据库的表结构 db.execSQL("create table person(id integer primary key autoincrement,name varchar(20),number varchar(20))"); } //当数据库的版本号发生变化的时候(增加的时候)调用 public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion){ Log.i(TAG,"数据库的版本变化了......"); } }创建Person类,用于封装id、name和number属性
package com.example.lenovo.contentprovider; /** * Created by lenovo on 2017/6/8. */ public class Person { private int id; private String name; private String number; public Person() { } public String toString() { return "Person [id=" + id + ", name=" + name + ", number=" + number + "]"; } public Person(int id, String name, String number) { this.id = id; this.name = name; this.number = number; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } }创建内容提供者
创建PersonDBProvider类继承ContentProvider,用于实现暴露数据库程序的功能
package com.example.lenovo.contentprovider; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; /** * Created by lenovo on 2017/6/8. */ public class PersonDBProvider extends ContentProvider { // 定义一个uri的匹配器 用于匹配uri 如果路径不满足条件 返回 -1 private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); private static final int INSERT = 1; //添加数据匹配Uri路径成功时返回码 private static final int DELETE = 2; //删除数据匹配Uri路径成功时返回码 private static final int UPDATE = 3; //更改数据匹配Uri路径成功时返回码 private static final int QUERY = 4; //查询数据匹配Uri路径成功时返回码 private static final int QUERYONE = 5; //查询一条数据匹配Uri路径成功时返回码 //数据库操作类的对象 private PersonSQLiteOpenHelper helper; static { // 添加一组匹配规则. matcher.addURI("com.example.lenovo.db.personprovider", "insert", INSERT); matcher.addURI("com.example.lenovo.db.personprovider", "delete", DELETE); matcher.addURI("com.example.lenovo.db.personprovider", "update", UPDATE); matcher.addURI("com.example.lenovo.db.personprovider", "query", QUERY); //这里的“#”号为通配符凡是符合”query/”皆返回QUERYONE的返回码 matcher.addURI("com.example.lenovo.contentprovider.personprovider", "query/#", QUERYONE); } //当内容提供者被创建的时候 调用 适合 数据的初始化 public boolean onCreate() { helper = new PersonSQLiteOpenHelper(getContext()); return false; } //查询数据操作 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { if (matcher.match(uri) == QUERY) { //匹配查询的Uri路径 //匹配成功 ,返回查询的结果集 SQLiteDatabase db = helper.getReadableDatabase(); //调用数据库操作的查询数据的方法 Cursor cursor = db.query("person", projection, selection, selectionArgs, null, null, sortOrder); return cursor; } else if (matcher.match(uri) == QUERYONE) { //匹配成功,根据id查询数据 long id = ContentUris.parseId(uri); SQLiteDatabase db = helper.getReadableDatabase(); Cursor cursor = db.query("person", projection, "id=?", new String[]{id+""}, null, null, sortOrder); return cursor; } else { throw new IllegalArgumentException("路径不匹配,不能执行查询操作"); } } //获取当前Uri的数据类型 public String getType(Uri uri) { if (matcher.match(uri) == QUERY) { // 返回查询的结果集 return "vnd.android.cursor.dir/person"; } else if (matcher.match(uri) == QUERYONE) { return "vnd.android.cursor.item/person"; } return null; } //添加数据 public Uri insert(Uri uri, ContentValues values) { if (matcher.match(uri) == INSERT) { //匹配成功 返回查询的结果集 SQLiteDatabase db = helper.getWritableDatabase(); db.insert("person", null, values); } else { throw new IllegalArgumentException("路径不匹配,不能执行插入操作"); } return null; } //删除数据 public int delete(Uri uri, String selection, String[] selectionArgs) { if (matcher.match(uri) == DELETE) { //匹配成功 返回查询的结果集 SQLiteDatabase db = helper.getWritableDatabase(); db.delete("person", selection, selectionArgs); } else { throw new IllegalArgumentException("路径不匹配,不能执行删除操作"); } return 0; } //更新数据 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { if (matcher.match(uri) == UPDATE) { //匹配成功 返回查询的结果集 SQLiteDatabase db = helper.getWritableDatabase(); db.update("person", values, selection, selectionArgs); } else { throw new IllegalArgumentException("路径不匹配,不能执行修改操作"); } return 0; } }从上述代码中可以看出,在暴露数据的增、删、改、查方法之前,首先需要添加一组用于请求数据操作的Uri,然后在相应的增删改查方法中匹配Uri,匹配成功才能对数据进行操作。
创建数据库逻辑操作类
package com.example.lenovo.contentprovider; import android.content.ContentValues; import android.content.Context; import android.database.sqlite.SQLiteDatabase; /** * Created by lenovo on 2017/6/8. */ public class PersonDao2 { private PersonSQLiteOpenHelper helper; //在构造方法里面完成helper的初始化 public PersonDao2(Context context){ helper=new PersonSQLiteOpenHelper(context); } //添加一条记录到数据库 public long add(String name,String number,int money){ SQLiteDatabase db=helper.getWritableDatabase(); ContentValues values=new ContentValues(); values.put("name",name); values.put("number",number); long id=db.insert("person",null,values); db.close(); return id; } }
MainActivity
package com.example.lenovo.contentprovider; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import java.util.ArrayList; import java.util.List; import java.util.Random; import android.content.ContentResolver; import android.database.Cursor; import android.net.Uri; import android.os.Handler; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends AppCompatActivity { private ListView lv; private List<Person> persons ; //创建一个Handler对象用于线程间通信 private Handler handler = new Handler(){ public void handleMessage(android.os.Message msg) { switch (msg.what) { case 100://接收到数据查询完毕的消息 //UI线程适配ListView lv.setAdapter(new MyAdapter()); break; } }; }; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lv = (ListView) findViewById(R.id.lv); //由于添加数据、查询数据是比较耗时的,因此需要在子线程中做这两个操作 new Thread(){ public void run() { //添加数据 AddData(); //获取persons集合 getPersons(); //如果查询到数据 则向UI线程发送消息 if(persons.size() > 0){ handler.sendEmptyMessage(100); } }; }.start(); } //往person表中插入10条数据 public void AddData(){ PersonDao2 dao = new PersonDao2(this); long number = 885900000l; Random random = new Random(); for(int i=0;i<10;i++){ dao.add("wangwu"+i, Long.toString(number+i), random.nextInt(5000)); } } //利用ContentResolver对象查询本应用程序使用ContentProvider暴露的数据 private void getPersons() { //首先要获取查询的uri String url = "content://com.example.lenovo.db.personprovider/query"; Uri uri = Uri.parse(url); //获取ContentResolver对象 这个对象的使用后面会详细讲解 ContentResolver contentResolver = getContentResolver(); //利用ContentResolver对象查询数据得到一个Cursor对象 Cursor cursor = contentResolver.query(uri, null, null, null, null); persons = new ArrayList<Person>(); //如果cursor为空立即结束该方法 if(cursor == null){ return; } while(cursor.moveToNext()){ int id = cursor.getInt(cursor.getColumnIndex("id")); String name = cursor.getString(cursor.getColumnIndex("name")); String number = cursor.getString(cursor.getColumnIndex("number")); Person p = new Person(id, name, number); persons.add(p); } cursor.close(); } //适配器 private class MyAdapter extends BaseAdapter{ private static final String TAG = "MyAdapter"; // 控制listview里面总共有多个条目 public int getCount() { return persons.size(); //条目个数 == 集合的size } public Object getItem(int position) { return persons.get(position); } public long getItemId(int position) { return 0; } public View getView(int position, View convertView, ViewGroup parent) { //得到某个位置对应的person对象 Person person = persons.get(position); View view = View.inflate(MainActivity.this, R.layout.list_item, null); //一定要在view对象里面寻找孩子的id //姓名 TextView tv_name = (TextView) view.findViewById(R.id.tv_name); tv_name.setText("姓名:"+person.getName()); //电话 TextView tv_phone = (TextView) view.findViewById(R.id.tv_phone); tv_phone.setText("电话:"+person.getNumber()); return view; } } }上述代码使用ContentResolver查询本程序使用ContentProvider暴露的数据。
需要注意的是,当执行耗时操作时,应创建一个子线程将耗时操作放在子线程中,然后使用handler实现子线程与UI线程的通信。
在清单文件中注册PersonDBProvider
<provider android:authorities="com.example.lenovo.db.personprovider" android:name="com.example.lenovo.contentprovider.PersonDBProvider"> </provider>
运行程序能看到如图所示
相关文章推荐
- Android(java)学习笔记246:ContentProvider使用之学习ContentProvider(内容提供者)的目的
- 【Android基础】内容提供者ContentProvider的使用详解
- Android基础内容提供者ContentProvider的使用详解(转)
- Androidx学习笔记(81)--- 内容提供者(ContentProvider)
- Android核心基础-5.Android 数据存储与访问-4.ContentProvider 内容提供者-示例(监听短信)
- Android开发13――内容提供者ContentProvider的基本使用
- Androidx学习笔记(82)--- 内容提供者(ContentProvider)-自定义内容提供者
- Android基础笔记(十三)- 内容提供者原理和简单使用
- Android中内容提供者ContentProvider的理解与基本使用
- [Android Pro] 内容提供者ContentProvider的基本使用
- Android(java)学习笔记252:ContentProvider使用之内容观察者01
- Android(java)学习笔记254:ContentProvider使用之内容观察者(观察发出去的短信)
- [Android Pro] 内容提供者ContentProvider的基本使用
- [Android Pro] 内容提供者ContentProvider的基本使用
- Android自助餐之内容提供者ContentProvider使用
- 无废话Android之listview入门,自定义的数据适配器、采用layoutInflater打气筒创建一个view对象、常用数据适配器ArrayAdapter、SimpleAdapter、使用ContentProvider(内容提供者)共享数据、短信的备份、插入一条记录到系统短信应用(3)
- Android 使用ContentProvider(内容提供者)查询手机联系
- Android中内容提供者ContentProvider的使用
- Android开发13——内容提供者ContentProvider的基本使用 推荐
- Android开发13——内容提供者ContentProvider的基本使用