コンテントプロバイダと Uri とレコードと

ちょっと微妙な部分で頭が混がらがってきたので整理してみます。
以下な動作を前提として

  • 一覧な ListView な Activity から ACTION_VIEW なアクションとある行のデータな Uri で作られてる intent で詳細 Activity が start された
  • intent の中身 (action とか data とか) を見て intent-filter に合致するナニを探索する。この時 data な Uri を元にコンテントプロバイダから Type を取得してマッチ判定をする
  • マッチした Activity が kickoff される

実装の確認をしてみたいと思います。iosched です。

iosched では

例えば SessionDetailFragment では onCreate で以下な処理をしてますね。

        final Intent intent = BaseActivity.fragmentArgumentsToIntent(getArguments());
        mSessionUri = intent.getData();
        mTrackUri = resolveTrackUri(intent);

        if (mSessionUri == null) {
            return;
        }

        mSessionId = ScheduleContract.Sessions.getSessionId(mSessionUri);
  • 引数から Intent に変換して
  • getData で SessionUri 取得
  • resolvTrackUri メソド (ローカル?) で TrackUri 取得

Uri から Id げとするメソドも ScheduleContract に定義されている模様 (確認スルー)。あと、onActivityCreated メソドにて以下な処理をしてますね。

        // Start background queries to load session and track details
        final Uri speakersUri = ScheduleContract.Sessions.buildSpeakersDirUri(mSessionId);

        mHandler = new NotifyingAsyncQueryHandler(getActivity().getContentResolver(), this);
        mHandler.startQuery(SessionsQuery._TOKEN, mSessionUri, SessionsQuery.PROJECTION);
        mHandler.startQuery(TracksQuery._TOKEN, mTrackUri, TracksQuery.PROJECTION);
        mHandler.startQuery(SpeakersQuery._TOKEN, speakersUri, SpeakersQuery.PROJECTION);

基本的に Uri でコンテントプロバイダにアクセスしているものと信じたいのですが、実装が見えてないので断言はしない方が良さげ。上記 NotifyingAsyncQueryHandler って AsyncQueryHandler を継承してるんですが、これって何でしょ。

android.content.AsyncQueryHandler

マニュアルでは以下な記述。

A helper class to help make handling asynchronous ContentResolver queries easier.

って、よくよく考えたら Uri ってそれ自身がどのコンテントプロバイダのどのデータなのか、ということを表現したものなのだ、ということに気づいてとほほだったりして。

それにしても

コンテントプロバイダと Intent と intent-filter の関係はなかなかに深いですな。
# 今サラ杉でスミマセン

てゆーか

そもそも ContentProvider なソレがどうやって Uri で query するんだ、ってあたりが完全に抜けてたりしてます。ちょっと基本的な部分を再確認する必要あり。

追記

Google 先生が教えてくれるナニでは Uri を上手に使って Activity のルーティングと並行しつつデータ操作を行なう例はなかなかないみたい。iosched の記述によれば以下なカンジなのかな。

    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
            String sortOrder) {
        if (LOGV) Log.v(TAG, "query(uri=" + uri + ", proj=" + Arrays.toString(projection) + ")");
        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();

        final int match = sUriMatcher.match(uri);
        switch (match) {
            default: {
                // Most cases are handled with simple SelectionBuilder
                final SelectionBuilder builder = buildExpandedSelection(uri, match);
                return builder.where(selection, selectionArgs).query(db, projection, sortOrder);
            }

このあたりを中心に探しつつ Content Provider を確認入れてみます。