2011年11月28日月曜日

String.xmlの内容をString型でjavaで扱う【android】【String.xml】【多言語化】

すでにあるvaluesフォルダと同じ階層にvalues-jaを作成し、同じXMLファイルを置いてやることで、
日本語専用のXMLファイルを用意することができ、本体の言語設定に応じて、どちらのXMLファイル
を使用するか選択させることができます。

このような仕組みをandroidでは「多言語化」と呼んでいますが、このような多言語化を行った際に
String.xmlの内容をString型で取得したい。とすぐになります。

一般的なString.xmlファイルからの値の取得方法は、下記のようになりますが、これでは、R.java
に記載されている「id」しか取得できません。

R.string.select_dir
※select_dirはString.xmlに定義されているものとします。

この解決方法として、android.content.Context.getStringメソッドを使用する方法があります。

String str = getString(R.string.select_dir);

としてやることで、String型でString.xmlファイルから値の取得ができます。


この方法は、Activity内では上記のように使用することができますが、共通部品のような、他の
クラスではContextが見つけられない事から、getStringメソッドが見つけられないため、使用
することができません。その場合のひとつの解決方法として、共通部品の引数にContextを増やし、
引数で、thisを渡してあげることで、解決することができます。

2011年11月20日日曜日

画像を画面サイズに合わせる(縮尺・縮小する)の続き【android】【画像表示】【エラー】

以前の投稿の続きです。↓
⇒画像を画面サイズに合わせる(縮尺・縮小する)【android】【画像表示】【エラー】

以前、紹介した画像を画面サイズに合わせる方法ですが、いざ、自分で使ってみると
GC(ガーベッジコレクション)が画像毎に発生して、処理が非常に遅いという問題
が発生しました。
※画像表示処理もそこそこに遅いのに、GCがさらに悪化させているようでした。

なんとかGCの発生を抑制したくいろいろ調べた結果、Bitmap作成処理を下記のように
書き換えることで、GCの発生を抑え、処理時間を短くすることができました。

以前の方法では、画像をそのままBitmapに読み込んでから縮尺していたようで、
メモリにごみができやすいという問題があったようです。
今回は画像のサイズをあらかじめ読み込んでおき、画像の読み込みのタイミングで
縮尺しているので、メモリを無駄なく使用することができます。

あと、不本意ではあるのですが、androidでは短命なオブジェクトや変数を生成しない
ようにしたほうがパフォーマンスがあがるという情報を得て、できるだけクラス変数
で、変数を宣言するようにしています。
※ほかにも下記のようなパフォーマンス対策がありました。
  ・setterやgetterは使用しない。
  ・オブジェクトを作成しない(コードはベタ書きすべき)。
  ・処理が遅くなっても問題ない箇所でGCするようにする。
  ・定数はfinalで宣言する。

ただし、そのままこの情報を受け取ってコーディングをすると、非常に見づらい
コードとなってしまいそうなので何か対策を立てる必要がありそうです。


    //setBitmap変数
Bitmap bmImage;
int zoomWidth;
int zoomHeight;

/**
* ディレクトリリストに表示するBitmapを設定する。
* @param File file(設定するBitmapファイル)
* @return Bitmap bmImage(設定されたBitmap)
* @exception なし
*/

public Bitmap setBitmap(File file){
// ビットマップ作成オブジェクトの設定
BitmapFactory.Options bmfOptions = new BitmapFactory.Options();
// RGBでそれぞれ 5/6/5 ビットの色を使用(メモリ対策)
bmfOptions.inPreferredConfig = Config.RGB_565;
// アプリケーション内でのピクセル密度を設定
bmfOptions.inScreenDensity = DisplayMetrics.DENSITY_LOW;
// 画像の大きさだけ取得
bmfOptions.inJustDecodeBounds = true;
bmImage = BitmapFactory.decodeFile(file.getPath(),bmfOptions);

// 画面のサイズの1/4で画像を縮尺するよう、縮尺率を設定
if (displayMetrics != null) {
zoomWidth = (int)Math.floor(bmfOptions.outWidth / (displayMetrics.widthPixels / REDUCTION_SIZE));
zoomHeight = (int)Math.floor(bmfOptions.outHeight / (displayMetrics.heightPixels / REDUCTION_SIZE));
bmfOptions.inSampleSize = Math.max(zoomWidth, zoomHeight);
}
// 画像そのものを設定された縮尺率で取得
bmfOptions.inJustDecodeBounds = false;
bmImage = BitmapFactory.decodeFile(file.getPath(),bmfOptions);

return bmImage;
}
}

2011年11月7日月曜日

画像を画面サイズに合わせる(縮尺・縮小する)【android】【画像表示】【エラー】

以前の投稿の続きです。↓
⇒java.lang.OutOfMemoryError: bitmap size exceeds VM budget【android】【画像表示】【エラー】 の続き


画像の表示について追記します。

以前、画像の縮小について下記の方法を書きましたが、

// 画像を1/20サイズに縮小(メモリ対策)
bmfOptions.inSampleSize = 20;


実際、表示されるすべての画像を均一に縮小するやり方はよくないということで、
画面の表示サイズを取得し、そこから必要に応じて縮小するやり方を紹介します。
以前紹介した、etBitmap(File file)を下記に変更してみました。
改善点等ございましたら、ご教授くださいませ。

    public Bitmap setBitmap(File file){
// ビットマップ作成オブジェクトの設定
BitmapFactory.Options bmfOptions = new BitmapFactory.Options();
// RGBでそれぞれ 5/6/5 ビットの色を使用(メモリ対策)
bmfOptions.inPreferredConfig = Config.RGB_565;
// GridViewの要素が横に3つ並ぶ想定で、余白も考慮し、画像の縮尺サイズを1/4に設定
// 画面のサイズに縮尺した後に、1/4にさらに縮尺
int reductionSize = Const.COLUMN_IMAGE_GRID_VIEW + 1;

if (metrics == null) {
// 現在の表示メトリクスの取得
DisplayMetrics dm = this.getResources().getDisplayMetrics();
// ビットマップのサイズを現在の表示メトリクスに合わせる(メモリ対策)
bmfOptions.inDensity = dm.densityDpi;
}
// システムメモリ上に再利用性の無いオブジェクトがある場合に勝手に解放(メモリ対策)
bmfOptions.inPurgeable = true;
// システム側で設定されているピクセル密度を無視して設定値を元に画像がスケール
bmfOptions.inScreenDensity = DisplayMetrics.DENSITY_LOW;

// 画像ファイルオブジェクトとビットマップ作成オブジェクトから、ビットマップオブジェクト作成
Bitmap bmImage = BitmapFactory.decodeFile(file.getPath(),bmfOptions);

if (metrics != null) {
float imageWidth = (float)bmImage.getWidth() / (float)metrics.widthPixels;
float imageHeight = (float)bmImage.getHeight() / (float)metrics.heightPixels;
float imageScale = Math.max(imageWidth, imageHeight);
if (imageScale > (1 / reductionSize)){
int newImageWidth = (int)((bmImage.getWidth() / imageScale) / reductionSize);
int newImageHeight = (int)((bmImage.getHeight() / imageScale) / reductionSize);
bmImage = Bitmap.createScaledBitmap(bmImage,newImageWidth,newImageHeight,false);
}else{
bmImage = Bitmap.createScaledBitmap(bmImage,bmImage.getWidth(),bmImage.getHeight(),false);
}
}
return bmImage;
}




【クラス変数宣言】
private DisplayMetrics metrics;


【onCreateメソッドで】
metrics = new DisplayMetrics();
display.getMetrics(metrics);




と、こんな感じです。
Const.COLUMN_IMAGE_GRID_VIEWは画面に表示している画像の列数です。
私のアプリでは、画像が3列表示されているので、余白も考え、
画面のサイズ/4 のサイズに縮小しています。
画面いっぱいいっぱいのサイズなら、reductionSizeを1にするとよいでしょう。

如何でしょうか?やっつけで作ったので、ちょっと不安ですが、
一応、今のところ、元気に動いているようですw