<HOME

Intent(暗黙)を使用して別のActivityを表示する30分


前に、明示的Intentを使用して、起動したいActivityを名指しで起動する方法を学習しました。

今回は、暗黙的インテントを使用してActivityを起動する方法について学習します。


Androidは、マーケットにたくさんのアプリケーションが存在し、それらをインストールしているユーザーはまちまちです。

メールを送るのにデフォルトのメールアプリを使っている人が居れば、Gmailアプリを使っている人もいます。


暗黙的Intentを用いれば、ある程度似たような機能をもつActivityを、ユーザーに選択して起動させることができるようになります。

  1. 「StartActivityTraining2」アプリを作成します。

    1. Android Studioを起動し、新規プロジェクトを作成します。

      「Welcome to Android Studio」画面の場合は、「Start a new Android Studio project」をクリックします。

      別のプロジェクトが開いている場合は、ツールバーから「File」→「New」→「New Project...」をクリックします。

    2. HelloWorldの時と同じようにプロジェクトを作成していきます。

      アプリ名は「StartActivityTraining2」としてください。

      今回は「Backwards Compatibility (AppCompat)」のチェックは外しておきます。

  2. 暗黙的Intentを使って、他のアプリのActivityを起動してみましょう。

    1. OptionsMenuから処理を呼び出すようにします。以下のメニューを作成してください。

      • 通話アプリを起動する
      • メールアプリを起動する
      • ブラウザアプリを起動する
      • テキストファイルを表示する
      • 画像ファイルを表示する

      サンプル : res/menu/options.xml

      コードを表示するにはJavaScriptを有効にしてください

    2. 通話アプリを起動する処理を実装します。

      コードを表示するにはJavaScriptを有効にしてください

      明示的Intentの生成時は起動対象のActivityの情報(class)を指定していましたが、

      暗黙的Intentの生成時は、実行したいActionを指定します。

      今回は「(通話アプリのActivityを)表示したい」ので、「ACTION_VIEW」を指定しています。


      また、「何を」表示したいのかを、CategoryやDataで指定することで、起動先を限定します。

      今回はDataに電話番号を詰めることで、起動対象を「電話番号を表示できるActivity」に限定しています。


      DataはUriオブジェクトで格納する必要があります。

      今回はtelスキームの文字列をparseしてUriオブジェクトに変換しています。


      「startActivity」を実行すると、OSが、「アクションがACTION_VIEWで、DataのスキームがtelのIntentを受信できるActivity」を起動してくれます。

      サンプル : MainActivity.java

      コードを表示するにはJavaScriptを有効にしてください

    3. メールアプリを起動する処理を実装します。

      コードを表示するにはJavaScriptを有効にしてください

      メーラー起動のスキームは「mailto」です。

      サンプル : MainActivity.java

      コードを表示するにはJavaScriptを有効にしてください

    4. ブラウザアプリを起動する処理を実装します。

      コードを表示するにはJavaScriptを有効にしてください

      おなじみの「http://~」のURLに対応するActivityを起動します。

      サンプル : MainActivity.java

      コードを表示するにはJavaScriptを有効にしてください

    5. ここまでで一度、アプリを起動して動作を確認してみましょう。



      起動できるActivityが1つのみの場合はそのActivityが起動し、

      起動できるActivityが複数存在する場合はユーザーに選択させるダイアログが表示されます。

    6. テキストファイルを表示する処理を実装します。

      コードを表示するにはJavaScriptを有効にしてください

      FileオブジェクトをUriクラスの「fromFile」メソッドでparseすると、「file://~」のUriオブジェクトになります。

      サンプル : MainActivity.java

      コードを表示するにはJavaScriptを有効にしてください

    7. アプリを起動してテキストファイルを表示する処理を確認してみましょう。

      ・・・クラッシュしました。

      もしかしたら、Android Nより前のバージョンだとクラッシュしないかもしれません。

      Android N以降のバージョンでは、fileスキームでのアプリ間連携は許容されていないため、クラッシュします。

    8. Android N以降のバージョンでは、fileスキームでのアプリ間連携は許容されていないため、

      代わりにcontentスキームを使用して、ContentProvider経由でファイルの所在を起動先に公開します。

      ContentProviderは、コンテンツへのアクセスを管理する役割をもっています。

      コンテンツをDBで管理し、外部からのクエリやインサートに対応します。

      詳細はAPIガイドを確認してください。

      Fileオブジェクトからcontent URIを取得するには、「FileProvider」クラスの「getUriForFile」メソッドを使用します。

      FileProviderの詳細はAPIリファレンスを確認してください。

      1. FileProviderクラスのパッケージは、「android.support.v4.content」です。

        「android.support.v4.*」のAPIを使用するには、Android Support Libraryの該当ライブラリを利用する必要があります。

        詳細はSupport Library の機能を確認してください。

        「Project Structure」→「Dependencies」→「+」→「Library dependency」から、「support-v4」のライブラリを選択します。

      2. Manifestで、FileProviderの利用を宣言します。

        以下の記述を追加してください。

        コードを表示するにはJavaScriptを有効にしてください

        「android:name」で、私用するクラスの名前(FileProvider)を指定します。

        「android:authorities」で、ContentProviderの識別子を指定します。

        他のアプリがProviderを参照するために使用される重要な情報です。

        <アプリのパッケージ名>.provider

        <アプリのパッケージ名>.fileprovider


        「android:exported」で、他アプリからこのProviderにアクセスできるか指定します。

        今回は、無条件にアクセスOKにするのではなく、一時的なパーミッションを有効にする方法をとるので、falseとしています。

        「android:grantUriPermissions」で、一時的なパーミッションを有効にするか指定します。


        「meta-data」で、FileProviderの対象となるファイルパスを定義したリソースファイルを指定しています。


        サンプル : AndroidManifest.xml

        コードを表示するにはJavaScriptを有効にしてください

      3. Manifestから参照される、FileProviderの対象となるファイルパスを定義したリソースファイルを作成します。

        サンプル : res/xml/filepaths.xml

        コードを表示するにはJavaScriptを有効にしてください

        「Environment.getExternalStorageDirectory()」配下を対象にしたい場合は、「external-path」要素を定義します。

        「name」は、content URIのパスに含まれてきます。今回はURIごと受け渡しするので、ぶっちゃけ何でも構いません。

        「path」は、対象にしたいファイル・ディレクトリを「Environment.getExternalStorageDirectory()」からの相対パスで指定します。

        今回は「Environment.getExternalStorageDirectory()」以下全部を対象にしたいので、「.」を指定しています。

      4. FileProviderでファイルを公開するためには、公開する側がファイルにアクセスできる必要があります。

        今回はExternalStorageのファイルをFileProviderで公開しようとしているので、ExternalStorageへのアクセスができないといけません。

        つまり、uses-permissionの宣言が必要ということです。

        サンプル : AndroidManifest.xml

        コードを表示するにはJavaScriptを有効にしてください

    9. 改めて、テキストファイルを表示する処理を実装します。

      ついでに、画像ファイルを表示する処理も実装します。

      コードを表示するにはJavaScriptを有効にしてください

      FileオブジェクトをFileProviderクラスの「getUriForFile」メソッドでUriオブジェクトに変換するように変更しています。

      引数2には、Manifestで定義したFileProviderのauthoritiesを指定します。


      また、Manifestでの定義時にFileProviderを限定公開としていたので、intentに、限定的に公開するためのフラグをセットしています。

      「FLAG_GRANT_READ_URI_PERMISSION」は、URIの読込権限を付与するためのフラグです。


      サンプル : MainActivity.java

      コードを表示するにはJavaScriptを有効にしてください

    10. 改めて、アプリを起動してテキストファイル・画像ファイルを表示する処理を確認してみましょう。

      他アプリでファイルの内容を表示できればOKです。


  3. 暗黙的Intentを受ける側のActivityを実装してみましょう。

    外部からの要求を受けてテキストファイルを表示するActivityを実装します。

    1. 前回似たような処理を実装しましたが、ファイルの読み込み処理は少し変わります。

      ファイル読込のメソッドは以下のような処理になります。

      サンプル

      コードを表示するにはJavaScriptを有効にしてください

      前回はFileオブジェクトからFileReader・BufferedReaderを利用してテキストを1行ずつ読み込みました。

      今回は入力ストリームをFileから直接得るのではなく、ContentResolver経由で、起動元アプリのContentProviderから得るようにします。


      byteデータをためこんでためこんで、最終的に1まとまりのbyte配列として出力するための出力ストリームを用意します。

      入力ストリームから適当な量ずつ読み込んだbyteデータを、その出力ストリームにため込んでいきます。

      最後に出力ストリームにためこんだbyte配列を、文字列に変換します。


      サンプル : res/layout/text_viewer.xml

      コードを表示するにはJavaScriptを有効にしてください

      サンプル : TextViewer.java

      コードを表示するにはJavaScriptを有効にしてください

      サンプル : res/layout/progress.xml

      コードを表示するにはJavaScriptを有効にしてください

      サンプル : ProgressDialog.java

      コードを表示するにはJavaScriptを有効にしてください

    2. Manifestでは以下のように宣言します。

      サンプル

      コードを表示するにはJavaScriptを有効にしてください

      「android:label」で、他アプリから起動される際の名前を指定します。


      「intent-filter」要素は、「このIntentを受信できる」というのを登録しています。


      「action」で、対応するアクション名を記載します。ファイル表示の場合、Intentの送信側では「ACTION_VIEW」を指定していました。

      あの「ACTION_VIEW」定数に与えられている実際の文字列は、「android.intent.action.VIEW」です。

      つまり、ここでは「ACTION_VIEW」のアクションをもつIntentを受信対象に指定しています。


      「category」で、アクションの中でも特定の分類を指定して起動制限をかけられます。

      特にカテゴリによって受信制限をしない場合は、「DEFAULT」を指定する必要があります。


      「data」で、IntentがもつData(URI)によって受信フィルタをかけることができます。

      「android:scheme="content" android:pathPattern=".*\\.txt"」は、「contentスキームで、パスの最後が.txt」のものを受信対象にしています。


      サンプル : AndroidManifest.xml

      コードを表示するにはJavaScriptを有効にしてください

    3. アプリを起動して動作を確認してみましょう。

      他のアプリからも起動できるようになっているはずです。

      ファイルマネージャーアプリ等を使える方は試してみてください。

Intentを用いたアプリコンポーネント間の連携に関する詳細については公式ドキュメントに記載されています。

また、Androidは先人たちがネット上にたくさんの情報を残してくれています。

これらも活用して、是非このAPIを有効に使えるようになってください。