歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

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;
    }
Copyright © Linux教程網 All Rights Reserved