暗黙的インテントで画像を指定し、外部のビュワーに渡すテスト


2014年4月24日現在、私が理解している内容です。
間違っている場合があります。


明示的インテントと、暗黙的インテント

インテントで、相手を呼び出すために、以下のようなメソッドが使われますが、これを「明示的インテント」といいます。
呼び出す側の相手をハッキリと指定しています。


//サービスを呼び出す明示的インテント startService(new Intent(MainActivity.this,MyServiceS1.class));

一方、何か、画像を選択したとき、画像ビュワーの選択肢が複数出てきて、
ユーザーが好きな画像ビュワーを選択し、画像を見る、というしくみに使われるのが、「暗黙的インテント」と呼ばれるものです。
直接、呼び出すアプリを指定するのではなく、「こんなデータを処理したい」という命令だけで、
「そのデータを受け取れるアプリ」がリストアップされるので、ユーザーがどれかを選んで実行するというものです。



「IMAGE」ボタンを押すと、ある指定された画像を、「暗黙的インテント」で、他のビュワーに渡す。

 


androidに登録されてるビュワーが選択肢に出てくるので、どれかを選ぶと、そのビュワーで画像が表示される。

 



このような「暗黙的インテント」は、わりと簡単に実現できます。
以下は、ブラウザを起動して、指定したアドレスのサイトを表示させるというものです。


//ブラウザを呼び出す暗黙的インテント Uri uri = Uri.parse("http://www115.sakura.ne.jp/~byunbyun/index.html"); Intent intent = new Intent(Intent.ACTION_VIEW,uri); startActivity(intent);

ブラウザで、指定のアドレスを開く。




じゃあ、ブラウザじゃなくて、最初の例のように、任意の画像を選択して、画像ビュワーを呼び出すには、
どうすればいいの?

というところで、ちょっとつまづいたので、メモしておこうというコーナーです。




暗黙的インテントで、SDカードの画像を指定する方法

ウェブで調べても、ブラウザや、地図やメールの呼び出し方は、よくご紹介されてて参考にさせていただきましたが、
「SDカードの画像を指定して暗黙的インテントで渡す」という、そのものズバリの情報が少ないので困り果てました。
海外のサイトも覗いて、断片的情報をかき集めて、ようやく以下の記述でよさそうだ、というところに行き着いたところです。


//画像を渡す File file = new File("/sdcard/test2.jpg"); Intent intent = new Intent(); intent.setAction(android.content.Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), "image/*"); startActivity(intent);


ポイントは、画像ファイルのアドレスを、Fileオブジェクトにして、「Uri.fromFile()」に渡せばいい、というところです。
「Uri.fromFile()」というメソッドがあることに気がつく前は、「Uri.parse()」を使ってあーだこーだ、コードをいじくってましたが、
さっぱりうまくいかずに悩みました。

いや、「Uri.parse()」でも、出来ることは出来るようです。
こんな記述でもOKです。


Intent intent = new Intent(); intent.setAction(android.content.Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse("file:///sdcard/test2.jpg"), "image/*"); startActivity(intent);

この場合、「file:///〜」という不可思議な文字列を用意しなければいけません。
この、「file:///〜」という記法は、なんなんだろうかというと、
Uriが使うためのアドレスだろうなあ、というのは、だいたいわかります。

androidの機種によっては、ディレクトリ構造が違う場合もあるようなので、
機種依存を吸収するため、絶対パスよりは抽象パスを使ったほうがシステム上都合が良いということなのでしょう。

というわけで、絶対パスで指定するよりは、Uriが処理しやすい「file:///〜」で渡したほうが良いのだろう、
けれども、こちらで変換するのは面倒なので、「Uri.fromFile()」というメソッドが用意されてるので、こっちを使おうと思うわけです。






暗黙的インテントで、いろんなアプリを起動させるテスト


画像をビュワーに渡したのと同じように、テキストファイル、音楽ファイル、動画ファイルを渡せます。
SDカードのルートに、以下のファイルを適当に用意して、テストできます。

test1.txt
test2.jpg
test3.mp3
test4.mp4


「startActivity(intent);」を、
「startActivityForResult(intent, MY_INTENT);」に変更すると、受け渡しがされたか、戻り値を知ることができます。

MainActivity.java

package com.example.test26; import java.io.File; import android.net.Uri; import android.os.Bundle; import android.app.Activity; import android.content.Intent; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.LinearLayout; public class MainActivity extends Activity { static final int MY_INTENT = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //レイアウトを作ってボタンを並べる LinearLayout layout1 = new LinearLayout(this); layout1.setOrientation(LinearLayout.VERTICAL); //縦に並べる setContentView(layout1); Button button1 = new Button(this); button1.setText("BROWS"); layout1.addView(button1); //----------------------- Button button2 = new Button(this); button2.setText("MAP"); layout1.addView(button2); //----------------------- Button button3 = new Button(this); button3.setText("MARKET"); layout1.addView(button3); //----------------------- Button button4 = new Button(this); button4.setText("DIAL"); layout1.addView(button4); //----------------------- Button button5 = new Button(this); button5.setText("MAIL"); layout1.addView(button5); //----------------------- Button button6 = new Button(this); button6.setText("SEND"); layout1.addView(button6); //----------------------- Button button7 = new Button(this); button7.setText("EDIT"); layout1.addView(button7); //----------------------- Button button8 = new Button(this); button8.setText("IMAGE"); layout1.addView(button8); //----------------------- Button button9 = new Button(this); button9.setText("MUSIC"); layout1.addView(button9); //----------------------- Button button10 = new Button(this); button10.setText("MOVIE"); layout1.addView(button10); //----------------------- button1.setOnClickListener( new OnClickListener(){ @Override public void onClick(View v) { //ブラウザ Uri uri = Uri.parse("http://www115.sakura.ne.jp/~byunbyun/index.html"); Intent intent = new Intent(Intent.ACTION_VIEW,uri); startActivity(intent); } }); button2.setOnClickListener( new OnClickListener(){ @Override public void onClick(View v) { //マップ Uri uri = Uri.parse("geo:0,0?q=Japan"); Intent intent = new Intent(Intent.ACTION_VIEW,uri); try { startActivity(intent); } catch (Exception e) { //マップが無い場合 } } }); button3.setOnClickListener( new OnClickListener(){ @Override public void onClick(View v) { //マーケット Uri uri = Uri.parse("market://details?id=jp.gr.java_conf.LightMagic.Memo_Calculator"); Intent intent = new Intent(Intent.ACTION_VIEW,uri); try { startActivity(intent); } catch (Exception e) { //マーケットが無い場合 } } }); button4.setOnClickListener( new OnClickListener(){ @Override public void onClick(View v) { //ダイアル Uri uri = Uri.parse("tel:123456789"); Intent intent = new Intent(Intent.ACTION_VIEW,uri); startActivity(intent); } }); button5.setOnClickListener( new OnClickListener(){ @Override public void onClick(View v) { //メール Uri uri = Uri.parse("mailto:"); Intent intent = new Intent(Intent.ACTION_SENDTO,uri); intent.putExtra(Intent.EXTRA_SUBJECT, "ご無沙汰してます"); intent.putExtra(Intent.EXTRA_TEXT, "お世話になります。"); startActivity(intent); } }); button6.setOnClickListener( new OnClickListener(){ @Override public void onClick(View v) { //データ送信 Intent intent = new Intent(); intent.setAction(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TEXT, "らりるれろ"); startActivity(intent); } }); button7.setOnClickListener( new OnClickListener(){ @Override public void onClick(View v) { //データ表示 File file = new File("/sdcard/test1.txt"); Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), "text/plain"); startActivity(intent); } }); button8.setOnClickListener( new OnClickListener(){ @Override public void onClick(View v) { //画像を渡す File file = new File("/sdcard/test2.jpg"); Intent intent = new Intent(); intent.setAction(android.content.Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), "image/*"); startActivity(intent); } }); button9.setOnClickListener( new OnClickListener(){ @Override public void onClick(View v) { //音楽を渡す File file = new File("/sdcard/test3.mp3"); Intent intent = new Intent(); intent.setAction(android.content.Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), "audio/*"); startActivity(intent); } }); button10.setOnClickListener( new OnClickListener(){ @Override public void onClick(View v) { //動画を渡す File file = new File("/sdcard/test4.mp4"); Intent intent = new Intent(); intent.setAction(android.content.Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), "video/*"); //startActivity(intent); startActivityForResult(intent, MY_INTENT); } }); } public void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); //受け渡し結果の戻り値 if (requestCode == MY_INTENT) { if (resultCode == RESULT_OK) { //受け渡し成功 } else if (resultCode == RESULT_CANCELED) { //キャンセルされた } } } }






その他いろいろ

「intent」へのパラメータの渡し方の記述方法は奥が深いようなので、全てを網羅しきれませんが、
気がついたところだけ。


以下の記述はOKですが、

File file = new File("/sdcard/test2.jpg"); Uri uri = Uri.parse("file://"+file.getAbsolutePath()); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(uri, "image/*"); intent.putExtra(Intent.EXTRA_STREAM, uri); startActivity(intent);

以下の記述では、うまく動きません。
ファイルが見つからないようなそぶりを見せるので、パスの指定が違うのかと思ってしまいますが、それは罠です。

File file = new File("/sdcard/test2.jpg"); Uri uri = Uri.parse("file://"+file.getAbsolutePath()); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setType("image/*"); intent.putExtra(Intent.EXTRA_STREAM, uri); startActivity(intent);

「setDataAndType」を使ったほうが無難なようです。気づかないとはまります。
画像ビュワーとかの場合は、「intent.putExtra(Intent.EXTRA_STREAM, uri);」は、無くても動いてるようです。
受け取り側のアプリによっては必要になるかもしれません。

typeは、「"image/*"」などとしてますが、ファイル形式に合わせて「"image/jpeg"」とか、書くこともできます。


次のようにすると、ギャラリーが開きます。

Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("image/*"); startActivity(intent);



省略しましたが、ブラウザなら、ブラウザというカテゴリを指定したほうがいいかもしれません。

intent.addCategory(Intent.CATEGORY_BROWSABLE);






メールに貼付画像を付けて送信したい

メールに貼付画像をつけて送信する場合の記述。

File file = new File("/sdcard/test2.jpg"); Uri uri = Uri.parse("file://" + file.getAbsolutePath()); String[] mailto = new String[]{"メール@アドレス"}; Intent intent = new Intent(Intent.ACTION_SEND); //intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.putExtra(Intent.EXTRA_EMAIL, mailto); intent.putExtra(Intent.EXTRA_SUBJECT, "ご無沙汰してます"); intent.putExtra(Intent.EXTRA_TEXT, "お世話になります。"); intent.putExtra(Intent.EXTRA_STREAM,uri ); intent.setType("image/jpeg"); try { startActivity(Intent.createChooser(intent, "Choose Email Client")); } catch (android.content.ActivityNotFoundException ex) { }

「FLAG_GRANT_READ_URI_PERMISSION」は、呼び出された側のアプリに、
指定されているIntentのデータの読み取り権限を与えるフラグです。
普通のメールソフトを使うなら、無くてもいいと思います。

備考として、外部のアプリにファイルアクセスを求める場合、
受け取り側のアプリには、ファイルアクセスするための権限が必要になります。
AndroisManifest.xmlに以下のような記述が必要になります。


<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_PROVIDER"/> <uses-permission android:name="android.permission.READ_ATTACHMENT"/>




















戻る