3

複雑なオブジェクトのリストを操作する Android アプリケーションを設計しています。オブジェクトには、一連の属性 (重要度や最終閲覧時間など) を伴うテキスト データまたはグラフィック データが含まれます。3 つのルールに従うコピー アンド ペースト機能でアプリを支援したいと思います。

  • ユーザーがオブジェクトをコピーしてアプリに貼り付けると、同じ属性を持つオブジェクトの完全なコピーが追加されます。
  • ユーザーがオブジェクトをコピーし、新しいコピー/貼り付け API (android.content.ClipboardManager) を使用する他のアプリに貼り付けると、そのアプリは、オブジェクトが表すデータがテキスト データかグラフィック データかに応じて、テキストまたは画像を受け取ります。画像の場合、そのアプリはファイル パスまたはメディア ギャラリー コンテンツ URI の形式で画像を受け取ります。
  • ユーザーがオブジェクトをコピーして、旧式の非推奨 API (android.text.ClipboardManager) を使用する他のアプリに貼り付けると、そのアプリはオブジェクトによって表されるテキストのみを受け取ります。オブジェクトが画像を表す場合、そのアプリはテキスト表現または空のテキストで URI を受け取ります。

これまでのところ、Google ドキュメントを調べたり、さまざまなプログラミング フォーラムを閲覧したりしましたが、これを行う方法や、それが実現不可能であるという説明についての回答は見つかりませんでした。現在、私は 2 つの悪から選択する必要があります
。1) オブジェクトを操作するコンテンツ プロバイダーを作成し、コンテンツ URI をクリップボードにコピーします。残念ながら、これはサード パーティのアプリケーションがテキストや画像を取得するために、コンテンツ プロバイダーの内部組織を認識している必要があることを意味します。
2) クリップボードにテキスト データのみ (ClipDescription.MIMETYPE_TEXT_PLAIN タイプ) または画像への URI (ClipDescription.MIMETYPE_TEXT_URILIST タイプ) のみをコピーします。このような場合、自分のアプリケーションに貼り付けるときにオブジェクトの属性を保持できません。

何か案は?

4

1 に答える 1

0

a を使用するのContentProviderは正しいことです。他のアプリは、コンテンツの構造や構成を理解する必要はありません。コンテンツ URI は不透明な識別子として使用でき、(API 11 以降では) 1 つの URI に複数のタイプを含めることができます。

テキストとして貼り付け

を実装するContentProvider.openTypedAssetFileと、プロバイダーは画像を要求するクライアントに画像を提供し、ベンダー固有の MIME タイプを要求するクライアントに内部データ形式を提供できます。ClipData.Item.coerceToTextこれは、が任意のコンテンツ URI からテキストを取得するために使用するメカニズムです: typetext/*を要求し、返されたストリームを文字列に読み取ります。(無限のテキスト ストリームをコピーしようとしないでください!) この呼び出しが失敗した場合にのみ、URI 自体のテキストを配置します。レガシーgetTextAPI もこのcoerceToText関数を使用します。これにより、従来のクライアントとテキストのみのクライアントが整理されます。

画像として貼り付け

画像のみが必要なクライアントは、上記と同じメカニズムを使用する必要があります。つまり、テキストContentProvider.openTypedAssetFileとして使用されますが、要求されたタイプはimage/*. ただし、すべてのクライアントがそれを行うことに依存できるとは思わないため、(ベンダー固有のタイプではなく) その URI のイメージ タイプを実装ContentProvider.getTypeして返すことをお勧めします。ContentProvider.getStreamTypes

query(the value of) という列を持つカーソルを返すように実装しますMediaStore.Images.ImageColumns.DATAMediaStore.Images.ImageColumnsこれらのクライアントにメタデータを提供する場合は、他の列を含めることもできます。

openFile次に、画像のファイル記述子を返すように実装するだけです。引数を確認して、mode他のアプリにファイルへの書き込みを許可しないようにしてください。あなたが持っているパスから戻る必要があるParcelFileDescriptor.openを作成するために呼び出すことができます。ParcelFileDescriptor

ベンダー固有のオブジェクトとして貼り付け

これで、サービスのすべてのサードパーティ クライアントが処理されました。では、自分のアプリに貼り付けてみてはどうでしょうか? ここでできることは 2 つあります。前のセクションで述べたように、 を使用ContentResolver.openTypedAssetDescriptorFileしてベンダー固有の型を要求し、実装ContentProvider.openTypedAssetFileしてその型のストリームを返すことができます。これは、アプリ固有のデータがシリアル化されたデータなどを含む特別な種類のファイルである場合に適しています。アプリ固有のコンテンツがデータベースの行である場合は、 を使用できます。上記queryの列だけでなく、返されたカーソルに任意のアプリ固有のデータを配置できます。MediaStore

ContentProviderこれらの方法のいずれかを使用すると、ストレージ メカニズムからフロントエンドを抽象化するための便利な方法が提供されます。私は 1 つのアプリで共有を実装するときにそれを行いました。これは非常に前向きな変化であり、明確な境界を課し、データベースへの卑劣でカプセル化に違反するすべてのアクセスをクリーンアップすることを余儀なくされ、その結果、コードベースの保守が容易になりました。 . Loaderまた、 s、Adapters、およびContentObservers の組み込みサポートを使用して、フロントエンド コードのサイズを縮小することも容易になりました。

しかし、この強制的なカプセル化の境界がアプリにとって不適切な場所にある場合や、貼り付け先がカーソルやシリアル化されたデータだけでなく、同じ Java オブジェクトにアクセスする必要がある場合もあります。その場合、貼り付け先のコードが貼り付けられた URI を解析し、そこから識別子を読み取るのは簡単です。次に、関連するデータ オブジェクトへの参照を取得するために、(既存のメカニズムを使用して) バックエンド コードと直接対話できます。使用する必要はまったくありませんContentResolver

結論

これらはすべて、開くには大きなワームの缶のように思えるかもしれませんが、ある意味ではそうです。しかしContentProvider、実際には、1 つのことだけを実行したい場合に実装するのは非常に簡単です。また、いったん開始すると、解決に役立つ他の問題が見つかる可能性があります。

于 2013-08-02T13:13:02.023 に答える