Android组件(Content Provider)

1.目录:
    1.Content Provider概述
    2.Content Provider共享数据过程
    3.Content Provider作用
    4.Content Provider创建
    5.Content Provider数据管理(数据的增删改查)
    6.访问Content Provider获取数据
    7.UriMatcher & Uri
    
2.Content Provider概述:
    Content Provider(内容提供者),明白它的含义我们的明白两点,内容是啥?提供给谁?
OK,内容即数据,来自File或者sqlite数据库,该组件主要用于建立一个统一的接口
提供给其他应用访问自己应用数据,同时也可利用他获取其他应用数据,达到信息交互的效果
    
3.Content Provider共享数据过程(例子解释):
    抗战时期的一个地下情报组织(我的APP),建立一个咖啡馆(Content Provider)向上级提供
    情报(数据),上级(其他APP)需要情报的时候会派接头人(ContentResolver)给他暗号和
    地址(URI),让他到咖啡馆来获取情报。
    ps:上面有几个关键的名词ContentResolver 数据 URI他们的作用上面的例子应该能看出来(后面深入讲解)

4.Content Provider作用:
    4.1 向其他app组件提供共享数据
    4.2 存储及检索数据
    
ps:下面用一个例子带描述的形式学习Content Provider的创建管理,以及访问
 
5.Content Provider创建
   5.1 创建Sqlite数据库(伙伴们不知道Sqlite没关系我们先用它讲解Content Provider的使用,后面再单独学习Sqlite)
        5.1.1 创建数据库管理类MyDBOpenHelper继承SQLiteOpenHelper
  
package com.demo.contentproviderdemo;

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

public class MyDBOpenHelper extends SQLiteOpenHelper {
	/*
	 * 带参构造方法,供外部实例化MyDBOpenHelper
	 */
	public MyDBOpenHelper(Context context, String name, CursorFactory factory,
			int version) {
		super(context, name, factory, version);
	}

	/*
	 * 数据库创建时调用,做一些创建数据表和初始化工作(non-Javadoc)
	 */
	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL("CREATE TABLE user(_id integer primary key autoincrement, user_name varchar(20))");
		Log.i("SYS", "create table user");
	}

	/*
	 * 数据库传入版本与传入的版本不同时执行
	 */
	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		db.execSQL("DROP TABLE IF EXISTS user");
		onCreate(db);
	}

}

      
        
   5.2 实现ContentProvider类
     ContentProvider类中需要继承实现了方法:
        1)public boolean onCreate() (创建ContentProvider时调用)
        2)public Cursor query(Uri, String[], String, String[], String) ( 查询指定URI的content provider 返回Cursor)
        3)public Uri insert(Uri, ContentValues) (插入数据到指定Uri的ContentProvider)
        4)public int update(Uri, ContentValues, String, String[]) (更新指定Uri的ContentProvider数据)
        5)public int delete(Uri, String, String[]) (删除指定Uri的ContentProvider数据)

        6)public String getType(Uri) (获得指定数据的MIME类型)


     MyContentProvider  类实现:
package com.demo.contentproviderdemo;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;

/**
 * 
 * @author Andy_lau
 *
 */
public class MyContentProvider extends ContentProvider {
	private MyDBOpenHelper dbOpenHelper;
	// 无uri匹配时默认匹配码NO_MATCH
	private static final UriMatcher MATCHER = new UriMatcher(
			UriMatcher.NO_MATCH);
	private static final int USERS = 1;
	private static final int USER = 2;

	// 静态代码块建立uri和匹配码的映射关系,方便后面根据不同uri进行不同操作
	static {
		MATCHER.addURI("com.demo.contentproviderdemo", "Users", USERS);
		MATCHER.addURI("com.demo.contentproviderdemo", "Users/#", USER);
	}

	/*
	 * MyContentProvider创建时调用,做一些初始化方法
	 */
	@Override
	public boolean onCreate() {
		// 实例化数据库管理类MyDBOpenHelper
		dbOpenHelper = new MyDBOpenHelper(this.getContext(), "user.db", null, 1);
		return true;
	}

	/*
	 * 接收外部数据进行数据查询操作
	 */
	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		Cursor cursor = null;
		SQLiteDatabase db = dbOpenHelper.getReadableDatabase();

		switch (MATCHER.match(uri)) {
		case USERS:
			cursor = db.query("user", projection, selection, selectionArgs,
					null, null, sortOrder);
			break;
		case USER:
			long user_id = ContentUris.parseId(uri);
			String where = "_id =" + user_id;
			where = selection + "and" + where;
			cursor = db.query("user", projection, where, selectionArgs, null,
					null, sortOrder);
			break;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
		return cursor;
	}

	/*
	 * 返回数据的MIME类型
	 */
	@Override
	public String getType(Uri uri) {
		switch (MATCHER.match(uri)) {
		case USERS:
			// 数据集的MIME类型字符串则应该以vnd.android.cursor.dir/开头
			return "vnd.android.cursor.dir/Users";

		case USER:
			// 单一数据的MIME类型字符串应该以vnd.android.cursor.item/开头
			return "vnd.android.cursor.item/Users";

		default:
			throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
		}
	}

	/*
	 * 接收外部数据进行数据插入操作 Uri:外部传入的uri ContentValues:外部传入的数据集合
	 */
	@Override
	public Uri insert(Uri uri, ContentValues values) {
		// TODO Auto-generated method stub
		SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
		switch (MATCHER.match(uri)) {
		case USERS:
			// 特别说一下第二个参数是当name字段为空时,将自动插入一个NULL。
			long rowid = db.insert("user", null, values);
			Uri insertUri = ContentUris.withAppendedId(uri, rowid);// 得到代表新增记录的Uri
			this.getContext().getContentResolver().notifyChange(uri, null);
			return insertUri;

		default:
			throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
		}
	}

	/*
	 * 接收外部数据进行数据删除操作 selection:sql语句中where后面的参考字段 selectionArgs参考字段的值
	 */
	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		// TODO Auto-generated method stub
		SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
		int count = 0;
		switch (MATCHER.match(uri)) {
		case USERS:
			count = db.delete("user", selection, selectionArgs);
			return count;

		case USER:
			// 从uri中获取id
			long id = ContentUris.parseId(uri);
			// 将id拼接到查询语句
			String where = "_id=" + id;
			if (selection != null && !"".equals(selection)) {
				where = selection + " and " + where;
			}
			count = db.delete("user", where, selectionArgs);
			return count;

		default:
			throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
		}
	}

	/*
	 * 接收外部数据进行数据更新操作
	 */
	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
		int count = 0;
		switch (MATCHER.match(uri)) {
		case USERS:
			count = db.update("user", values, selection, selectionArgs);
			return count;
		case USER:
			long id = ContentUris.parseId(uri);
			String where = "_id=" + id;
			if (selection != null && !"".equals(selection)) {
				where = selection + " and " + where;
			}
			count = db.update("user", values, where, selectionArgs);
			return count;
		default:
			throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
		}
	}

}


        
   5.3 Manifest.xml注册ContentProvider

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.Andy.contentprovider"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!-- authorities与MyContentProvider中uriMatcher的第一个参数一致 -->
        <provider
            android:name=".MyContentProvider"
            android:authorities="com.Andy.contentprovider" >
        </provider>
    </application>

</manifest>

  

6.Content Provider数据管理(数据增删改查)

     Content Provider数据管理可用ContentProvider实现类;或者,通过数据库管理类SQLiteOpenHelper去实例化SQLiteDatabase操作类
从而实现数据管理(ContentProvider实现类上面已经实现,通过SQLiteDatabase管理的部分准备在sqlite那一部分去学习)


7.访问Content Provider获取数据

    我们新建一个android工程去访问上面的ContentProvider

    7.1 MainActivity.java(通过ContentResolver访问ContentProvider获取数据并绑定到UI展示)

package com.test.contentresvoler;

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.support.v4.widget.SimpleCursorAdapter;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends Activity {
	private Button button;
	private ListView listView;
	final String uri = "content://com.demo.contentproviderdemo/Users";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		// 绑定button按钮
		button = (Button) findViewById(R.id.button1);
		// 绑定listview
		listView = (ListView) findViewById(R.id.list);
		// 设置button监听
		button.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// 实例化ContentResolver ContentProvider管理类
				ContentResolver contentResolver = getContentResolver();
				// 根据String地址实例化Uri(访问ContentProvider路径)
				Uri addUri = Uri
						.parse("content://com.demo.contentproviderdemo/Users");
				// 实例化数据封装类ContentValues
				ContentValues values = new ContentValues();
				// 放入数据
/*				values.put("_id", 3);
				Log.i("_id", values.get("_id")+"");*/
				values.put("user_name", "Andy");
				// 通过管理类将数据与Uri整合
				Uri uri = contentResolver.insert(addUri, values);
				// toast提示信息
				Toast.makeText(MainActivity.this, "添加成功", Toast.LENGTH_LONG)
						.show();
			}
		});
		// 实例化ContentResolver ContentProvider管理类
		ContentResolver contentResolver = getContentResolver();
		// 根据String地址实例化Uri(访问ContentProvider路径)
		Uri selectUri = Uri
				.parse("content://com.demo.contentproviderdemo/Users");
		// 通过通过管理类将数据与Uri整合contentResolver实例方法获取操作游标Cursor实例
		Cursor cursor = contentResolver
				.query(selectUri, null, null, null, null);
		
		if (cursor == null) {
			Log.i("report", "cursor is null");
		} else {
			while (cursor.moveToNext()) {
				int id = cursor.getInt(cursor.getColumnIndex("_id"));
				String user_name = cursor.getString(cursor.getColumnIndex("user_name"));
				Log.i("id&name", id+"&"+user_name);
				Toast.makeText(MainActivity.this,  id+"&"+user_name, Toast.LENGTH_LONG).show();
			}
			// 设置listview适配器,适配布局和数据
			/*
			 * MainActivity.this
			 */
			ListAdapter listAdapter = new SimpleCursorAdapter(MainActivity.this, R.layout.list,
					cursor, new String[] { "_id", "user_name" }, new int[] {
							R.id.value_id, R.id.value_name },0);
			listView.setAdapter(listAdapter);
		    }
			

		// 设置listview item监听
		listView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				// 通过位置获取listview显示内容,强制类型转换为Cursor
				Cursor cursor = (Cursor) listView.getItemAtPosition(position);
				// 通过cursor方法获取对应字段的值
				int name = cursor.getColumnIndex("user_name");
				// toast提示信息
				Toast.makeText(MainActivity.this, name + "", Toast.LENGTH_LONG)
						.show();
			}
		});

	}

}
    7.2 主UI布局activity_main.xml(展示查询结果)
 
<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="com.test.contentresvoler.MainActivity" >

    <!-- text的内容尽量写到 strings.xml中,方便国际化 -->

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="添加" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/id"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="25dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="编号" />

        <TextView
            android:id="@+id/name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="25dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="姓名" />
    </LinearLayout>

    <ListView
        android:id="@+id/list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >
    </ListView>

</LinearLayout>

    7.3 ListView 自定义布局list.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="wrap_content"
    android:orientation="horizontal" >

       <TextView  
          android:layout_width="0dp"  
          android:layout_height="wrap_content"  
          android:layout_weight="1" 
          android:id="@+id/value_id" 
           android:layout_gravity="center"   
          android:gravity="center" 
          />  
        
     <TextView  
          android:layout_width="0dp"  
          android:layout_height="wrap_content"  
          android:layout_weight="1"
          android:layout_gravity="center"  
          android:id="@+id/value_name"
          android:gravity="center"  
          /> 

</LinearLayout>


8.UriMatcher & Uri

    UriMatcher:我们先解释一下,UriMatcher用在哪儿,作用是啥?
        UriMatcher用在Contentprovider实现类中,用来创建“暗号”接口路径和建立路径与code的匹配关系
    //authority即是你注册provider的时候定义的路径(包名),path即访问路径可为table名,也可自定义
    //code只是一个匹配码,一个Uri对应一个匹配码,用于后面对不同的uri执行不同的操作
    uriMatcher.addURI(authority, path, code);
    
    URI:上面提到过Uri相当于暗号和地址,什么意思呢,就是我定义一个Contentprovider开放一个“暗号”接口,好你ContentResolver

        想要获得我提供的数据,你先根据地址找到我并告诉我暗号,如果暗号匹配我就把数据给你,这就是URI主要作用。


参考:http://blog.csdn.net/wangkuifeng0118/article/details/7028953

PS:学习大神们的,自己的思路总结,谢谢大神们的分享!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值