Android: ContentProviderとSQLiteでデータの登録・削除・検索

AndroidのContentProviderとSQLiteでデータの登録・削除・検索をするサンプルを作ってみました。
(ContentProviderの機能確認のための、基本的なメソッドのみを使った簡単なサンプルです。)


アプリの内容:

・カラム2とカラム3の値を指定して登録ボタンを押すと、データが登録される
・カラム1(_ID)にID番号を指定して削除ボタンを押すと、該当するデータが削除される
 カラム1に値を指定しないで削除ボタンを押すと、全データが削除される
・カラム1(_ID)にID番号を指定して表示ボタンを押すと、該当するデータが表示される
 カラム1に値を指定しないで表示ボタンを押すと、全データが表示される

処理の流れは次のようになります。

  Activity
   getConentResolver().insert
   getConentResolver().delete
   getConentResolver().query
    ↓
  クエリ発行
    ↓
  ContentProvider ( URIは content://jp.knowd.helloprovider <= 今回の例 )
    ↓
  SQLiteデータベース

ここままだと画面のレイアウトがあまり良くないので、次回はxmlファイルでWidgetを画面にレイアウトし、データの表示も表で行なってみます。

[ ContentProviderについて ]
http://developer.android.com/guide/topics/providers/content-providers.ht...

Content providers store and retrieve data and make it accessible to all applications. They're the only way to share data across applications; there's no common storage area that all Android packages can access.

[ 使用した主なクラスとメソッド ]
ContentProvider
http://developer.android.com/reference/android/content/ContentProvider.h...

Content providers are one of the primary building blocks of Android applications, providing content to applications. They encapsulate data and provide it to applications through the single ContentResolver interface. A content provider is only required if you need to share data between multiple applications. For example, the contacts data is used by multiple applications and must be stored in a content provider. If you don't need to share data amongst multiple applications you can use a database directly via SQLiteDatabase.

The primary methods that need to be implemented are:
 * onCreate() which is called to initialize the provider
 * query(Uri, String[], String, String[], String) which returns data to the caller
 * insert(Uri, ContentValues) which inserts new data into the content provider
 * update(Uri, ContentValues, String, String[]) which updates existing data in the content provider
 * delete(Uri, String, String[]) which deletes data from the content provider
 * getType(Uri) which returns the MIME type of data in the content provider

SQLiteOpenHelper
http://developer.android.com/reference/android/database/sqlite/SQLiteOpe...

A helper class to manage database creation and version management.

This class makes it easy for ContentProvider implementations to defer opening and upgrading the database until first use, to avoid blocking application startup with long-running database upgrades.

SQLiteDatabase
http://developer.android.com/reference/android/database/sqlite/SQLiteDat...

Exposes methods to manage a SQLite database.
SQLiteDatabase has methods to create, delete, execute SQL commands, and perform other common database management tasks.

メソッド:

execSQL(String sql)
Execute a single SQL statement that is NOT a SELECT or any other SQL statement that returns data.

execSQL(String sql, Object[] bindArgs)
Execute a single SQL statement that is NOT a SELECT/INSERT/UPDATE/DELETE.

SQLiteQueryBuilder
http://developer.android.com/reference/android/database/sqlite/SQLiteQue...

This is a convience class that helps build SQL queries to be sent to SQLiteDatabase objects.

getContentResolver
http://developer.android.com/guide/topics/providers/content-providers.ht...

It's an interface that clients use indirectly, most generally through ContentResolver objects. You get a ContentResolver by calling getContentResolver() from within the implementation of an Activity or other application component:

 ContentResolver cr = getContentResolver();

You can then use the ContentResolver's methods to interact with whatever content providers you're interested in.

ContentResolverのメソッド:
http://developer.android.com/reference/android/content/ContentResolver.h...

delete(Uri url, String where, String[] selectionArgs)
 Deletes row(s) specified by a content URI.

insert(Uri url, ContentValues values)
 Inserts a row into a table at the given URL.

query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
 Query the given URI, returning a Cursor over the result set.

managedQuery
http://developer.android.com/reference/android/app/Activity.html#managed...

managedQuery(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
This method is deprecated. Use CursorLoader instead.

Wrapper around query(android.net.Uri, String[], String, String[], String) that gives the resulting Cursor to call startManagingCursor(Cursor) so that the activity will manage its lifecycle for you. If you are targeting HONEYCOMB or later, consider instead using LoaderManager instead, available via getLoaderManager().

Parameters

 uri      The URI of the content provider to query.
 projection   List of columns to return.
 selection   SQL WHERE clause.
 selectionArgs The arguments to selection, if any ?s are pesent
 sortOrder   SQL ORDER BY clause.

[ AndroidManifest.xml ]
ここにContentProviderを登録する。以下、今回のサンプルの例。

< provider android:name=".ContentProviderSample" android:authorities="jp.knowd.helloprovider" />

[ サンプルのコード ]
ContentProviderSampleActivity.java

package jp.knowd.ContentProviderSample;

import android.app.Activity;
import android.os.Bundle;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class ContentProviderSampleActivity extends Activity {
    /** Called when the activity is first created. */
	
    //  Widget
    public TextView txtInfo1,txtInfo2, txtInfo3;
    public EditText edtInput1, edtInput2;
    public Button btn1, btn2, btn3;
    public TextView txtResult;
    
    // Uri
    public Uri uri;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // レイアウトを作成
        LinearLayout layout = new LinearLayout(this);
        layout.setOrientation(LinearLayout.VERTICAL);
        setContentView(layout);

        // ラベル1
        txtInfo1 = new TextView(this);
        txtInfo1.setText("カラム1の値(表示,削除時)/カラム2(登録時)の値");
        layout.addView(txtInfo1);
               
        // エディタ1
        edtInput1 = new EditText(this);
        layout.addView(edtInput1);
       
       // ラベル2
        txtInfo2 = new TextView(this);
        txtInfo2.setText("カラム3(登録時)の値");
        layout.addView(txtInfo2);    
       
       // エディタ2
        edtInput2 = new EditText(this);
        layout.addView(edtInput2);      
        
        // ボタン1
        btn1 = new Button(this);
        btn1.setText("登録 (カラム2と3の値を指定する)  ");
        layout.addView(btn1);
        
        // ボタン2
        btn2 = new Button(this);
        btn2.setText("削除 (カラム1の指定なしは全データ)");
        layout.addView(btn2);      
        
        // ボタン3
        btn3 = new Button(this);
        btn3.setText("表示 (カラム1の指定なしは全データ)");
        layout.addView(btn3);
               
        // ラベル3
        txtInfo3 = new TextView(this);
        txtInfo3.setText("ここに検索されたデータが表示される");
        layout.addView(txtInfo3);
       
       // Uri 作成
        uri = Uri.parse("content://jp.knowd.helloprovider");
        
        // ボタン1のイベントを設定 (登録)
        btn1.setOnClickListener(new OnClickListener(){
            public void onClick(View v) {
                String strInput1 = edtInput1.getText().toString();
                String strInput2 = edtInput2.getText().toString();          	
                ContentValues values = new ContentValues();
                values.put("col2", strInput1);
                values.put("col3", strInput2);          
                getContentResolver().insert(uri, values);
             }
        });
        
        // ボタン2のイベントを設定 (削除)
        btn2.setOnClickListener(new OnClickListener(){
            public void onClick(View v) {       
           	String strInput1 = edtInput1.getText().toString();
           	String selection = "_ID=" + strInput1;
              try {getContentResolver().delete(uri, selection, null);}
              catch(Exception e){getContentResolver().delete(uri, null, null);}
             }
        });     
        
        // ボタン3のイベントを設定 (検索/表示)
        btn3.setOnClickListener(new OnClickListener(){
            public void onClick(View v) {
            	String strInput1 = edtInput1.getText().toString();
            	String selection = "_ID=" + strInput1;
            	Cursor cur;
              try {cur = managedQuery(uri, null, selection, null, null);}
              catch(Exception e){cur = managedQuery(uri, null, null, null, null);}
              String str = "_ID | col2 | col3\n";
               str = str + "----------------------\n";
              while (cur.moveToNext()) {
            	      str = str + cur.getString(0) +  " | " + cur.getString(1) +  " | "
            	      + cur.getString(2) + '\n';
                }
              txtInfo3.setText(str);   
            }
        }); 
    }
}

ContentProviderSample.java

package jp.knowd.ContentProviderSample;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
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.provider.BaseColumns;

public class ContentProviderSample extends ContentProvider {
    private static class DatabaseHelper extends SQLiteOpenHelper {
    	
        DatabaseHelper(Context context) {
            super(context, "SQLite.db", null, 1);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL("CREATE TABLE sampletable (" + BaseColumns._ID
                       + " INTEGER PRIMARY KEY," + "col2 TEXT,"
                       + "col3 TEXT" + ");");
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            db.execSQL("DROP TABLE IF EXISTS sampletable");
            onCreate(db);
        }
    }

    DatabaseHelper databaseHelper;

    @Override
    public boolean onCreate() {
        databaseHelper = new DatabaseHelper(getContext());
        return true;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        SQLiteDatabase db = databaseHelper.getWritableDatabase();
        db.insert("sampletable", null, values);
        return null;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        SQLiteDatabase db = databaseHelper.getReadableDatabase();
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
        qb.setTables("sampletable");
        Cursor c = qb.query(db, projection, selection, selectionArgs, null,
                            null, null);
        return c;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
    	SQLiteDatabase db = databaseHelper.getReadableDatabase();
    	db.delete("sampletable", selection, null);
       return 0;
    }
    
    @Override
    public String getType(Uri uri) {
        return null;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        return 0;
    }
}

AndroidManifest.xml