Androidのレイアウトで苦労しない為に – 重要なのはdpiとdp

レイアウトについて知識不足だった為、困ったことがありました。
Android2.3でのお話です。

最近、解像度が960*540のいわゆるHD端末がありますよね。
アスペクト比は現在主流の854*480とほぼ同じです。
どちらもhdpiです。

この2種類の端末で同じように表示されるレイアウトを作る必要がありました。
アスペクト比が同じですので一つのレイアウトでいけるじゃん!
と思いながらレイアウトエディタでAndroidの推奨する単位であるdpでレイアウトしました。
レイアウトした時のプレビュー画面は854*480の設定です。

完成したので表示すると…960*540でちょっと小さい!

dpを理解していれば当たり前でしょ、と言われるところです。

dpiが同じ場合、実際に表示されるピクセル数は同じです。
例えば10dpをhdpiで表示する時は10 * 1.5 = 15pxとなります。
なので、960*540・854*480どちらの端末でも15pxで表示されちゃうんです。

dpで吸収できないこの問題。
どうやって対応します?
レイアウトを2つ作る・dpを指定しているもの全てを表示前に拡大縮小処理(値の調整)する、のどちらかだと思います。

前者は対象が限定されていれば問題ないですが、どんな端末でも対応とはいきません。
また、レイアウトを出し分ける仕組みもうまく働かない為、自前でsetContentViewへ与えるレイアウトIDを出し分ける処理を書く必要があります。

後者はどんな端末でも対応できるとは思いますが、専用の処理を書く必要があります。
(専用の処理は結構めんどくさそう&重そう…)

前者の方法で今回は対応したのですが、Android環境はカオスすぎますね…
dpとはなんだったのでしょう。
どんな端末でも同じ大きさで表示してくれる単位だと思ってましたよ、googleさん…

最近のAndroid巡回まとめ – 開発環境構築からゲームエンジンまで色々

Androidについてgoogleさんで検索してオッ、と思ったものをまとめました。

マンガで分かるAndroid開発環境構築方法 – Android Dev – CroCro
胡散くさい教師(ナルシストだろこれ)が、かわいい女の子にAndroidの開発環境構築方法を教えるマンガがあります。
マンガの出来にはノーコメントとして、環境構築についての解説は親切でわかりやすいのでオススメです。

Android開発環境の構築 Eclipse編
このサイト見ながら、会社のPCにAndroid開発環境導入してみました。
開発環境は、いれたときにちゃんと入れ方をメモっとかないとダメですねw(一回キリのことなので大体忘れてしまう)

ひとつ、AndroidSDK導入時にJDKが認識されない不具合があって手間取ったのでそこの解決法が載っているページも貼っておきます。
Android SDKのインストールでJDK not found. – Smart&Social会議室
戻って進むでうまくいくなんてどうかしてるよ…w

AndroidでJNIを使う方法 – Android(アンドロイド)情報-ブリリアントサービス
Android JNI: NativeからのJavaメソッドの呼び出し–日本語のドキュメント–Google Android 論壇
Android C言語を触る(JNI, NDK など基礎知識)|世界的日曜WEBプログラマー日記
JNI関連、詳しくは見てなかったり。
Androidのプログラミングでは高速化が重要なので、今後はJNI使う方法を覚えていきたいですねー。

e3roid – 2D OpenGL game engine for Android – Google Project Hosting
日本の方が作られている2Dゲームエンジンです。
動画を見ると何が出来るかわかりますね。
ゲーム作りたい! と思っている方は利用してみてはいかがでしょう。

AIRNovel
Androidでノベルゲームのゲームエンジン作れば儲かるんじゃないか? と思って検索したら既にありましたw
でもこれはAdobe AIRで動くとのことなので、形としてはFlashみたいですね。

throw Life – Dalvik VMのGarbage Collection概要
Android内の仮想マシン「Dalvik VM」のガベージコレクションの詳しいお話。
短寿命なオブジェクトを生成しまくってるとGC走りまくるよ、というお話でした。

個人でau one Marketでアプリを販売する方法

au one Market。
このマーケットでは、決済方法で携帯料金引き落としに合わせて支払う形(かんたん決済)を選ぶ事が出来ます。
これによりクレジットカードを持っていないユーザの方々に課金してもらえる可能性があります。

Android Market、au one Market、どちらも登録するっきゃない!
と思ったのですが、auのサイトを見ると…

>なお、au one Marketのお申し込みは法人さまに限定させていただいておりますので、ご了承ください。
引用元:Android™向けアプリケーション開発者さま用技術情報 | au by KDDI

法人限定…

個人で気軽に登録は出来ないということですね。
でも何とか個人でも登録したい…ネットを検索してみるとひとつの方法が見つかりました。

アンドロイダー「au one Market」登録販売代行について | Android(アンドロイド)アプリの人力レビューサイト【アンドロイダー】
アンドロイダーさんが、登録を代行してくれるとのことです。
詳細は上記リンク参照で。

以上です。
個人でau one Marketに登録したい! でもどうすれば…と悩んでいる方のお役に立てたらと思い書きました。

Androidアプリでのデータ保存方法

Androidアプリでデータの読み込み・保存を行う場合、以下の3つの方法があります。

・Preferenceを使う
・ローカルフォルダを使う
・SQLiteを使う

どんなデータを扱うかで使い分ける形になると思います。
読み込み・保存ともに簡単なので、単純な値の保存であればPreferenceがオススメ。

以下詳細。
Read the rest of this entry »

ウィジェットで独自フォントを頑張って使う方法

ネットの情報をかき集めてAndroidプログラミングしています、ぐるぽです。

ウィジェットで常駐する時計アプリを制作していました。
そこで、通常のフォントではなく独自のフォントを使おうとしていたのですが、ウィジェットを調べていくと普通の方法では使えない事が判明…
(ウィジェットのアイテムのフォント指定部分には最初から用意されている3つのフォントしか選べない)

どうにかフォント利用できないかと調べていたら、

1.フォントをCanvasに描画
2.画像として保存
3・ウィジェットで画像表示

という方法を見つけました。

私の制作したアプリでは、設定画面(PreferenceActivity)でサイズと色を変更>設定画面終了時に画像生成 としました。

キモである設定画面のコード(必要な部分以外はカットしています)

/**
 * 設定画面
 * @author ぐるぽ
 */
public class SettingMenuActivity extends PreferenceActivity {

	@Override
	protected void onDestroy() {
		super.onDestroy();

		// 指定された設定で画像を生成してローカルフォルダに保存
		for (int i = 0; i < TokikakeClockWidgetProvider.IMG_NAMES.length; i++) {
			Bitmap bmp = createCharacterBitmap(
					TokikakeClockWidgetProvider.IMG_NAMES[i], size);
			saveBitmapToPng(String.valueOf(i), bmp);
		}
	}

	/**
	 * 指定された文字・フォントサイズで画像を生成する
	 * @param chara 文字
	 * @param size フォントサイズ
	 * @return Bitmap形式の画像
	 */
	private Bitmap createCharacterBitmap(char chara, int size) {
		// フォントを指定
		Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		paint.setTypeface(Typeface.createFromAsset(getAssets(), "timeleap100.ttf"));
		paint.setTextSize(size);

		// フォントサイズに合った大きさの画像を生成する
		FontMetrics fm = paint.getFontMetrics();
		int height = (int) (fm.bottom - fm.top);

		float[] widths = new float[1];
		paint.getTextWidths(String.valueOf(chara), widths);
		int width = (int) widths[0];

		Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
		Canvas canvas = new Canvas(bmp);
		canvas.drawColor(Color.argb(0, 0, 0, 0));

		canvas.drawText(String.valueOf(chara), 0.0f, -fm.ascent, paint);

		return bmp;
	}

	/**
	 * BitmapをローカルフォルダにPNG形式で保存する
	 * @param fileName ファイル名
	 * @param bmp Bitmap形式の画像
	 */
	private void saveBitmapToPng(String fileName, Bitmap bmp) {
		try {
			OutputStream out = openFileOutput(fileName + ".png",MODE_PRIVATE);
			bmp.compress(CompressFormat.PNG, 100, out);
			out.flush();
			out.close();
			Log.i("list", fileName + ".png" + " create success!");
		} catch (IOException e) {
			e.printStackTrace();
			Log.i("list", fileName + ".png" + " can't create");
		}
	}
}

・PreferenceActivityのonDestroy()
設定画面を閉じた時に画像を生成したいので、PreferenceActivityのonDestroy()内で画像生成処理を呼び出します。

・createCharacterBitmap()
ここで独自フォントの画像をBitmap形式で生成しています。
(フォントを関数内で指定していますが、引数に与える形の方がいいですね…)
独自フォントはAssetsフォルダに置いています。

・saveBitmapToPng()
生成した画像をpng形式でアプリのローカルフォルダに保存します。
ローカルフォルダの読み込み・保存は簡単なので便利^^

ローカルフォルダ読込:InputStream is = context.openFileInput(“ファイル名”);
ローカルフォルダ保存:OutputStream out = context.openFileOutput(“ファイル名”,モード);

以上です。
Assetsフォルダとローカルフォルダを利用すれば、結構なんでもいけそうですね。

dpiとdip

Android端末の様々な大きさの画面に対応する為に、アプリの設定ではpxではなくdipという単位を使います。

dip。
Density Independent Pixel。
この値を使うと、端末のdpiによってサイズが切り替わります。
dpiによってサイズが変わることで、ボタンやテキストなどの画面上でのサイズを統一することができます。
(pxで直接指定してしまうと、dpiの低い端末では大きく、高い端末では小さくなってしまいます。)

端末のdpiの分類
・xhdpi(320dpi) ※2.3から
・hdpi(240dpi)
・mdpi(160dpi)
・ldpi(120dpi)

mdpi(160dpi)の時、1dip = 1pxとなります。

画像を扱う場合は、drawableフォルダに各dpiに合わせた画像を置いておけば、dpiによって読み込む画像が変わります。
(drawable-mdpiフォルダにいれておけば、mdpiの端末で読み込まれる)

dpiごとに画像を用意しなかった場合は、他dpiに用意した画像を拡大・縮小して表示する形になります。
(drawable-mdpiフォルダに画像を置いた状態で、hdpi端末から動かすと画像が拡大されて表示される)

dpiごとの倍率
・xhdpi:2 ※2.3から
・hdpi:1.5
・mdpi:1
・ldpi:0.75

拡大・縮小で画像が汚くなってしまうのを防ぐ場合には、dpiごとの倍率をかけたサイズの画像を用意しましょう。

以上。

Androidのレイアウトで画面いっぱいに表示したい時の設定

画面いっぱいに表示させる方法。

表示させたいアイテムのプロパティの

・Layout height
・Layout width

を「fill_parent」にすることで画面いっぱいに表示させることが出来ます。

ただ、この方法では複数のアイテムが並んでいる形の場合にうまくいきません。

LinearLayout
-Button
-TextView
-Button

と縦に並んでいる形のときに真ん中のTextViewを画面いっぱい表示させたいと考えます。

・TextViewのLayout heightを「fill_parent」にした場合
下のボタンが表示されていない

画面いっぱいに表示できてはいるのですが、下のButtonの表示スペースが無くなってしまっています。

解決方法。
TextViewのLayout weightプロパティの値を「1」にする事で解決できました。

・TextViewのLayout weightを「1」にした場合
下のボタンも表示される

Layout weightは余白がある場合に、どの程度利用するかの重みを設定します。
(複数のアイテムに同じ値を設定した場合、余白を均等に利用する形になり、差をつけた場合は大きい値のアイテムが余白を多く利用する形になります。)
未設定の状態は値が「0」、余白を利用しない設定です。

ウィジェット開発のデバッグ時はブレークポイントで止まらない?!

ウィジェットの開発に興味を持って、二日前ぐらいから情報を集めています。
動作確認の為にサンプルコードを書いたもののうまく動かず…

そこでどこまで動いているか確認する為にブレークポイント置いてデバッグしようとしました。
しかし、どこにおいてもブレークポイントで止まらず…

Activity開発の時は問題なく止まったので不思議に思い、検索。

こんなページがありました。

ブレークポイントでとまらない – 日本Androidの会 | Google Groups

私の探し求める情報ど真ん中でした^^
サービスの場合、onCreate()内に下記のメソッドをいれないと止まらないようです。

android.os.Debug.waitForDebugger();

onCreate()内じゃなくとも、ブレークしたいところの前にいれれば止まりそうですが、生成時が確実か。