◆PROCESSING 逆引きリファレンス
カテゴリー:スマホ(AndroidMode)
リソースを読み込むには(AndroidMode編)
【概要】
PROCESSINGにAndroidMode を導入する事で、PROCESSINGで開発したプログラムをAndroid端末上で動かす事ができるようになります。
AndroidModeの導入については「PROCESSINGをAndroid端末で動かすには(4.0版)」記事を参照してください。
アプリケーションの動作に必要なデータを格納しておく場所には、ストレージ領域とプログラム領域があります。
ストレージ領域は、いわゆるDISK装置の事ですね。スマホなら大抵の場合はNAND型のメモリドライブになります。
アプリケーションの動作に必要なデータが、プログラムの制作段階で準備できるようなものなら、該当データをあらかじめプログラム領域に格納しておき、それをプログラム実行時に読み出して利用するのが一般的です。
そのようなデータとしては、ゲームのキャラクター画像や、パラメータ情報、定型的に表示する文章や音楽データなどが該当するのではないでしょうか?。
もちろんこれらの情報をストレージ領域から読み込むことも可能ですが、ここではプログラムの内部領域(リソースエリア)から取得する方法について紹介したいと思います。
同じプログラムの内部領域であるアセットエリアから取得する方法については、「アセットを読み込むには(AndroidMode編)」記事を参照してください。
リソースエリアやアセットエリアは、ストレージ領域とは異なる考え方でアクセスを行います。
リソースエリアとアセットエリアは、AndroidStudioで以下の場所にあります。
【詳細】
リソースエリアから読み込む
プログラムの内部領域にはリソースエリアとアセットエリアがありますが、Androidのプログラムで「より一般的」なのは、リソースエリアでしょう。
Androidの標準的なプログラムであれば、Rクラスを介してリソースエリアから様々な情報を読み込むことができます。
ですがPROCESSINGを標準エディタから利用している人は、リソースエリアから何かを読み取るのは難しいかもしれません。
なぜなら、そもそも標準エディタの機能だけでは、リソースエリアに予めファイルなどの情報を格納しておくことができないからです。
また標準エディタでは、Androidでリソースを扱う際に利用するRクラスも使うことができません。
ですのでリソースエリアから何かを読み取りたい人は、必然的にAndroidStudioなどを使って開発をする事になります。
リソースエリアに格納された情報は、Activityがもつ getResources()メソッドでResourcesオブジェクトを取得して、Resourcesオブジェクト経由で読み込むのが一般的です。
.
act : Activityインスタンス
res : Resourcesインスタンス
リソース情報にアクセスするためには、まずResourcesクラスのインスタンスを取得します。
Resourcesクラスには、リソースエリアに格納された xml ファイルから、予め設定しておいた文字列や数値を読み取る便利な命令があります。
文字列リソースを取得する
リソースエリアの values フォルダには、はじめから colors.xml、strings.xml、styles.xml の3つのファイルが用意されています。
このうち strings.xml は、一般的に文字列を格納しておく目的で利用されます。strings.xml には、デフォルトで以下のような内容が記述がされています。
1 2 3 |
<resources> <string name="app_name">sample</string> </resources> |
app_name と名前がつけられた行は、最初からある行です。sample と書かれた場所は、あなたのアプリケーション名ですので、本例とは異なる場合があります。
あらかじめリソース情報として文字列データを格納しておくためには、これを以下のように変更します。
1 2 3 4 |
<resources> <string name="app_name">sample</string> <string name="fighter_name">小次郎</string> </resources> |
上記例では、最初からある行の下に fighter_name という名前の行を追記して、「小次郎」という文字列を格納しました。
この fighter_name と名前がつけられた行に格納されている値(本例では「小次郎」)をプログラムから読み出すには、Resourcesクラスが持つ getString() メソッドを利用します。
.
res : リソースインスタンス
rid : リソースID
getStr : 取得した文字列
rid には、Rクラス経由で得られるリソースIDを指定します。
1 2 3 4 |
Activity act = getActivity(); //Activityを得る Resources res = act.getResources(); //Resourcesを得る //文字列リソースを取得する String name = res.getString(R.string.fighter_name); |
例えば上記のような感じです。これで name には「小次郎」が格納されます。
数値リソースを取得する
リソース情報として格納しておけるものは、文字列だけではありません。
今度は values フォルダの中に、values.xml という名前のファイルを作成して、あらかじめ整数値を格納しておき、それをプログラムから取得してみましょう。
実は整数を格納するために、新しいリソースファイルを作成する必要はないんです。やろうと思えば、最初からある strings.xml などに、整数として取得したい値を格納しておく事も可能です。
が・・・ファイル名が strings なのに、数値が格納されているのは違和感がありますよね。そこでわかりやすいように、「整数のリソースを格納する専用のファイル」を作る事にします。
新たにリソースファイルを作成するには、values フォルダで右クリックをして表示されるメニューから
新規→XML→値XMLファイル
と選択して New Android Component ダイアログBOXを開きます。
そしてダイアログBOXの Values File Name に好きなファイル名を記述して、完了ボタンを押します。
上記では新しいリソースファイルとして、整数を格納する目的で利用する「values.xml」ファイルを作成しました。
初期状態では以下のような中身になっている筈です。
1 2 |
<?xml version="1.0" encoding="utf-8"?> <resources></resources> |
ここに整数型のリソースを追記してみます。
1 2 3 4 |
<?xml version="1.0" encoding="utf-8"?> <resources> <integer name="fighter_hp">120</integer> </resources> |
上記例では、fighter_hp という名前の行を追記しました。
この fighter_hp と名前がつけられた行に格納されている値(本例では「120」)をプログラムから読み出すには、Resourcesクラスが持つ getInteger() メソッドを利用します。
.
res : リソースインスタンス
rid : リソースID
getVal : 取得した整数値
1 2 3 4 |
Activity act = getActivity(); //Activityを得る Resources res = act.getResources(); //Resourcesを得る //数値リソースを取得する int hp = res.getInteger(R.integer.fighter_hp); |
例えば上記のような感じです。これで hp には「120」が格納されます。
文字列配列を取得する
リソースファイルには、複数の値を同じ名前で格納しておき、配列変数として取り出す事も可能です。
今度は、strings.xml を以下のように記述してみましょう。
1 2 3 4 5 6 7 8 9 10 |
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">sample</string> <string-array name="party_member"> <item>小次郎</item> <item>武蔵</item> <item>十兵衛</item> <item>水戸黄門</item> </string-array> </resources> |
念の為、先頭行に文字コードの指定を追記しています。
そして、元々あった app_name の下に、party_member という名前で、なにやら強そうな人たち(笑)の名前を並べました。
この party_member と名前がつけられた複数の値を読み出すには、Resourcesクラスが持つ getStringArray() メソッドを利用します。
.
res : リソースインスタンス
rid : リソースID
getStrs : 取得した文字列配列
1 2 3 4 |
Activity act = getActivity(); //Activityを得る Resources res = act.getResources(); //Resourcesを得る //文字列配列リソースを取得する String[] members = res.getStringArray(R.array.party_member); |
こんな感じです。
これで menbers[0] には 小次郎、menbers[1] には武蔵・・・という感じで、順番に文字列が格納されます。
画像を取得する
それでは画像ファイルをリソースデータとして格納しておき、それをプログラムから読み取るには、どうすれば良いでしょうか?。
画像や音楽などの任意のファイルは、res フォルダの raw フォルダ配下に格納するのが一般的です。
上記例では、raw フォルダに fighter.png という名前の画像ファイルを格納しています。
この raw フォルダに格納されたファイルへアクセスするには、 Resources クラスが提供する openRawResource() メソッドを使ってファイルをOPENし、InputStream 記述子を得ます。
.
res : リソースインスタンス
rid : リソースID
is: ファイルへアクセスするための InputStream
1 |
InputStream is = res.openRawResource(R.raw.fighter); |
こんな感じです。
あとはこの InputStream を使って、OPENしたファイルを好きなように加工します。
対象となるファイルが音楽や画像データであれば、もっと簡単に、画像や音楽を扱うクラスに直接リソースIDを指定して、データを読み込ませる事も可能です。
1 2 3 4 5 6 7 |
Activity act = getActivity(); //Activityインスタンス Resources res = act.getResources(); //Resourcesインスタンス //リソースエリアから画像データを読み込む BitmapFactory.Options options = new BitmapFactory.Options(); options.inScaled = false; //密度によるサイズ変更をキャンセル Bitmap bm = BitmapFactory.decodeResource(res,R.raw.fighter, options); |
上記は、Rクラス経由で raw フォルダに格納された fighter.png ファイルを Bitmap オブジェクトに読み取る例です。
【関連記事】
- アセットを読み込むには(AndroidMode編)
- SDカードをアクセスするには(AndroidMode編)
サンプルプログラム
数値配列を読み取る例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
import android.app.Activity; import android.content.res.Resources; import processing.core.PApplet; /** * PROCESSING Resource 整数配列読み取り Sample * @author MSLABO * @version 1.0 2018/7 */ public class Sketch extends PApplet { @Override public void settings() { fullScreen(); } int[] param; float fontSize; @Override public void setup() { //文字設定 fontSize = 16 * displayDensity; textSize(fontSize); textAlign(LEFT, TOP); fill(0); Activity act = getActivity(); //Activityインスタンス Resources res = act.getResources(); //Resourcesインスタンス //リソースエリアから整数配列を取得する param = res.getIntArray(R.array.chara_status); } @Override public void draw(){ background(255); //読み取った整数データを画面に表示する int y = 0; for(int data : param){ text(data, 0, y); y += fontSize; } } } |
詳細のところでは文字列配列を読み取る例を紹介しましたが、このサンプルは整数配列を読み取る例となっいています。
res フォルダの values フォルダ配下に values.xml ファイルを作成し、その中身に以下が記述してある前提となります。
1 2 3 4 5 6 7 8 9 |
<?xml version="1.0" encoding="utf-8"?> <resources> <integer-array name="chara_status"> <item>200</item> <item>150</item> <item>30</item> <item>45</item> </integer-array> </resources> |
画像を読み取る例1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
import android.app.Activity; import android.content.res.Resources; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import processing.core.PApplet; /** * PROCESSING リソースファイル COPY処理 Sample * @author MSLABO * @version 1.0 2018/7 */ public class Sketch extends PApplet { @Override public void settings() { fullScreen(); } @Override public void setup() { //リソースファイルを内部ストレージ領域にCOPYする CopyAssetFile(R.raw.fighter, "outImage.png"); } @Override public void draw() { background(255); } /** * File Copy処理 * * @param rid リソースID * @param outFileName 出力ファイル名 * @return true:正常 false:異常 */ boolean CopyAssetFile(int rid, String outFileName) { Activity act = getActivity(); //Activityインスタンス Resources res = act.getResources(); //Resourcesインスタンス //コピー先フォルダが存在しない場合は作成する File fs = new File(dataPath("")); if (!fs.exists()) { fs.mkdirs(); } //コピー処理 InputStream is = null; BufferedInputStream bis = null; FileOutputStream os = null; BufferedOutputStream bos = null; try { //リソースからイメージファイルを取得する is = res.openRawResource(R.raw.fighter); bis = new BufferedInputStream(is); //書き込み用STREAMを準備する os = new FileOutputStream(new File( fs.getPath() + File.separator + outFileName)); bos = new BufferedOutputStream(os); //COPYする byte[] buffer = new byte[1024]; while (bis.read(buffer) != -1) { bos.write(buffer); } bos.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); return false; } catch (IOException e) { e.printStackTrace(); return false; } finally { //後始末 try { if (is != null) is.close(); if (bis != null) bis.close(); if (os != null) os.close(); if (bos != null) bos.close(); } catch (IOException e) { e.printStackTrace(); return false; } } return true; } } |
res フォルダの raw フォルダ配下に格納されている fighter.png という名前の画像ファイルを読み取り、ストレージの内部領域に複写します。
注意としては、上記サンプルをAndroid6.0以降で試す場合は、自アプリケーション領域へのCOPYでしか、正しく動作しないという事です。
Android6.0以降で自アプリケーションの領域外にCOPYする場合は、特別な処理を加える必要があります。詳しくは「SDカードをアクセスするには(AndroidMode編)」を参照してください。
画像を読み取る例2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
import android.app.Activity; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import processing.core.PApplet; import processing.core.PImage; /** * PROCESSING Resource画像読み取り Sample * @author MSLABO * @version 1.0 2018/7 */ public class Sketch extends PApplet { @Override public void settings() { fullScreen(); } PImage fighter; //画像 @Override public void setup() { Activity act = getActivity(); //Activityインスタンス Resources res = act.getResources(); //Resourcesインスタンス //リソースエリアから画像データを読み込む BitmapFactory.Options options = new BitmapFactory.Options(); options.inScaled = false; //密度によるサイズ変更をキャンセル Bitmap bm = BitmapFactory.decodeResource(res,R.raw.fighter, options); //BitmapをPImageに変換する fighter = changeBitmapImage(bm); } //BitMapをPImageに変換する処理 PImage changeBitmapImage(Bitmap bm){ int bitHeight = bm.getHeight(); int bitWidth = bm.getWidth(); //元画像と同じ大きさの空PImageを用意する PImage retImage; retImage = createImage(bitWidth, bitHeight, ARGB); //元画像の画素をすべてPImageに複写する retImage.loadPixels(); bm.getPixels(retImage.pixels, 0, bitWidth, 0, 0, bitWidth, bitHeight); retImage.updatePixels(); return retImage; } @Override public void draw(){ background(255); image(fighter,0,0); } } |
res フォルダの raw フォルダ配下に格納されている fighter.png という名前の画像ファイルを読み取り、画面に表示します。
PROCESSINGは AndroidのBitmapクラスに格納した画像を直接表示できないので、PROCESSING専用の PImage クラスに変換して表示しています。
<出力サンプル>
(画像URL:illust-AC 様:Kamesan さん)
本ページで利用しているアイコン画像は、下記サイト様より拝借しております。各画像の著作権は、それぞれのサイト様および作者にあります。