ContentsProviderの使い方の基本(Android)

#ContentsProviderの使い方の基本

##対象者
・異なるアプリ間でDBを共有したい方

##使用するもの
・SQLiteOpenHelperクラス(データベースの作成等に使用します)
・ContentsProviderクラス(データの挿入、削除、データベースの更新等に使用します)

##データベース構成
今回は簡単に作成します。
データベース名:database.db
テーブル名: user
使用するデータ
・id(自動インクリメント)
・username
・email
のみです。

まずはデータベースを作成します。
ちなみにSQLiteで使用できる型は、NULL,INTEGER,REAL,TEXT,BLOBのみです。

```java:MySQLiteOpenHelper.java
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class MySQLliteOpenHelper extends SQLiteOpenHelper {

    private static final int DATABASE_VERSION = 1;//データベースのバージョン
    private static final String DATABASE_NAME = "database.db";//データベースの名前

    public MySQLliteOpenHelper(Context context) {

        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        //テーブル作成
        db.execSQL(
                "create table user (" +
                        "id integer primary key autoincrement, "+
                        "username TEXT not null, "+
                        "email TEXT not null );"
        );

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        
        db.execSQL("drop table user");//テーブルの削除
        onCreate(db);
    }
}
```

コンストラクタでデータベース作成、
OnCreateでテーブル作成しています。
ここがよくわからない方は、これを参照して学んでください。
https://techbooster.org/android/application/567/

##ContentsProviderの作成
コンテンツプロバイダは、query,insert,delete,update等が使用できます。

```java:MyContentsProvider.java


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

import java.net.URI;

public class MyContentProvider extends ContentProvider {
    private MySQLliteOpenHelper helper;

    public MyContentProvider() {
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        SQLiteDatabase db = helper.getWritableDatabase();
        final int count=db.delete(uri.getPathSegments().get(0),selection,selectionArgs);
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }

    @Override
    public String getType(Uri uri) {
        //MiMEタイプのリクエスト
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        SQLiteDatabase db = helper.getWritableDatabase();

        long newRowId = db.insert("user", null, values);
        Uri returnUri = ContentUris.withAppendedId(uri, newRowId);

        return returnUri;

    }

    @Override
    public boolean onCreate() {
        helper=new MySQLliteOpenHelper(getContext());//ヘルパーインスタンの作成
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {
        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
        queryBuilder.setTables("user");

        SQLiteDatabase db = helper.getReadableDatabase();

        Cursor c = db.query(
                uri.getPathSegments().get(0),//テーブル名
                null, // fields(取得したいフィールド
                null, // where句
                null, // where args（whereの引数)
                null, // groupBy句
                null, // having句
                null,//order_by句
                null // LIMIT句
        );

        Log.d("ContentsPro","");
        return c;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) {
        SQLiteDatabase db = helper.getWritableDatabase();
        final int count = db.update(uri.getPathSegments().get(0),values,selection,selectionArgs);
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }
}
```

queryメソッドは適当に変えてください。

##query,insert,delete,update
次にデータを操作する場合の処理を記述します。

```java:MainActivity.java

import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity {
    
    private Uri uri;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        insert();
        query();
        update();
        delete();
        
    }
    
    public void insert(){
        for(int i=0;i<30;i++){
            //ContentValuesにデータを入れる
            ContentValues values=new ContentValues();
            values.put("username","username:"+String.valueOf(i));
            values.put("email","testemail:"+String.valueOf(i)+"@gmail.com");

            getContentResolver().insert(uri,values);//MyContentsProviderのinsertを実行

            Log.d("mainActivity",uri.getPathSegments().get(0));

        }
    }

    public void query(){
        //テーブルのデータを全件表示.
        Cursor c= getContentResolver().query(uri, null, null, null, null);


        while (c.moveToNext()) {
            int id=0;
            String username="";
            String email="";

            id = c.getInt(c.getColumnIndex("id"));
            username=c.getString(c.getColumnIndex("username"));
            email = c.getString(c.getColumnIndex("email"));

            Log.d("DB_TESTS", "id: " + id + " username: " + username + " email: " + email);
        }

        c.close();//カーソルを閉じる
    }

    public void update(){
        ContentValues values=new ContentValues();
        values.put("username","username:"+String.valueOf("abc"));
        values.put("email","testemail:"+String.valueOf("1")+"@gmail.com");

        getContentResolver().update(uri,values,"id=7",null);
    }
    
    public void delete(){
        getContentResolver().delete(uri,"id=5",null);
    }
    
}
```
ContentValuesは(key,value)の形式でputします。
またgetContentsResolverでコンテンツプロバイダの取得ができます。

さらに大事なポイントとして、URIは一意に決めなければなりません。
また他のアプリから、DBにアクセスする場合は、このURIを指定してあげれば、
データを操作することが可能になります。

Uriの形式は"contens://authorities/テーブル名"
です。
またauthoritiesはManifestファイルに記述しなければなりません。

##Permission
最後にContentsProviderはPermission設定が必要なので、設定します。

```xml:AndroidManifest.xml
<provider
            android:name=".MyContentProvider"
            android:authorities="com.example.main"
            android:enabled="true"
            android:exported="true"></provider>
```

これをapplicationタグ内に記述してください。
またexportedをtrueにしないと、他のアプリからデータを使用できないので、
ご注意を

##最後に
これで、どのアプリからでもURIを指定してやれば、共通のDBを使用することができます。
電話帳やメモなどに有効そうですね。
間違っている点や、わからない点がありましたら、言ってください。