ContentProviderから返されたCursor実装を取る
例えば以下のようなAbstractCursorを継承したクラスを作ったとする
package sample.test;
import android.database.AbstractCursor;
import android.provider.BaseColumns;
public class SampleCursor extends AbstractCursor implements BaseColumns {
@Override
public String[] getColumnNames() {
return null;
}
@Override
public int getCount() {
return 0;
}
@Override
public double getDouble(int column) {
return 0;
}
@Override
public float getFloat(int column) {
return 0;
}
@Override
public int getInt(int column) {
return 0;
}
@Override
public long getLong(int column) {
return 0;
}
@Override
public short getShort(int column) {
return 0;
}
@Override
public String getString(int column) {
return null;
}
@Override
public boolean isNull(int column) {
return false;
}
}
あくまでネタとしてなんで実装はほとんど書いてません。それはおいといて
でこれを返すContentProviderを作る
package sample.test;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri;
public class SampleProvider extends ContentProvider {
private static UriMatcher matcher;
static {
matcher = new UriMatcher(UriMatcher.NO_MATCH);
matcher.addURI("sample.provider", "samples", 0);
}
@Override
public String getType(Uri uri) {
return "vnd.android.cursor.dir/sample.provider";
}
@Override
public boolean onCreate() {
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
// 作ったAbstractCursorを継承したクラスのインスタンスを返す
return new SampleCursor();
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int delete(Uri arg0, String arg1, String[] arg2) {
return 0;
}
}
でこれを Uri.parse("content://sample.provider/samples")をgetContentResolver().query した場合に実体クラスでキャストするとどうなるか。結果はClassCastException。理由としてgetContentResolver.queryが返すCursorクラスはContentResolver.CursorWrapperInnerにラップされてる。それはContentResolverのソースコードにもろ書いてる
でこういう場合にqueryメソッドを使って返されるCursorクラスの実体を取得したい場合はどうなるかって話になる訳なのですが
getContentResolver -> acquireContentProviderClient(uri) -> query
っていうようにContentResolverのacquireContentProviderClientメソッドを使ってContentProviderClientクラスを取得する。でそのクラスからqueryをする事で、ラップされずにqueryメソッドから返される結果のCursor実体を取得する事が出来る
実際それをやると
package sample.test;
import android.app.Activity;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
import android.widget.TextView;
public class MainActivity extends Activity {
private Uri uri = Uri.parse("content://sample.provider/samples");
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.main);
fetch1();
fetch2();
}
private void fetch1() {
/* これをやるとClassCastExceptionになる
SampleCursor csr = (SampleCursor)getContentResolver().query(uri, null, null, null, null);
*/
Cursor csr = getContentResolver().query(uri, null, null, null, null);
((TextView)findViewById(R.id.text1)).setText(
"getContentResolver.query: " + csr.toString()
);
}
private void fetch2() {
ContentResolver resolver = getContentResolver();
ContentProviderClient client = resolver.acquireContentProviderClient(uri);
try {
Cursor csr = client.query(uri, null, null, null, null);
((TextView)findViewById(R.id.text2)).setText(
"ContentProviderClient.query: " + csr.toString()
);
} catch(RemoteException e) {
e.printStackTrace();
}
}
}
これを実行すると
というようになる。っていう感じ。だけどそんなにCursorの実体クラスが必要になるケースなんてあんまり無いような気もするけど
もっと簡単に出来る方法あるのかなーって思うところなんだけど
追記
http://yuki312.blogspot.jp/2012/07/androidcontentresolvercontentprovidercl.html
を見ておいた方がいいかも