以簡單的備忘錄應用程程序爲例,實現ContentProvider,並測試

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);
    }
}
發佈了14 篇原創文章 · 獲贊 1 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章