記事一覧

onKeyDown --> get KEYCODE_BACK no longer works

Android API changes very quickly.
Searching on the web about how to override the functionality of device's back button you'll find the code like this:


@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ( keyCode == KeyEvent.KEYCODE_BACK ) {
// do something;
}
return true;
}

But this seems no longer work on Android 2.x
I followed a suggestion found on the web to have done like this instead.

@Override
public void onBackButton(){
// do something;
}

You'd better watch out when googl'ing because lots of obsolete information will come upwards in search results because they are not old enough to be hidden by new information.


Android APIの変化は早いですね。
さっき端末の戻るボタンを乗っ取る方法を調べてたんですが、多くのページが


@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ( keyCode == KeyEvent.KEYCODE_BACK ) {
// do something;
}
return true;
}

という感じのコードを載せてる。でもこれって 2.x では動かないらしい。もうちょい調べて出てきたこういうコードで動きました。

@Override
public void onBackButton(){
// do something;
}

Web上では、1.x系の情報もまだ十分に「古くなりきってない」感じなので、けっこう検索の上位に出てきてしまいます。
この手の話をググるときは気をつけた方が良さそうですね。

Catching MotionEvent.ACTION_MOVE / UP

In my current Android app I have several customized views that inherit View Class.
Each of them overrides onTouchEvent and tracks touch movements.
But one of them cannot catch MotionEvent.ACTION_MOVE and UP, while others can.

I did about one hour of try & errors to find that, if you return false for onTouchEvent's return value when you caught MotionEvent.ACTION_DOWN, tracking of touch event finishes and is no longer performed until your next touch.
I modified my code to return true when needed and it worked.

It may mean "You returned false? OK, this touch is something you don't need to care about, right? You'll never get troubled even if I stop giving further information about it."
It's understandable but...

今手がけているAndroidアプリでは、Viewクラスをカスタマイズしたクラスをいくつか使っているのだけど、そのうちのひとつのクラスだけがタッチイベントの MotionEvent.ACTION_MOVE と UP を取れない、という現象に遭遇。
他はちゃんと取れてるのになんでや?と思って悩むこと1時間あまり、やっと発見したのが、最初に MotionEvent.ACTION_DOWN を受け取ったとき、onTouchEventの戻り値に false を返してしまうと、タッチの動作をそれ以上追いかけるのをやめてしまうようなのだ。
しかるべき時にちゃんと trueを返すようにしたらうまくいきました。

これってつまり「false返したってことはこのタッチは要らないんだよね?じゃあそれ以降情報渡すのやめるから!」ってことなんでしょうね。わからんでもないが・・・。

createBitmap and recycle()

I wrote a code like this to get a shrunk image, but when I try to use the bitmapB in the following part I get "bitmap already recycled" error.


Matrix matrix = new Matrix()
matrix.postScale(0.5, 0.5);
Bitmap bitmapA = BitmapFactory.decodeResource(getResources(),anId);
Bitmap bitmapB = Bitmap.createBitmap( bitmapA, 0, 0, bitmapA.getWidth(), bitmapB.getHeight(),matrix, true);
bitmapA.recycle();

I wondered why and searched a bit to found this:
http://stackoverflow.com/questions/4648926/create-a-subset-of-bitmap-without-make-a-copy

I thought createBitmap() makes copy of the original bitmap but if the bitmap is immutable they(source and destination) share the same byte array on the memory.

I think it's pretty confusing to have "create" in the name of the method...

画像を縮小しようと思ってこんなコードを書いたのだけど、得られた bitmapB をこの後使おうとすると「recycle済みのビットマップを使用した」という旨のエラーが出ます。


Matrix matrix = new Matrix()
matrix.postScale(0.5, 0.5);
Bitmap bitmapA = BitmapFactory.decodeResource(getResources(),anId);
Bitmap bitmapB = Bitmap.createBitmap( bitmapA, 0, 0, bitmapA.getWidth(), bitmapB.getHeight(),matrix, true);
bitmapA.recycle();

なんでや? と思って調べてみたらこれが出てきました。
http://stackoverflow.com/questions/4648926/create-a-subset-of-bitmap-without-make-a-copy

createBitmap()ってビットマップをコピーして新たにビットマップを作るものかと思ってたんですが、元のビットマップが immutable の場合、同じバイト列を共有するようです。なので bitmapB を破棄してしまうと bitmapA も実体がなくなってしまう、と。

それは理解したとして、それってcreateBitmapっていう名前のイメージと違う・・・。混乱のもとですわ。

Android - jpg color mode

It may depend on decoding attribute setting but in my case jpg files with CMYK color mode caused an error in runtime.

I came across this error while I was testing the method for getting resource ID dynamically, and I had no doubt that it's the problem about getting resource ID, so it took a few hours until notice that...

jpgファイルのカラーモードがCMYKだと実行時にエラーで落ちるようです。デコードの際のオプション設定をちゃんとすれば読めるのかもしれないけど、ひとまずそういうこともありましたよ、ということで。

で、この現象に出くわしたのがリソースIDを動的に取ってくるやり方を実験してた時で、なのでID取得が原因と思い込んでそれ(CMYKモードが読めてない)に気づくのに数時間要してしまったというお話し・・。

Shared Preferences

getSharedPreferences(prefName,mode)の省略形である getPreferences(mode) では、プリファレンス名としてアクティビティ名が採用されるんですね。
どこかの記事でアプリケーション名と書かれていた気がした(うろ覚え)ので勘違いしてました;
アプリケーション内で共通して使う場合は明示的にプリファレンス名を指定しましょう。

Subfolders ignored when making R.java

As my app have lots of images, so I wanted to categorize them and put into some subfolders, but the IDs disappeared from R.java when I did it.

Unfortunately, the android environment seems to be designed to ignore the subfolders under "drawable" etc..
http://stackoverflow.com/questions/1077357/can-the-android-drawable-directory-contain-subdirectories
Oh, my...

アプリ内に画像がいろいろ増えてきたんでカテゴリ分けしてサブフォルダに・・・と思ったら、サブフォルダに映すと R.java からIDが消えてしまう。

どうやらサブフォルダは無視される仕様らしい・・・
http://stackoverflow.com/questions/1077357/can-the-android-drawable-directory-contain-subdirectories
なんちゅう設計や・・・

Screen resolution

今アンドロイドappの開発は主にエミュレータベースでやっております。エミュレーターではスクリーン解像度を任意に設定できるようになっているんで いろいろ変えてレイアウトなどをチェックしているんですが、どうも以下のコードで解像度をチェックしてみたところ横幅が320のまま変わらない。

WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Log.d("display", "w:" + display.getWidth());

なぜかと思って調べてみたら、どうやらSDKのバージョンが関係あるようです。
http://romly.com/archives/2010/08/android_api_screensize.html
SDKバージョンが3以下(=Android OS 1.5以下)だと 横320pxを越える解像度は扱えないようですね。
minSdkVersionを7にしたらちゃんと指定した解像度になりました。

I'm working with Android emulator, on which you can set arbitrary screen resolution. But invoking the code below to get screen size only get 320px width while I set various resolution on the Emulator Settings.

WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Log.d("display", "w:" + display.getWidth());

The reason was the setting of SDK version.
If the minSdkVersion is 3 or lower (Android1.5 or lower) you cannot handle the screen width bigger than 320.
I rebuild the project with minSdkVersion=7 (Android OS 2.1) and got the result as desired.

Localization of app name

Wanted to localize the app name displayed under the app icon and set the info.plist file as localizable, but it didn't work.
I searched on the web for about an hour and finally find this article:
http://www.awaresoft.jp/development/35-iphone-app/88-iphone-app-localization.html (Japanese)

The article says: The right way to localize app display name is, to make InfoPlist.strings and set it as localizable.
Then, add a line like this on each InfoPlist.strings(language) files :
CFBundleDisplayName = "App Name";


アプリアイコンの下に表示されるアプリ名をローカライズしようと思って、info.plistを「ローカライズ可能」にしてみたのだけど、うまくいきませんでした。
小一時間ほど検索してやっとこの記事を見つけました。
http://www.awaresoft.jp/development/35-iphone-app/88-iphone-app-localization.html

この記事によれば、表示アプリ名を変更するには、まずInfoPlist.stringsファイルを作って、それを「ローカライズ可能」にする。
で、できたInfoPlist.strings(言語名) ファイルのそれぞれに
CFBundleDisplayName = "アプリ名";
という文を追加する、ということのようです。

Android

Andoroidアプリを勉強しております。
とりあえず、Andoroidアプリの構造とか、使用言語であるJavaの文法とかは本を読めば理解できるし、忘れたら読み返せばいいだけなのでほぼ問題ないんですが、問題は開発環境の Eclipse や Andoroidエミュレータのクセとかですね。

とりあえず、今日は System.out.println の出力を見るにはどうしたらいいのかで10分か20分ほど戸惑ってしまいました;
(ちなみに正解は Window -> Show View -> Other... -> android -> Log Cat です。)
他にも ImageView に配置した画像の縮尺が、Eclipse上で見る限りどうしても意図通りにならないのだけど、実行してエミュで見たらとっくにちゃんと出来ていた、とか、他人の実機でテストしようと思ってネット経由で .apk ファイルをやりとりしようと思ったが署名が無効なのか何なのかインストールできない(未解決;)、とか・・・

そんな感じで大変なこと山盛りですが、Eclipseのコード入力支援は XCode より親切な部分も多くて助かりますね。あと、Javaはメモリ管理がガベージコレクションなので気楽です。
リソースの扱い方も iOS よりスマートでいいな。

とりあえずいろいろ難しそうですががんばります;

Transparent background on UIView

UIViewの背景を透明にするには、
aView.backgroundColor = [UIColor clearColor];
みたいにコードを書かないといけないようです。
IB上にそういうオプションがあれば一発なのに・・

To have the background of UIView transparent you have to set the background color to "clearColor" programatically like this:
aView.backgroundColor = [UIColor clearColor];
I wonder why there aren't the option to do that on IB....