2011年9月19日月曜日

java.lang.OutOfMemoryError: bitmap size exceeds VM budget の続き【android】【画像表示】【エラー】

前回の続きです。前回↓
⇒java.lang.OutOfMemoryError: bitmap size exceeds VM budgetandroid】【画像表示】【エラー】

Activityの状態遷移(ライフサイクル)というのは、いったいどのようなものなのでしょうか。
世のサンプルソースにはonCreateメソッドのメソッドばかり実装したものが多く、
他のメソッドはどのように実装すればよいのでしょうか。

そのヒントになるのが、@IT様の下記の記事です。
⇒Androidアプリ作成の基本“Activity”とは何か?

下記のイメージ図は上記サイトの転載です。
























onCreateメソッドを実行することで、基本的に実行中までアプリの状態が遷移することから、
通常のアプリでは、onStartメソッドやonRestartメソッドは実装しなくてよさそうです。
※私自身探り探り調べながらやっていますので、何か情報持っている方は共有していただければ幸いです。


下記の場合、onPauseメソッドやonStopメソッド、onDestroyメソッドが呼ばれそうなので、
そのタイミングで、不要なデータをクリアする処理を入れるとリソースを有効的に使えそうです。

【onPauseメソッドやonStopメソッド、onDestroyメソッドが呼ばれそうなタイミング】
 ・アプリケーションを終了
 ・画面の向きを変えることでの再表示
 ・戻るボタン
 ・次の画面に遷移



何か情報が入れば追記します。

2011年9月10日土曜日

java.lang.OutOfMemoryError: bitmap size exceeds VM budget【android】【画像表示】【エラー】

下記にこの記事の内容に関連する記事があります。ご参考ください。
⇒画像を画面サイズに合わせる(縮尺・縮小する)



カメラで撮影した画像のような高画質な画像を表示すると、たびたび下記のような
メッセージが出力され、アプリケーションが強制終了してしまいます。


09-10 06:27:57.701: ERROR/dalvikvm-heap(2168): 7680000-byte external allocation too large for this process.
09-10 06:27:57.701: ERROR/GraphicsJNI(2168): VM won't let us allocate 7680000 bytes
09-10 06:27:57.712: DEBUG/skia(2168): --- decoder->decode returned false
09-10 06:27:57.732: DEBUG/AndroidRuntime(2168): Shutting down VM
09-10 06:27:57.732: WARN/dalvikvm(2168): threadid=1: thread exiting with uncaught exception (group=0x4001d800)
09-10 06:27:57.941: ERROR/AndroidRuntime(2168): FATAL EXCEPTION: main
09-10 06:27:57.941: ERROR/AndroidRuntime(2168): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
09-10 06:27:57.941: ERROR/AndroidRuntime(2168): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
09-10 06:27:57.941: ERROR/AndroidRuntime(2168): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:459)
09-10 06:27:57.941: ERROR/AndroidRuntime(2168): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:271)

※EclipseのDDMSのLogCatにLogは表示されています。


この場合の対処方法として、下記のようなものがあげられます。
 ・Bitmap.Configの設定をARGB_8888をやめて、RGB_565やARGB_4444を使用する(デフォルトRGB_565)
  これらは解像度の設定。
 ・inSampleSizeを設定し、画像ファイルのサイズを小さくして表示する。

  BitmapFactory.Options bmfOptions = new BitmapFactory.Options();
  bmfOptions.inSampleSize = 4;

  とすると、1辺4分の1のサイズとなり、面積は16分の1。

 ・システムメモリ上に再利用性の無いオブジェクトがある場合に勝手に解放するように設定する。
  bmfOptions.inPurgeable = true;

 ・ビットマップのサイズを現在の表示メトリクスに合わせる。
  DisplayMetrics dm = this.getResources().getDisplayMetrics();
  bmfOptions.inDensity = dm.densityDpi;

 ・使わなくなったタイミングでBitmapデータの解放を行う。
  Bitmap.recycle();
  ※Bitmap変数をクラス変数として持ち、onPause()メソッドでBitmap.recycle();
   とすればよいですが、System.gc()でよい気もします。

 ・ガーベッジコレクションを行う。
  System.gc();


ざっとこんなところですが、Bitmap.recycle()は使用したことがないので、情報いただければ幸いです。



私は今のところ下記のような対処を行い、OutOfMemoryErrorを防いでいます。
(不要な処理もありかもしれません)

①ビットマップ設定メソッドで、BitmapFactory.Optionsの設定を行う。
    /**
* ディレクトリリストに表示するBitmapを設定する。
* @param File file(設定するBitmapファイル)
* @return Bitmap bmImage(設定されたBitmap)
* @exception なし
*/

private Bitmap setBitmap(File file){

// ビットマップ作成オブジェクトの設定
BitmapFactory.Options bmfOptions = new BitmapFactory.Options();
// ARGBでそれぞれ0~127段階の色を使用(メモリ対策)
bmfOptions.inPreferredConfig = Config.ARGB_4444;
// 画像を1/20サイズに縮小(メモリ対策)
bmfOptions.inSampleSize = 20;
// システムメモリ上に再利用性の無いオブジェクトがある場合に勝手に解放(メモリ対策)
bmfOptions.inPurgeable = true;
// 現在の表示メトリクスの取得
DisplayMetrics dm = this.getResources().getDisplayMetrics();
// ビットマップのサイズを現在の表示メトリクスに合わせる(メモリ対策)
bmfOptions.inDensity = dm.densityDpi;
// 画像ファイルオブジェクトとビットマップ作成オブジェクトから、ビットマップオブジェクト作成
Bitmap bmImage = BitmapFactory.decodeFile(file.getPath(),bmfOptions);

return bmImage;
}

 

②アプリケーション終了時(戻るボタン押下時など)にSystem.gc();を行う。
 ※次回、Activityのライフサイクルも含めて説明します。



日本Androidの会がOutOfMemoryErrorについて纏めてくださっております。
http://mtnk.org/down/PDF/OutOfMemoryError.pdf

2011年9月5日月曜日

ListViewの一行をクリックし、別の画面に遷移【android】【ListView】【画面遷移】

ListViewの一行をクリックし、別の画面に遷移する場合には、
onListItemClick()をオーバーライドします。
※別の方法もあるようですが、この方法が比較的綺麗にコーディングできそうです。

オーバーライドしたonListItemClick()の中で、intentインスタンスを作成し、
startActivity()を実行します。
Intent intent = new Intent(遷移元のクラス.this, 遷移先のクラス.class);
と作成してください。

Intent.putExtra()を使用することにより、値の受け渡しも可能です。

    /**

* クリックされたListに対して、ImageListViewに遷移する。
* (非 Javadoc)
* @see android.widget.AdapterView$OnItemClickListener#onItemClick(android.widget.AdapterView, android.view.View, int, long)
* @param AdapterView parent(未使用)
* @param View view(未使用)
* @param int position(クリックされたポジション)
* @param long id(未使用)
* @return void
* @exception なし
*/

@Override
public void onListItemClick(ListView listView, View v, int position,long id) {
super.onListItemClick(listView, v, position, id);

String dir = dirList.get(position);
Log.v("onClick", String.format("onListItemClick: %s", dir));

// ディレクトリリストからクリックされたディレクトリを取得
String imageDirPath = dirList.get(position);
// ImageListViewクラスに、ディレクトリを渡す為のIntentを作成
Intent intent = new Intent(DirListView.this, ImageGridView.class);
// Intentにクリックされたディレクトリを設定
intent.putExtra("IMAGE_DIR_PATH", imageDirPath);
// ImageListViewに遷移
startActivity(intent);
}

2011年9月4日日曜日

別パッケージのActivityに遷移【android】【画面遷移】【エラー】

前回の続きです。前回↓

⇒android.content.ActivityNotFoundException

別Activityに遷移する際、前回記載した
        </activity>

<activity android:name="ImageListView"></activity>


では同様のエラーとなり、Activityを見つけることができず、エラーとなってしまいます。
これは、AndroidManifest.xmlの 「「package="」は1つしか記述できないようですので、2つ目からはパッケージ込みで記述する必要があります。


上記をまとめると下記となります。

【現象】
別パッケージのActivityに遷移しようとするとエラーになる。

【LogCat】
…android.content.ActivityNotFoundException: Unable to find explicit activity class
※デバイス上でのログは、EclipseのDDMSのLogCatに表示されます。

【原因】
AndroidManifest.xmlに遷移先のアクティビティをパッケージ込みで記述していない為、
AndroidManifest.xmlに遷移先のアクティビティが設定されていないと判断されている。

【解決策】
AndroidManifest.xmlに遷移先のアクティビティを設定する。
<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="jp.co.vacaposi.android.iv.iv.iv0010"
android:versionCode="1"
android:versionName="1.0">

<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".DirListView"
android:label="@string/app_name">

<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="jp.co.vacaposi.android.iv.iv.iv0020.ImageGridView"></activity>
</application>
<uses-sdk android:minSdkVersion="7" />
</manifest>

android.content.ActivityNotFoundException【android】【画面遷移】【エラー】

この投稿の続きがあります↓

⇒別パッケージのActivityに遷移【android】【画面遷移】【エラー】


デバイス上でのログは、EclipseのDDMSのLogCatに表示されます。

【現象】
画面遷移時に「…has stopped unexpectiedly. Please try again.」というダイアログが表示され、
アプリケーションが終了してしまう。

【LogCat】
…android.content.ActivityNotFoundException: Unable to find explicit activity class 
※デバイス上でのログは、EclipseのDDMSのLogCatに表示されます。

【原因】
AndroidManifest.xmlに遷移先のアクティビティが設定されていない。

【解決策】
AndroidManifest.xmlに遷移先のアクティビティを設定する。



        </activity>

<activity android:name="ImageListView"></activity>