2015年8月29日
Android端末でも、パソコンと同じように、端末内部にファイルを作って保存することができます。ところが、そのファイルをUSBケーブルでつないだパソコンから取り出そうとすると、かなりくせのある動作をする様子です。
PCからアクセス可能な場所にファイルを保存するとともに、MediaScannerという仕組みでファイルをスキャンして、MTPでアクセスできるようにして、さらに、USBケーブルを端末につなぎなおして、端末へのMTPのアクセスを最初からやり直す必要があります。
基本的な処理にもかかわらず、意外とこの方法が世間に知られていないようですので、紹介します。
Android端末では、アプリで作ったデータをファイルに保存できます。例えば、テキストエディタのようなアプリを作れば、作ったテキストファイルは、端末内のフラッシュメモリーに保存できます。
ファイルを保存する先のディレクトリは、アプリのプログラムでの指定により、以下に示すように、いくつかのデフォルトの場所から選べるようになっています。
プライベートな場所
ファイルを作成するアプリだけからアクセスできる、端末内蔵のフラッシュメモリです。この領域にファイルを保存すると、保存したアプリだけから読み出せるようになります。
このようなファイルは、PCをつないでもアクセスできないし、同じ端末の別のアプリからのアクセスも、基本的にはできないことになっています。
例えば、ソースコードに以下のように書いて取得できるファイル出力ストリームは、パソコンをつないでもアクセスできない領域に作成される様子です。
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
外部ストレージのアプリ別領域
アプリからgetExternalFilesDir()を実行すると、アプリ別に整理されたディレクトリが取得できます。ここにファイルを保存すると、外部ストレージとしての、アプリ別のファイルとなります。
「外部ストレージ」は端末により、SDカードであったり、内蔵のフラッシュメモリーだったりと、物理的な実装に違いがあります。
手持ちのNexus 7 (2012年モデル)では、外部ストレージへの保存は、端末内蔵のフラッシュメモリへの保存として扱われます。保存したファイルは、PCをUSBケーブルで端末に接続すればアクセス可能です。
PCを端末に接続すると、アプリのパッケージ名がjp.ne.sakura.sugi.test512の場合は、ファイルはWindows PCからは"PC\Nexus 7\内部ストレージ\Android\data\jp.ne.sakura.sugi.test512"に見える場所に保存されるようです。
なお、ここに保存したファイルは、アプリをアンインストールすると、道連れに削除されてしまうそうです。
外部ストレージのパブリック領域
getExternalStoragePublicDirectory()で得られるディレクトリにファイルを保存すると、外部ストレージのうち、アプリに依存しない「ダウンロード」「ピクチャー」などのディレクトリにファイルを保存できます。
こちらの領域も、端末によりSDカードであったり、端末内部のフラッシュメモリーだったりします。
Nexus 7で「ダウンロード」を指定して保存すると、ファイルは端末内蔵のフラッシュメモリに保存されます。このファイルは、PCとUSBケーブルで接続すれば、Windows PCから"PC\Nexus 7\内部ストレージ\Download"に見える場所に保存されます。
この領域に保存したファイルは、アプリをアンインストールしても消えません。ユーザが作成したコンテンツや、写真など、アプリがなくなっても残っていてほしいデータの保存に使います。
外部ストレージがSDカードなどになっている端末では、端末からファイルを保存した後で、SDカードを取り出してパソコンにセットすれば、端末で保存したファイルをパソコンで利用できます。
外部ストレージが内蔵フラッシュメモリーになっているNexus 7のような端末では、端末をUSBケーブルでパソコンにつなぐと、保存したファイルをパソコンから読み出すことができます。
パソコンと端末を接続するときは、あらかじめ端末の設定で、USBをMTPモードにしておく必要があります。
MTPモードにすると、画像データだけでなく、テキストやPDF、音声データなど、さまざまなファイルをパソコンと端末の間でやりとりできるようになります。
Android端末で、後でPCからアクセスしたいファイルを保存するときは、単にFileWriter等でファイルを書き出すだけでは不十分です。
MediaScannerという仕組みを使い、作成したファイルを、システムに「メディア」として認識させる必要があります。
AndroidはWindowsやUbuntuとは違い、ファイルを保存すれば、自然にファイルリストに現れるのではなく、保存したファイルをさらに、システムからスキャンして、外部からアクセスした場合に参照できるように設定してはじめて、パソコンからアクセスできるようになっているのです。
なぜこんなに面倒な仕組みになっているかはよく分かりませんが、仕組みがそうなっている以上、その仕組みに乗せておかないと、意図したとおりに動くアプリは作成できません。困ったことではありますが、使い方は覚えておきたいものです。
Androidで作ったファイルをメディアスキャナでスキャンするときは、次のようにします。
メディアスキャナのコールバックメソッドのインターフェースを実装します。
メディアスキャナーでファイルをスキャンするには、「接続する」「スキャンする」「接続を解除する」「スキャン結果を受け取る」の各処理を、手順をふんで実行する必要があるので、その処理に必要なインターフェースを、スキャンを行うアクティビティーなどに実装しておきます。
スキャナに接続したときの処理を実装する
コールバックメソッドである public void onMediaScannerConnected()の中身を書きます。
このメソッドは、メディアスキャナに接続ができたときに、自動的に実行されます。
メソッドの内容は、目当てのファイルをスキャンすることです。スキャナのインスタンスから、scanFile()を実行します。
スキャンの指示が終わったら、以後メディアスキャナにスキャンの指示を出すことはなくなるので、スキャナのインスタンスでdisconnect()を実行します。
スキャンが終わった後の処理を実装する
スキャンの処理が終わると、もうひとつのコールバックメソッドpublic void onScanCompleted(String path, Uri uri)が実行されます。
このメソッドでは、スキャンしたファイルのパスと、スキャンした結果を示すメディアのURIが引数として渡されます。
このURIはおそらく、別のアクティビティーや、あるいは別のアプリケーションから、保存したファイルを使いたいときに用いるのでしょう。
スキャンに失敗するとNULLが帰ってくるらしいです。
ファイルをパソコンからアクセスできるようにすることだけが目的であれば、このメソッドで何かをする必要はありません。ただし、このインターフェースを実装した場合は、このメソッドの中身を書く必要がある様子なので、何か書いておいたほうがよいでしょう。
メディアスキャナへの接続オブジェクトを作り接続する
メディアスキャナへは、MediaScannerConnectionのインスタンスを作り、そのconnect()メソッドを実行することで、接続します。
接続した後の処理は、上記で説明しましたので、接続が始まれば目当てのファイルがスキャンされ、スキャンの結果を確認できるようになります。
実際に上記の処理でソースコードを書くときは、http://techbooster.org/android/multimedia/5341/などが参考になると思います。
この、メディアスキャンを実行してはじめて、端末を次回パソコンに接続したときから、ファイルをパソコンからアクセスできるようになります。
USBケーブルでパソコンとMTPで接続中の状態で、端末を操作して、端末内にファイルを作ると、作ったファイルは、Windows 10のパソコンからはすぐには見えない様子です。
例えば、端末内でテキストファイルを作って保存しても、保存したディレクトリやファイルは、パソコンの画面からは見えません。
USBケーブルをパソコンとつないだ状態で、端末でスクリーンショットを取ると、スクリーンショットのファイル名はすぐに、パソコン側に表示されますが、新しいファイルのサイズが0になってしまっており、開いても何も表示されません。
既にパソコンに認識されているファイルを端末内で書き換えると、USBケーブルをPCから外さないでそのファイルにPCからアクセスすると、ファイルの内容が化けて見える場合もあるようです。
いずれの場合も、いったんUSBケーブルをパソコンから外し、何秒か待ってもう一度接続すると、新しくできたファイルや端末で編集したファイルに、パソコンから正しくアクセスできるようになる様子です。
端末内部でのファイルの変更が、すぐにはPCに反映されないというのは、意外と不便です。
ちなみに、OSをLinux (Ubuntu 14.04)に変更して同じことを試したところ、端末でファイルを作るとすぐに、PCから参照できることが分かりました。
しかし、Linux (Ubuntu 14.04)のMTP接続の機能がやや不完全だったせいか、しばらくアクセスを続けているうちに、Nexus 7の端末がフリーズして、勝手に再起動してしまいました。
この再起動は、強制的に全てのアプリの最適化が実行され、数十分もかかるという凶悪なものでした。
Androidでは、アプリでファイルを作り保存できる。保存する場所は、ファイルを作成したアプリだけがアクセスできる領域、外部ストレージなど、いろいろな場所から選択できる。
Android端末とPCをUSBケーブルで接続して、様々な種類のファイルをやりとりするには、MTP接続を有効にする必要がある。
Androidでは、MediaScannerConnectionを使い、作成したファイルをシステムにメディアと認識させて初めて、パソコンからアクセスできるファイルとして扱えるようになる。
Android端末をパソコンと接続したままの状態で、端末でファイルを作成・編集した場合は、パソコンからはすぐには読み出せない。パソコンからケーブルをいったん外し、再度接続すると、端末内のファイルにパソコンからアクセスできるようになる。
なんて、面倒なんでしょうね。
パソコンのアプリであれば、ファイルを保存したら、エクスプローラ等で編集したファイルをすぐに確認できることは、当たり前のことなのですが。
でも、知っていると役に立つことだと思います。
杉原俊雄のホームページ→ Androidアプリ開発メモ(もくじ)
(c) 2015 Toshio Sugihara. All rights reserved.