[每天学点Android开发]为应用程序自定义ContentProvider对象以共享数据

今日学习任务:以简单的备忘录应用程程序为例,实现ContentProvider,并测试。

涉及的主要内容:1) 创建ContentProvider所需的步骤 2)学习官方实例代码(Note Pad)  

 

1. 如何为自己的应用程序自定义ContentProvider

   首先,我们得有数据。所以,需要创建一个SQLite数据库来存储数据。而为了访问数据库,我们需要提供访问数据库的各种接口,如创建,打开,升级等

   其次,创建一个类,继承ContentProvider类,并实现其中访问数据的所有方法,包括:1)query():查询  2) insert():插入  3)update():插入  4)delete():删除  5)getType():获得类型  6)onCreate():创建时调用。

   最后,定义好的ContentProvider类必须在AndroidManifest.xml里声明后,才能使用。声明中必须添加的参数是授权属性“android:authorities”。

   在实际的写代码过程中,目前只能好好研究developer.android.com上面的相关实例代码,学习Google提供的良好规范的代码:

   http://developer.android.com/resources/samples/NotePad/src/com/example/android/notepad/index.html

   在这个Note pad的例子中,Notepad.java和NotePadProvider.java两个文件是与创建ContentProvider相关的两个文件。其中Notepad.java类定义了用于可以访问的ContentProvider的常量,之所以创建这个文件,我觉得是优化代码架构而把常量写在同一个类中方便调用和访问。而NotePadProvider则主要涉及数据的相关操作,包括数据库的创建,连接以及继承实现ContenProvider类的6个方法。在阅读这部分代码时,对我来说最大的苦难是需要很好地理解URI的原理,只有这样才能看懂Google提供的代码的结构。关于URI的理解请参考官方文档:

http://developer.android.com/guide/topics/providers/content-providers.html#creating  中最后部分:Content URI Summary。

   令人欣慰的是,Google提供的实例代码有详细的注释,这样方便了我们去理解和学习。 

2.  现在以备忘录程序为例,来实现以上各个部分。

  注:假设备忘录程序中只有一张数据表,叫做Memo, 表中有两个字段: _ID 和 MemoContent。 

  2.1 参考Notepad.java 创建 MemoContract.java 类,定义各种 主要的URI和数据表字段常量。之所以定义这个类,可以参考下面关于该类的注释

package  com.memo;
import  android.net.Uri;
import  android.provider.BaseColumns;

/**
 * Defines a contract between the Memo content provider and its clients. 
 * A contract defines the information that a client needs to access the provider as one or more data tables.
 * A contract is a public, non-extendable (final) class that contains constants defining column names and URIs. 
 * A well-written client depends only on the constants in the contract.
 
*/
public   final   class  MemoContract {
    
/**
     * identification of the content provider.
     
*/
    
public   static   final  String AUTHORITY  =   " com.memo.MemoProvider " ;

    
/**
     * This class can not be instantiated
     
*/
    
private  MemoContract(){
    }
    
    
/**
     * Memo table contract
     
*/
    
public   static   final   class  Memo  implements  BaseColumns{
        
/**
         * This class can not be instantiated
         
*/
        
private  Memo(){
        }
        
        
/**
         * The table name offered by this provider
         
*/
        
public   static   final  String TABLE_NAME  =   " Memo " ;

        
        
/*  URI definition  */
        
/**
         * The content:// style URL for this table
         
*/
        
public   static   final  Uri CONTENT_URI = Uri.parse( " content:// " + AUTHORITY + " / " + TABLE_NAME);
        
        
/*  MIME definitions  */
        
/**
         * The MIME type of {
@link  #CONTENT_URI} providing a directory of memo.
         
*/
        
public   static   final  String CONTENT_TYPE =   " vnd.android.cursor.dir/vnd.companyName.memo " ;
        
/**
         * The MIME type of a {
@link  #CONTENT_URI} sub-directory of a single memo.
         
*/
        
public   static   final  String CONTENT_ITEM_TYPE =   " vnd.android.cursor.item/vnd.companyName.memo " ;
        
        
/*  Default sort order and column definitions for this table  */
        
/**
         * The default sort order for this table
         
*/
        
public   static   final  String DEFAULT_SORT_ORDER  =  _ID + "  DESC " ;
        
/**
         * Column name for the content of the memo
         * <P>Type: TEXT</P>
         
*/
        
public   static   final  String COLUMN_NAME_CONTENT  =   " MemoContent " ;

    }
}


  2.2 参考NotePadProvider.java创建了MemoProvider类,该类提供了访问数据的主要接口,并继承实现了ContenProvider的query()方法,其它方法类似。详细代码如下:

package  com.memo;

import  java.util.HashMap;
import  com.memo.MemoContract.Memo;
import  android.content.ContentProvider;
import  android.content.ContentValues;
import  android.content.Context;
import  android.content.UriMatcher;
import  android.database.Cursor;
import  android.database.sqlite.SQLiteDatabase;
import  android.database.sqlite.SQLiteOpenHelper;
import  android.database.sqlite.SQLiteQueryBuilder;
import  android.net.Uri;
import  android.text.TextUtils;
import  android.util.Log;

/**
 * Provides the access to the data of Memo
 
*/
public   class  MemoProvider  extends  ContentProvider {

    
/**
     * a new DbHelper 
     
*/
    
private  DbHelper dbHelper;
    
/**
     * Create and initialize a UriMatcher instance
     
*/
    
private   static   final  UriMatcher sUriMatcher  =   new  UriMatcher(UriMatcher.NO_MATCH);;
    
//  The incoming URI matches the Memo URI pattern
     private   static   final   int  MEMOS  =   1 ;
    
//  The incoming URI matches the Memo ID URI pattern
     private   static   final   int  MEMO_ID  =   2 ;
    
static {
        
//  Add a pattern that routes URIs terminated with "Memos" to a Memos operation
        sUriMatcher.addURI(MemoContract.AUTHORITY,  " Memo " , MEMOS);
        
//  Add a pattern that routes URIs terminated with "Memos" plus an integer
        
//  to a memo ID operation
        sUriMatcher.addURI(MemoContract.AUTHORITY,  " Memo/# " , MEMO_ID);
    }
    
/**
     * A projection map used to select columns from the database
     
*/
    
private   static  HashMap < String, String >  ProjectionMap;

    
/*  constants for whole database  */
    
private   static   final  String DATABASE_NAME =   " db " ;
    
private   static   final   int  DATABASE_VERSION =   2 ;
    
    
/*  table creation SQL statements  */
    
public   static   final  String CREATE_TABLE_MEMO =   " create table  " + Memo.TABLE_NAME + "  ( "
                               
+ Memo._ID + "  integer primary key autoincrement,  "
                               
+ Memo.COLUMN_NAME_CONTENT + "  text) " ;
    
    
/**
     * The helper class which manage the database creation and database version upgrade
     
*/
    
private   class  DbHelper  extends  SQLiteOpenHelper{

        
public  DbHelper(Context context) {
            
super (context, DATABASE_NAME,  null , DATABASE_VERSION);
        }
        
/**
         * Create the data table by executing the SQL statement
         
*/
        @Override
        
public   void  onCreate(SQLiteDatabase db) {
            db.execSQL(CREATE_TABLE_MEMO);
        }

        
/**
         *
         * Demonstrates that the provider must consider what happens when the
         * underlying database is changed. In this sample, the database is upgraded 
         * by destroying the existing data.
         * A real application should upgrade the database in place.
         
*/
        @Override
        
public   void  onUpgrade(SQLiteDatabase db,  int  oldVersion,  int  newVersion) {
            
            
//  Logs that the database is being upgraded
            Log.w(DATABASE_NAME,  " Upgrading database from version  "   +  oldVersion  +   "  to  "   +  newVersion
                    
+   " , which will destroy all old data " );
            
//  Kills the table and existing data
            db.execSQL( " DROP TABLE IF EXISTS Memo " );
            
//  Recreates the database with a new version
            onCreate(db);
        
        }
        
    }
    
    
/**
     *
     * Initializes the provider by creating a new DbHelper. onCreate() is called
     * automatically when Android creates the provider in response to a resolver request from a
     * client.
     
*/
    @Override
    
public   boolean  onCreate() {
        
//  Creates a new helper object. Note that the database itself isn't opened until
        
//  something tries to access it, and it's only created if it doesn't already exist.
        dbHelper = new  DbHelper(getContext());
        
        
//  Assumes that any failures will be reported by a thrown exception.
         return   true ;
    }
    
    
/**
     * This method is called when a client calls
     * {
@link  android.content.ContentResolver#query(Uri, String[], String, String[], String)}.
     * Queries the database and returns a cursor containing the results.
     *
     * 
@return  A cursor containing the results of the query. The cursor exists but is empty if
     * the query returns no results or an exception occurs.
     * 
@throws  IllegalArgumentException if the incoming URI pattern is invalid.
     
*/
    @Override
    
public  Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
            String sortOrder) {
        
        
//  Constructs a new query builder and sets its table name
        SQLiteQueryBuilder qb  =   new  SQLiteQueryBuilder();
        
/**
         * Choose the projection and adjust the "where" clause based on URI pattern-matching.
         
*/
        
switch  (sUriMatcher.match(uri)) {
               
//  If the incoming URI is for menos, chooses the Memos projection
                case  MEMOS:
                   qb.setTables(Memo.TABLE_NAME);
                   qb.setProjectionMap(ProjectionMap);
                   
break ;

               
/*  If the incoming URI is for a single memo identified by its ID, chooses the
                * memo ID projection, and appends "_ID = <MemoID>" to the where clause, so that
                * it selects that single memo
                
*/
               
case  MEMO_ID:
                   qb.setTables(Memo.TABLE_NAME);
                   qb.setProjectionMap(ProjectionMap);
                   qb.appendWhere(
                       Memo._ID 
+      //  the name of the ID column
                        " = "   +
                       
//  the position of the memo ID itself in the incoming URI
                       uri.getPathSegments().get( 1 ));
                   
break ;
               
default :
                   
//  If the URI doesn't match any of the known patterns, throw an exception.
                    throw   new  IllegalArgumentException( " Unknown URI  "   +  uri);
           }


           String orderBy;
           
//  If no sort order is specified, uses the default
            if  (TextUtils.isEmpty(sortOrder)) {
               orderBy 
=  Memo.DEFAULT_SORT_ORDER;
           } 
else  {
               
//  otherwise, uses the incoming sort order
               orderBy  =  sortOrder;
           }

           
//  Opens the database object in "read" mode, since no writes need to be done.
           SQLiteDatabase db  =  dbHelper.getReadableDatabase();

           
/*
            * Performs the query. If no problems occur trying to read the database, then a Cursor
            * object is returned; otherwise, the cursor variable contains null. If no records were
            * selected, then the Cursor object is empty, and Cursor.getCount() returns 0.
            
*/
           Cursor c 
=  qb.query(
               db,            
//  The database to query
               projection,     //  The columns to return from the query
               selection,      //  The columns for the where clause
               selectionArgs,  //  The values for the where clause
                null ,           //  don't group the rows
                null ,           //  don't filter by row groups
               orderBy         //  The sort order
           );

           
//  Tells the Cursor what URI to watch, so it knows when its source data changes
           c.setNotificationUri(getContext().getContentResolver(), uri);
           
return  c;
    }
    
    @Override
    
public   int  delete(Uri arg0, String arg1, String[] arg2) {
        
//  TODO Auto-generated method stub
         return   0 ;
    }

    @Override
    
public  String getType(Uri arg0) {
        
//  TODO Auto-generated method stub
         return   null ;
    }

    @Override
    
public  Uri insert(Uri arg0, ContentValues arg1) {
        
//  TODO Auto-generated method stub
         return   null ;
    }



    @Override
    
public   int  update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
        
//  TODO Auto-generated method stub
         return   0 ;
    }

 

  2.3 在AndroidMenifest.xml中声明我们定义的ContentProvider:

< provider  android:name ="MemoProvider"
          android:authorities
="com.memo.MemoProvider" >

</ provider>


  2.4 为了测试我定义的ContentProvider,我们在创建的Main.activity中,利用ContentResolver读取数据,并用ListView显示:参考上一篇博文: http://www.cnblogs.com/ruiyi1987/archive/2011/06/20/2084925.html  代码如下:

 

package  com.memo;

 

import  java.util.ArrayList;
import  com.memo.MemoContract.Memo;
import  android.app.ListActivity;
import  android.database.Cursor;
import  android.net.Uri;
import  android.os.Bundle;
import  android.widget.ArrayAdapter;
import  android.widget.ListView;

public   class  Main  extends  ListActivity {
    
    
/**  Called when the activity is first created.  */
    @Override
    
public   void  onCreate(Bundle savedInstanceState) {
        
super .onCreate(savedInstanceState);
        
        Uri memoUri
=  Memo.CONTENT_URI;
        String[] proj1
= new  String[]{Memo.COLUMN_NAME_CONTENT};
        Cursor cur
= getContentResolver().query(memoUri,proj1,  null null null );
           
        
// declare a ArrayList object to store the data that will present to the user
        ArrayList < String >  memoList = new  ArrayList < String > (); 
        
if (cur.getCount() > 0 ){
            
while (cur.moveToNext()){   
                memoList.add(cur.getString(
0 ));
            }
        }
   
        
//  binding the data to ListView 
        setListAdapter( new  ArrayAdapter < String > ( this ,android.R.layout.simple_list_item_1, memoList));
        ListView lv
= getListView();
        lv.setTextFilterEnabled(
true );
    }
}

转载于:https://www.cnblogs.com/ruiyi1987/archive/2011/06/24/2087704.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值